Skip to content

fix: pipeline status labels and reliable merge-gate dispatch#2343

Merged
MervinPraison merged 2 commits into
mainfrom
fix/pipeline-status-labels-merge-gate-dispatch
Jun 26, 2026
Merged

fix: pipeline status labels and reliable merge-gate dispatch#2343
MervinPraison merged 2 commits into
mainfrom
fix/pipeline-status-labels-merge-gate-dispatch

Conversation

@MervinPraison

@MervinPraison MervinPraison commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Summary

  • Merge-gate dispatch fix: resolvePrNumberFromWorkflowRun ignores fork sync PR links (fixes 404 on [pull] main from MervinPraison:main Milkmange/PraisonAI#21) and validates internal PRs before returning
  • Explicit dispatch: claude.yml dispatches claude-merge-gate with pr_number after PR @claude runs when pipeline is ready
  • Pipeline labels: New pipeline/* stage + blocker labels synced from evaluatePipelineQuiescent via pipeline-status.js
  • Sync triggers: auto-pr-comment (review chain steps), merge-gate scan, and pipeline-status-sync.yml (every 15 min)

Test plan

  • node .github/scripts/merge-gate-selftest.js
  • node .github/scripts/pipeline-status-selftest.js
  • After merge: open PRs show stage/blocker labels (e.g. pipeline/merge-ready, pipeline/blocked:manual-review)
  • PR with completed FINAL gets merge-gate dispatch without 404

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Added a scheduled/manual “Pipeline Status Sync” to keep pipeline/* stage and pipeline/blocked:* labels aligned for open pull requests.
    • Extended existing review and merge-gate workflows to refresh pipeline labels and, when ready, trigger merge-gate evaluation.
  • Bug Fixes

    • Improved linked-PR handling to accept only matching internal pull requests and valid open PRs, reducing incorrect PR matching from forks.
    • Refined PR discovery logic to improve consistency when linked information is incomplete.

Filter fork sync PRs in resolvePrNumberFromWorkflowRun, dispatch merge gate
explicitly from claude.yml after PR runs, and sync pipeline/* stage/blocker
labels via auto-pr-comment, merge-gate scan, and 15-min sync workflow.

Co-authored-by: Cursor <cursoragent@cursor.com>
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ab50cbb2-9917-46ab-9e8c-dbb9be55590d

📥 Commits

Reviewing files that changed from the base of the PR and between 45b2052 and d1e26a1.

📒 Files selected for processing (2)
  • .github/scripts/merge-gate.js
  • .github/scripts/pipeline-status.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/scripts/merge-gate.js
  • .github/scripts/pipeline-status.js

📝 Walkthrough

Walkthrough

Adds pipeline-status label syncing, merge-gate PR-number resolution, self-tests, and workflow steps that sync labels or dispatch merge-gate events.

Changes

Pipeline status and merge-gate automation

Layer / File(s) Summary
Pipeline label helpers
.github/scripts/pipeline-status.js, .github/scripts/pipeline-status-selftest.js
pipeline-status.js defines stage and blocker label derivation, label creation, and PR syncing; pipeline-status-selftest.js covers stage and blocker assertions.
Internal PR lookup
.github/scripts/merge-gate.js, .github/scripts/merge-gate-selftest.js, .github/scripts/pipeline-status-selftest.js
merge-gate.js adds internal linked-PR detection and workflow-run PR-number resolution; the self-tests cover internal pull request link matching.
PR workflow label sync
.github/workflows/auto-pr-comment.yml, .github/workflows/claude.yml, .github/workflows/claude-merge-gate.yml, .github/workflows/pipeline-status-sync.yml
auto-pr-comment.yml adds checkout and pipeline-status sync steps across PR-triggered jobs, bot-pr-trigger-reviews gains issues: write, claude.yml dispatches claude-merge-gate after readiness checks, and the scan/scheduled workflows sync open PR labels.
PR status self-tests
.github/scripts/merge-gate-selftest.js, .github/scripts/pipeline-status-selftest.js
Executable self-tests add assertions for internal PR link matching, stage derivation, and blocker label derivation.

Sequence Diagram(s)

PR-triggered label sync and merge-gate dispatch

sequenceDiagram
  participant ClaudeResponse as claude.yml claude-response job
  participant PipelineStatus as pipeline-status.js
  participant MergeGate as merge-gate.js
  participant GitHubAPI as GitHub REST API
  ClaudeResponse->>PipelineStatus: ensurePipelineLabels(...) and syncPipelineLabels(...)
  PipelineStatus->>GitHubAPI: list labels and update PR labels
  ClaudeResponse->>MergeGate: evaluate pipeline readiness
  MergeGate->>GitHubAPI: inspect PR and workflow state
  ClaudeResponse->>GitHubAPI: createDispatchEvent("claude-merge-gate", { pr_number })
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

Review effort 4/5

Poem

A rabbit tuned the labels in the moonlit yard,
Then hopped through workflows, neat and hard.
Internal links said, “Yes, that’s right,”
And merge gates sparkled in the night.
🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the two main changes: pipeline status label sync and more reliable merge-gate dispatch.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/pipeline-status-labels-merge-gate-dispatch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@MervinPraison

Copy link
Copy Markdown
Owner Author

@copilot Do a thorough review of this PR. Read ALL existing reviewer comments above from Qodo, Coderabbit, and Gemini first — incorporate their findings.

Review areas:

  1. Bloat check: Are changes minimal and focused? Any unnecessary code or scope creep?
  2. Security: Any hardcoded secrets, unsafe eval/exec, missing input validation?
  3. Performance: Any module-level heavy imports? Hot-path regressions?
  4. Tests: Are tests included? Do they cover the changes adequately?
  5. Backward compat: Any public API changes without deprecation?
  6. Code quality: DRY violations, naming conventions, error handling?
  7. Address reviewer feedback: If Qodo, Coderabbit, or Gemini flagged valid issues, include them in your review
  8. Suggest specific improvements with code examples where possible

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a pipeline status synchronization mechanism to manage GitHub labels representing PR stages and blockers, along with corresponding self-tests. It also refactors the merge gate logic to extract helper functions for resolving PR numbers from linked pull requests and head branches. The review feedback suggests several optimizations and robustness improvements: prioritizing checking linked PRs over head branches to reduce API calls, wrapping label creation in a try-catch block to handle existing labels gracefully, and avoiding unnecessary pagination when fetching open pull requests if the limit is small.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +348 to +360
async function resolvePrNumberFromWorkflowRun(github, owner, repo, workflowRun) {
const fromBranch = await resolvePrNumberFromHeadBranch(
github, owner, repo, workflowRun.head_branch
);
if (fromBranch) return fromBranch;

const fromLinked = await resolvePrNumberFromLinkedPullRequests(
github, owner, repo, workflowRun.pull_requests
);
if (fromLinked) return fromLinked;

return null;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Checking the head branch first via resolvePrNumberFromHeadBranch always triggers a pulls.list API call. However, if the workflow run already has linked pull requests (workflowRun.pull_requests), we can validate them first using resolvePrNumberFromLinkedPullRequests. This is both more accurate (since it uses the explicit association from GitHub) and more efficient (as it avoids the list API call entirely when a valid linked PR is found).

Suggested change
async function resolvePrNumberFromWorkflowRun(github, owner, repo, workflowRun) {
const fromBranch = await resolvePrNumberFromHeadBranch(
github, owner, repo, workflowRun.head_branch
);
if (fromBranch) return fromBranch;
const fromLinked = await resolvePrNumberFromLinkedPullRequests(
github, owner, repo, workflowRun.pull_requests
);
if (fromLinked) return fromLinked;
return null;
}
async function resolvePrNumberFromWorkflowRun(github, owner, repo, workflowRun) {
const fromLinked = await resolvePrNumberFromLinkedPullRequests(
github, owner, repo, workflowRun.pull_requests
);
if (fromLinked) return fromLinked;
const fromBranch = await resolvePrNumberFromHeadBranch(
github, owner, repo, workflowRun.head_branch
);
if (fromBranch) return fromBranch;
return null;
}

Comment on lines +93 to +111
async function ensurePipelineLabels(github, owner, repo, core) {
const { data: existing } = await github.rest.issues.listLabelsForRepo({
owner,
repo,
per_page: 100,
});
const names = new Set(existing.map((l) => l.name));
for (const spec of LABEL_SPECS) {
if (names.has(spec.name)) continue;
await github.rest.issues.createLabel({
owner,
repo,
name: spec.name,
color: spec.color,
description: spec.description,
});
core?.info?.(`Created label ${spec.name}`);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If a repository has more than 100 labels, or if there is a race condition where multiple workflow runs attempt to sync labels concurrently, createLabel will throw a 422 Unprocessable Entity error because the label already exists. Wrapping the createLabel call in a try/catch block to gracefully handle 422 or already_exists errors prevents the entire sync process from crashing.

async function ensurePipelineLabels(github, owner, repo, core) {
  const { data: existing } = await github.rest.issues.listLabelsForRepo({
    owner,
    repo,
    per_page: 100,
  });
  const names = new Set(existing.map((l) => l.name));
  for (const spec of LABEL_SPECS) {
    if (names.has(spec.name)) continue;
    try {
      await github.rest.issues.createLabel({
        owner,
        repo,
        name: spec.name,
        color: spec.color,
        description: spec.description,
      });
      core?.info?.('Created label ' + spec.name);
    } catch (err) {
      if (err.status === 422 || err.message?.includes('already_exists')) {
        core?.info?.('Label ' + spec.name + ' already exists');
      } else {
        throw err;
      }
    }
  }
}

Comment on lines +147 to +166
async function syncOpenPullRequests(github, owner, repo, options, core) {
const { maxPrs = 20 } = options || {};
await ensurePipelineLabels(github, owner, repo, core);
const prs = await github.paginate(github.rest.pulls.list, {
owner,
repo,
state: 'open',
per_page: 100,
});
let synced = 0;
for (const pr of prs) {
if (synced >= maxPrs) break;
if (pr.draft) continue;
if (pr.head?.repo?.full_name && pr.head.repo.full_name !== `${owner}/${repo}`) continue;
await syncPipelineLabels(github, owner, repo, pr.number, core);
synced += 1;
}
core?.info?.(`Pipeline label sync complete (${synced} PR(s))`);
return synced;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using github.paginate will fetch all open pull requests in the repository. If a repository has hundreds of open PRs, this consumes significant API rate limits and causes unnecessary overhead, especially since the sync is capped at maxPrs (which defaults to 20). If maxPrs is less than or equal to 100, we can fetch just the first page using github.rest.pulls.list to optimize performance.

async function syncOpenPullRequests(github, owner, repo, options, core) {
  const { maxPrs = 20 } = options || {};
  await ensurePipelineLabels(github, owner, repo, core);
  
  let prs = [];
  if (maxPrs <= 100) {
    const { data } = await github.rest.pulls.list({
      owner,
      repo,
      state: 'open',
      per_page: 100,
    });
    prs = data;
  } else {
    prs = await github.paginate(github.rest.pulls.list, {
      owner,
      repo,
      state: 'open',
      per_page: 100,
    });
  }

  let synced = 0;
  for (const pr of prs) {
    if (synced >= maxPrs) break;
    if (pr.draft) continue;
    if (pr.head?.repo?.full_name && pr.head.repo.full_name !== `${owner}/${repo}`) continue;
    await syncPipelineLabels(github, owner, repo, pr.number, core);
    synced += 1;
  }
  core?.info?.('Pipeline label sync complete (' + synced + ' PR(s))');
  return synced;
}

@greptile-apps

greptile-apps Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR updates the review pipeline automation and status reporting. The main changes are:

  • Workflow-run PR resolution now filters fork sync links and validates internal PRs.
  • Claude runs can dispatch the merge gate with an explicit PR number.
  • Pipeline stage and blocker labels are synced from merge-gate state.
  • Scheduled and workflow-triggered label sync paths were added.

Confidence Score: 4/5

This is close, but the merge-gate dispatch path should be fixed before merging.

  • The sender checks readiness with cooldown bypasses.
  • The receiving workflow re-checks the same PR without those bypasses.
  • A just-finished Claude run can still block the targeted merge-gate dispatch.

.github/workflows/claude-merge-gate.yml

Important Files Changed

Filename Overview
.github/workflows/claude.yml Adds pipeline label sync and sends a targeted merge-gate dispatch after a ready Claude run.
.github/workflows/claude-merge-gate.yml Receives targeted merge-gate dispatches and syncs labels, but the targeted path still re-checks cooldown state without the sender's bypass.
.github/scripts/merge-gate.js Adds internal PR-link filtering and helper functions for resolving workflow-run PR numbers.
.github/scripts/pipeline-status.js Adds helpers for deriving and syncing pipeline stage and blocker labels.

Comments Outside Diff (1)

  1. .github/workflows/claude-merge-gate.yml, line 151 (link)

    P1 Bypass is dropped

    This targeted dispatch re-checks the PR without the skip options used by the sender. When claude.yml dispatches right after a ready Claude run, this path receives the pr_number but calls evaluatePipelineQuiescent with default cooldown checks. The PR can still be rejected as recent @claude within 35min or claude.yml in progress, so the dispatch is consumed without running the merge gate until a later scan.

Reviews (2): Last reviewed commit: "fix: address reviewer feedback in merge-..." | Re-trigger Greptile

Comment thread .github/workflows/claude.yml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (6)
.github/scripts/merge-gate.js (1)

308-313: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

base.repo.name fallback never matches the owner/repo comparison.

link?.base?.repo?.name is the bare repo name (e.g. PraisonAI), which can never equal ${owner}/${repo} (MervinPraison/PraisonAI). The fallback only ever yields a false negative; the baseUrl check is the effective secondary path. Consider dropping the fallback or comparing it against repo alone to make intent clear.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/scripts/merge-gate.js around lines 308 - 313, The fallback in
isInternalPullRequestLink is comparing link?.base?.repo?.name against
owner/repo, but repo.name is only the bare repository name and can never match
that full string. Update the logic in isInternalPullRequestLink to either remove
the repo.name fallback or compare it only to repo, while keeping the
baseUrl.endsWith(/repos/${owner}/${repo}) check as the secondary path so the
intent is clear.
.github/scripts/pipeline-status.js (1)

93-111: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

ensurePipelineLabels only reads the first 100 labels and doesn't guard createLabel against duplicates.

listLabelsForRepo is called with per_page: 100 and no pagination. If the repo has more than 100 labels and an existing pipeline/* label falls outside the first page, names.has(...) misses it and createLabel throws a 422 (already_exists), aborting the whole sync. Use github.paginate or tolerate the 422.

♻️ Proposed hardening
-  const { data: existing } = await github.rest.issues.listLabelsForRepo({
-    owner,
-    repo,
-    per_page: 100,
-  });
+  const existing = await github.paginate(github.rest.issues.listLabelsForRepo, {
+    owner,
+    repo,
+    per_page: 100,
+  });
   const names = new Set(existing.map((l) => l.name));
   for (const spec of LABEL_SPECS) {
     if (names.has(spec.name)) continue;
-    await github.rest.issues.createLabel({
-      owner,
-      repo,
-      name: spec.name,
-      color: spec.color,
-      description: spec.description,
-    });
-    core?.info?.(`Created label ${spec.name}`);
+    try {
+      await github.rest.issues.createLabel({
+        owner, repo, name: spec.name, color: spec.color, description: spec.description,
+      });
+      core?.info?.(`Created label ${spec.name}`);
+    } catch (err) {
+      if (err.status !== 422) throw err;
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/scripts/pipeline-status.js around lines 93 - 111,
ensurePipelineLabels currently only checks the first page of labels and can fail
when an existing pipeline label is beyond the initial 100 results. Update
ensurePipelineLabels to paginate through all labels (for example via
github.paginate around issues.listLabelsForRepo) before building the names set,
and also make the createLabel call resilient to a duplicate-existing-label 422
so the sync continues if another process created the label first.
.github/workflows/pipeline-status-sync.yml (1)

6-7: 🚀 Performance & Scalability | 🔵 Trivial

Cron cadence vs. API cost.

Running syncOpenPullRequests with maxPrs: 30 every 15 minutes means each cycle fans out into many REST/GraphQL calls per PR (loadPrContext + evaluatePipelineQuiescent + label add/remove). On a busy repo this can pressure the secondary rate limit for GH_TOKEN. Consider a longer interval (e.g. */30) or confirm the per-cycle call budget stays well under limits, since the PR-, scan-, and scheduled-paths now all sync the same labels.

Also applies to: 29-31

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/pipeline-status-sync.yml around lines 6 - 7, The scheduled
run in the pipeline status sync workflow is too aggressive for the amount of
GitHub API traffic generated by syncOpenPullRequests and related label updates.
Update the cron cadence in the workflow schedule to a longer interval, or
otherwise adjust the syncOpenPullRequests/maxPrs budget so the combined load
from loadPrContext, evaluatePipelineQuiescent, and label add/remove stays
comfortably within GH_TOKEN rate limits.
.github/workflows/auto-pr-comment.yml (2)

219-219: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Unpinned action references flagged by policy.

zizmor reports these actions/checkout@v4 / actions/github-script@v7 refs as unpinned under the blanket pin-to-hash policy. The rest of this file uses the same unpinned @vN style, so pinning only the new lines would be inconsistent — if the policy is intended to be enforced, pin repo-wide; otherwise this is informational.

Also applies to: 335-335, 362-362, 459-459, 589-589, 676-676

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/auto-pr-comment.yml at line 219, The workflow uses
unpinned GitHub Actions references, and the policy check flags the new
actions/checkout and actions/github-script entries as inconsistent with the
required pin-to-hash standard. Update the action references in this workflow
consistently by pinning all uses of actions/checkout and actions/github-script
to immutable commit SHAs, or, if that policy is not meant to be enforced here,
keep the versioned refs uniform across the file. Use the existing action usages
in the workflow to locate all affected steps, including the repeated checkout
and github-script invocations.

Source: Linters/SAST tools


334-346: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Identical pipeline-sync step duplicated across four jobs.

This same 6-line require(...pipeline-status.js) + ensurePipelineLabels + syncPipelineLabels block now appears in four jobs (and again in claude.yml). Consider extracting a local composite action (e.g. .github/actions/sync-pipeline-labels) to keep token/permission handling and the script path consistent in one place.

Also applies to: 458-470, 588-598, 673-684

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/auto-pr-comment.yml around lines 334 - 346, The pipeline
label sync logic is duplicated across multiple workflow jobs, so extract the
repeated actions/github-script block that loads pipeline-status.js and calls
ensurePipelineLabels/syncPipelineLabels into a reusable local composite action
such as .github/actions/sync-pipeline-labels. Update each job to invoke that
action instead of inlining the script, keeping PR_NUMBER, github-token, and
permission handling consistent in one place.
.github/workflows/claude.yml (1)

361-366: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Pass pr_number via env, not inline template expansion.

parseInt('${{ steps.check_fork.outputs.pr_number }}', 10) interpolates the value directly into the script body (flagged by zizmor template-injection). Although pr_number is currently set from String(prNumber) and is numeric, the other github-script steps in this repo pass values through env: and read process.env. Mirror that pattern here for consistency and to harden against future changes.

🔒 Suggested change (both steps)
      - name: Sync pipeline status labels for PR
        if: steps.check_fork.outputs.is_pr == 'true'
        uses: actions/github-script@v7
        env:
          PR_NUMBER: ${{ steps.check_fork.outputs.pr_number }}
        with:
          github-token: ${{ secrets.GH_TOKEN }}
          script: |
            const path = require('path');
            const ps = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/pipeline-status.js'));
            const prNumber = parseInt(process.env.PR_NUMBER, 10);
            await ps.ensurePipelineLabels(github, context.repo.owner, context.repo.repo, core);
            await ps.syncPipelineLabels(github, context.repo.owner, context.repo.repo, prNumber, core);

Apply the same env: PR_NUMBER + process.env.PR_NUMBER approach to the dispatch step at Line 378.

Also applies to: 373-378

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/claude.yml around lines 361 - 366, The github-script step
is still interpolating pr_number directly into the script body, which triggers
template-injection risk and is inconsistent with the repo’s other steps. Update
the pipeline status label sync block to pass PR_NUMBER through env and read it
with process.env.PR_NUMBER inside the script, using the existing
ps.ensurePipelineLabels and ps.syncPipelineLabels flow. Apply the same env-based
pattern to the dispatch step as well, so both github-script invocations avoid
inline template expansion.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.github/scripts/merge-gate.js:
- Around line 308-313: The fallback in isInternalPullRequestLink is comparing
link?.base?.repo?.name against owner/repo, but repo.name is only the bare
repository name and can never match that full string. Update the logic in
isInternalPullRequestLink to either remove the repo.name fallback or compare it
only to repo, while keeping the baseUrl.endsWith(/repos/${owner}/${repo}) check
as the secondary path so the intent is clear.

In @.github/scripts/pipeline-status.js:
- Around line 93-111: ensurePipelineLabels currently only checks the first page
of labels and can fail when an existing pipeline label is beyond the initial 100
results. Update ensurePipelineLabels to paginate through all labels (for example
via github.paginate around issues.listLabelsForRepo) before building the names
set, and also make the createLabel call resilient to a duplicate-existing-label
422 so the sync continues if another process created the label first.

In @.github/workflows/auto-pr-comment.yml:
- Line 219: The workflow uses unpinned GitHub Actions references, and the policy
check flags the new actions/checkout and actions/github-script entries as
inconsistent with the required pin-to-hash standard. Update the action
references in this workflow consistently by pinning all uses of actions/checkout
and actions/github-script to immutable commit SHAs, or, if that policy is not
meant to be enforced here, keep the versioned refs uniform across the file. Use
the existing action usages in the workflow to locate all affected steps,
including the repeated checkout and github-script invocations.
- Around line 334-346: The pipeline label sync logic is duplicated across
multiple workflow jobs, so extract the repeated actions/github-script block that
loads pipeline-status.js and calls ensurePipelineLabels/syncPipelineLabels into
a reusable local composite action such as .github/actions/sync-pipeline-labels.
Update each job to invoke that action instead of inlining the script, keeping
PR_NUMBER, github-token, and permission handling consistent in one place.

In @.github/workflows/claude.yml:
- Around line 361-366: The github-script step is still interpolating pr_number
directly into the script body, which triggers template-injection risk and is
inconsistent with the repo’s other steps. Update the pipeline status label sync
block to pass PR_NUMBER through env and read it with process.env.PR_NUMBER
inside the script, using the existing ps.ensurePipelineLabels and
ps.syncPipelineLabels flow. Apply the same env-based pattern to the dispatch
step as well, so both github-script invocations avoid inline template expansion.

In @.github/workflows/pipeline-status-sync.yml:
- Around line 6-7: The scheduled run in the pipeline status sync workflow is too
aggressive for the amount of GitHub API traffic generated by
syncOpenPullRequests and related label updates. Update the cron cadence in the
workflow schedule to a longer interval, or otherwise adjust the
syncOpenPullRequests/maxPrs budget so the combined load from loadPrContext,
evaluatePipelineQuiescent, and label add/remove stays comfortably within
GH_TOKEN rate limits.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 91a7cb4f-502f-44ee-aa33-965c2aa47cc4

📥 Commits

Reviewing files that changed from the base of the PR and between 078bb69 and 45b2052.

📒 Files selected for processing (8)
  • .github/scripts/merge-gate-selftest.js
  • .github/scripts/merge-gate.js
  • .github/scripts/pipeline-status-selftest.js
  • .github/scripts/pipeline-status.js
  • .github/workflows/auto-pr-comment.yml
  • .github/workflows/claude-merge-gate.yml
  • .github/workflows/claude.yml
  • .github/workflows/pipeline-status-sync.yml

@MervinPraison

Copy link
Copy Markdown
Owner Author

@claude You are the FINAL architecture reviewer. If the branch is under MervinPraison/PraisonAI (not a fork), you are able to make modifications to this branch and push directly. SCOPE: Focus ONLY on Python packages (praisonaiagents, praisonai). Do NOT modify praisonai-rust or praisonai-ts. Read ALL comments above from Gemini, Qodo, CodeRabbit, and Copilot carefully before responding.

Phase 1: Review per AGENTS.md

  1. Protocol-driven: check heavy implementations vs core SDK
  2. Backward compatible: ensure zero feature regressions
  3. Performance: no hot-path regressions
  4. SDK value: review in depth whether the change genuinely adds value to the SDK — never add features for the sake of adding them. It must strengthen the SDK (simpler, more user-friendly, robust, world-class, secure). If it does not clearly add value, request changes or recommend rejecting/closing rather than merging scope creep
  5. Do not bloat the Agent class with additional params — only if absolutely required; we already support many params.

Phase 2: FIX Valid Issues
5. For any VALID bugs or architectural flaws found by Gemini, CodeRabbit, Qodo, Copilot, or any other reviewer: implement the fix
6. Push all code fixes directly to THIS branch (do NOT create a new PR)
7. Comment a summary of exact files modified and what you skipped

Phase 3: Final Verdict
8. If all issues are resolved, approve the PR / close the Issue
9. If blocking issues remain, request changes / leave clear action items

@praisonai-triage-agent

praisonai-triage-agent Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MervinPraison's task —— View job


FINAL Architecture Review — PR #2343

Scope note: This PR is CI/automation only (.github/scripts/*.js, .github/workflows/*.yml). No praisonaiagents/praisonai Python SDK code is touched, so AGENTS.md SDK-value/Agent-bloat gates are N/A. Changes are well-isolated to the merge-gate/pipeline-label tooling.

Fixes applied (pushed to d1e26a1c)

  • GeminiresolvePrNumberFromWorkflowRun now checks linked PRs before head branch. More accurate (uses GitHub's explicit association) and skips the pulls.list call when a valid linked PR exists.
  • CodeRabbit — dropped the unreachable base.repo.name fallback in isInternalPullRequestLink (bare repo name can never equal owner/repo; only ever produced false negatives). baseUrl.endsWith(...) remains the secondary path.
  • Gemini + CodeRabbitensurePipelineLabels now paginates all repo labels and wraps createLabel in a 422-tolerant try/catch, so a concurrent run or >100 labels no longer aborts the sync.
  • GeminisyncOpenPullRequests uses a single pulls.list page when maxPrs <= 100 instead of full pagination, cutting API cost.
  • Self-tests pass: merge-gate-selftest.js (22 ok) and pipeline-status-selftest.js (8 ok).

Intentionally skipped (with reasons)

  • Greptile P1 — dispatch loses cooldown bypass (claude.ymlclaude-merge-gate.yml): valid concern. The dispatcher evaluates with skipRecentClaudeCooldown: true, but the receiving workflow re-checks with normal cooldown and can drop the dispatch as recent @claude within 35min. I cannot fix this — it requires editing files in .github/workflows/, which my GitHub App permissions do not allow. The scheduled merge-gate scan (every cycle) recovers the PR shortly after, so it self-heals with a small delay rather than failing permanently. Recommend a follow-up to forward the bypass via client_payload (e.g. { pr_number, bypass_cooldown: true }) and honor it in the receiver.
  • CodeRabbit — template-injection in claude.yml (parseInt('${{ ... }}')env: PR_NUMBER): valid hardening. Same workflow-file permission limitation — cannot modify. pr_number is set from String(prNumber) (numeric), so it's low-risk today; worth doing in a workflow-only follow-up.
  • CodeRabbit — duplicated sync step → composite action, and cron cadence (*/15): maintainability/perf nitpicks in workflow files. Same permission limitation; non-blocking.
  • zizmor — unpinned @vN actions: file-wide existing style; pinning only new lines would be inconsistent. Out of scope for this PR.

Verdict

The JS-script issues raised by reviewers are resolved and all self-tests pass. The remaining items are workflow-file changes I'm not permitted to make (only .github/scripts/ was editable); the Greptile P1 is non-fatal due to the scheduled scan self-healing. No blocking issues in the editable code — recommend a small workflow-only follow-up PR for the cooldown-bypass propagation and env: hardening.


🤖 Job run · Branch fix/pipeline-status-labels-merge-gate-dispatch

- Reorder resolvePrNumberFromWorkflowRun to check linked PRs before head
  branch (Gemini): more accurate and avoids a pulls.list call
- Drop unreachable base.repo.name fallback in isInternalPullRequestLink
  (CodeRabbit): bare repo name can never match owner/repo
- Paginate labels and tolerate 422 in ensurePipelineLabels (Gemini/CodeRabbit)
- Skip full pagination when maxPrs <= 100 in syncOpenPullRequests (Gemini)

Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com>
@MervinPraison

Copy link
Copy Markdown
Owner Author

@claude You are the FINAL architecture reviewer. If the branch is under MervinPraison/PraisonAI (not a fork), you are able to make modifications to this branch and push directly. SCOPE: Focus ONLY on Python packages (praisonaiagents, praisonai). Do NOT modify praisonai-rust or praisonai-ts. Read ALL comments above from Gemini, Qodo, CodeRabbit, and Copilot carefully before responding.

Phase 1: Review per AGENTS.md

  1. Protocol-driven: check heavy implementations vs core SDK
  2. Backward compatible: ensure zero feature regressions
  3. Performance: no hot-path regressions
  4. SDK value: review in depth whether the change genuinely adds value to the SDK — never add features for the sake of adding them. It must strengthen the SDK (simpler, more user-friendly, robust, world-class, secure). If it does not clearly add value, request changes or recommend rejecting/closing rather than merging scope creep
  5. Do not bloat the Agent class with additional params — only if absolutely required; we already support many params.

Phase 2: FIX Valid Issues
5. For any VALID bugs or architectural flaws found by Gemini, CodeRabbit, Qodo, Copilot, or any other reviewer: implement the fix
6. Push all code fixes directly to THIS branch (do NOT create a new PR)
7. Comment a summary of exact files modified and what you skipped

Phase 3: Final Verdict
8. If all issues are resolved, approve the PR / close the Issue
9. If blocking issues remain, request changes / leave clear action items

@MervinPraison MervinPraison added pipeline/blocked:ci Blocked: CI not green on HEAD pipeline/blocked:manual-review Blocked: requires manual review pipeline/blocked:cooldown Blocked: post-push or @claude cooldown pipeline/reviews-pending Waiting for CodeRabbit/Qodo/Copilot reviews labels Jun 26, 2026
@praisonai-triage-agent

praisonai-triage-agent Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MervinPraison's task —— View job


FINAL Architecture Review — PR #2343

Scope: CI/automation only (.github/scripts/*.js, .github/workflows/*.yml). No praisonaiagents/praisonai SDK code touched → AGENTS.md SDK-value/Agent-bloat gates are N/A. Backward-compat, hot-path, and protocol-routing concerns don't apply to this tooling change.

  • Read all reviewer comments (Gemini, CodeRabbit, Greptile, Qodo)
  • Verify each finding against current .js code
  • Confirm self-test coverage
  • Final verdict

Verification — all editable (.js) findings already resolved in d1e26a1c

  • GeminiresolvePrNumberFromWorkflowRun checks linked PRs before head branch (merge-gate.js:347-359). Avoids the pulls.list call when a valid linked PR exists. ✔
  • CodeRabbit — unreachable base.repo.name fallback dropped from isInternalPullRequestLink (merge-gate.js:308-312); baseUrl.endsWith(...) is the secondary path. ✔
  • Gemini + CodeRabbitensurePipelineLabels paginates all repo labels and wraps createLabel in a 422-tolerant try/catch (pipeline-status.js:93-125). Race-safe and >100-label-safe. ✔
  • GeminisyncOpenPullRequests uses a single pulls.list page when maxPrs <= 100 (pipeline-status.js:164-179). ✔
  • Self-tests assert these: isInternalPullRequestLink accepts internal / rejects fork-sync (Milkmange#21); stage + blocker derivation covered (pipeline-status-selftest.js, merge-gate-selftest.js).

Note: I'm not able to execute node in this run to re-run the suites live; I verified the assertions statically against the current source. The prior FINAL run reported 22 ok / 8 ok on the same commit.

Intentionally skipped — workflow-file changes (outside my permissions)

I cannot modify files under .github/workflows/ (GitHub App permission limitation), so these remain for a workflow-only follow-up PR:

  • Greptile P1 — dispatch loses cooldown bypass (claude.yml:379-384claude-merge-gate.yml): The dispatcher evaluates with skipRecentClaudeCooldown: true, but the receiver re-checks with normal cooldown and can drop the dispatch as recent @claude within 35min. Non-fatal — the scheduled merge-gate scan recovers the PR a cycle later, so it self-heals with a short delay. Recommended follow-up: forward client_payload: { pr_number, bypass_cooldown: true } and honor it in the receiver's evaluation options.
  • CodeRabbit — template-injection hardening (claude.yml:364,378): move parseInt('${{ ... }}') to env: PR_NUMBER + process.env.PR_NUMBER. Low-risk today (pr_number is numeric from String(prNumber)), worth doing for consistency.
  • CodeRabbit — extract duplicated sync step → composite action + cron cadence (*/15*/30): maintainability/rate-limit nitpicks, non-blocking.
  • zizmor — unpinned @vN actions: repo-wide existing style; pinning only new lines would be inconsistent. Out of scope.

Verdict — ✅ No blocking issues in editable code

All JS-script issues raised by reviewers are resolved on d1e26a1c and covered by self-tests. The only remaining item with real merge-behavior impact (Greptile P1) is a .github/workflows/ change I'm not permitted to make, and it's self-healing via the scheduled scan rather than a hard failure. Recommend merging this PR, then a small workflow-only follow-up to (1) propagate the cooldown bypass through client_payload and (2) move PR_NUMBER to env:.

No code changes pushed in this run — everything editable was already fixed by the prior FINAL commit.


🤖 Job run · Branch fix/pipeline-status-labels-merge-gate-dispatch

@MervinPraison MervinPraison merged commit 911db9d into main Jun 26, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pipeline/blocked:ci Blocked: CI not green on HEAD pipeline/blocked:cooldown Blocked: post-push or @claude cooldown pipeline/blocked:manual-review Blocked: requires manual review pipeline/reviews-pending Waiting for CodeRabbit/Qodo/Copilot reviews

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant