Skip to content

ci: introduce deterministic native merge queue gate + PR queue visibility#22294

Merged
BrianCLong merged 1 commit intomainfrom
codex/implement-merge-queue-system-in-ci/cd-ud4wxk
Apr 9, 2026
Merged

ci: introduce deterministic native merge queue gate + PR queue visibility#22294
BrianCLong merged 1 commit intomainfrom
codex/implement-merge-queue-system-in-ci/cd-ud4wxk

Conversation

@BrianCLong
Copy link
Copy Markdown
Owner

@BrianCLong BrianCLong commented Mar 31, 2026

Motivation

  • Reduce merge-time flakiness and redundant CI by consolidating queue sequencing around GitHub native merge queue and validating each candidate against the integrated tip of main.
  • Improve developer visibility into queue state (position, depth, dequeue reason) so contributors know why a PR was removed or when it will be processed.
  • Eliminate competing/duplicated automation that caused non-deterministic merges and excessive CI fan-out.

Description

  • Add a single authoritative queue workflow at .github/workflows/merge-queue.yml that:
    • Listens to merge_group for checks_requested and to pull_request queue lifecycle events, publishes a persistent PR comment with queue position/depth/reason, and runs an integrated validation job merge-queue-critical that performs install, lint, typecheck, and test on the merge candidate.
    • Uses a named concurrency group (merge-queue-main) with cancel-in-progress: false to serialize queue validations and avoid superseding in-flight validations.
  • Convert competing automation to manual-only to avoid uncontrolled queue churn by updating: .github/workflows/merge-group-heavy.yml, .github/workflows/merge-queue-feeder.yml, and .github/workflows/merge-train-autopilot.yml to workflow_dispatch/no-op operator guidance.
  • Add the merge queue check context to the desired branch-protection payload at .github/protection/main.required-checks.json as merge-queue / merge-queue-critical so the integrated validation is required before main merges.
  • PR metadata block for repository agent tooling (inserted in PR description): { "agent": "antigravity", "change_class": "ci", "impact": "branch-protection,workflows" }

Testing

  • Parsed the modified workflows with YAML to ensure valid workflow syntax using ruby -ryaml and all modified workflow files loaded successfully (ok .github/workflows/*.yml). — Success.
  • Validated .github/protection/main.required-checks.json with jq to ensure valid JSON structure. — Success.
  • Performed local checks for workflow consistency and committed the changes; workflows are limited to workflow_dispatch or merge_group triggers as intended. — Success.

Codex Task

Summary by CodeRabbit

  • Chores
    • Updated branch protection requirements to include merge queue critical status check.
    • Refactored merge queue workflow with improved pull request visibility and status tracking.
    • Modified merge train autopilot to manual-only mode; automated scheduling is no longer active.
    • Added manual dispatch option for heavy CI checks workflow.

@BrianCLong BrianCLong added the codex Codex-owned implementation work label Mar 31, 2026 — with ChatGPT Codex Connector
Copy link
Copy Markdown
Contributor

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

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 updates the branch protection configuration for the main branch, specifically modifying the encoding of an existing check name and adding 'merge-queue / merge-queue-critical' to the required status checks. Feedback highlights a critical concern regarding a potential circular dependency: if the newly added check only runs during the merge group phase, it will prevent pull requests from being queued as the requirement cannot be met beforehand.

"test (20.x)",
"Workflow Validity Check"
"Workflow Validity Check",
"merge-queue / merge-queue-critical"
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.

high

Adding merge-queue / merge-queue-critical as a required status check will likely block pull requests from entering the merge queue. GitHub's branch protection requires all mandatory status checks to pass before a pull request can be added to the queue. If this job is only triggered by the merge_group event (as suggested by the workflow name and PR description), it will not have run yet when a developer attempts to queue the PR. This creates a circular dependency where the PR cannot enter the queue because the check hasn't passed, and the check cannot run because the PR isn't in the queue. To resolve this, ensure the job (or a job with the same name) also triggers on standard pull_request events (e.g., opened, synchronize), or consider if this check should be required only for the final merge and not for queue entry.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

Walkthrough

GitHub Actions workflows and branch protection configuration were updated to restructure merge queue automation. Triggers were modified from scheduled/automated to manual or event-based dispatches. The core merge queue validation job was refactored with new visibility checks and concurrency settings, while auxiliary autopilot and feeder workflows were disabled.

Changes

Cohort / File(s) Summary
Branch Protection Configuration
.github/protection/main.required-checks.json
Added merge-queue / merge-queue-critical as a new required status check alongside existing CI checks.
Workflow Trigger Changes
.github/workflows/merge-group-heavy.yml, .github/workflows/merge-queue-feeder.yml, .github/workflows/merge-train-autopilot.yml
Disabled automated execution: replaced merge_group trigger with workflow_dispatch, removed scheduled cron triggers, disabled autopilot script execution, and replaced functional job steps with informational no-op messages.
Core Merge Queue Workflow Restructuring
.github/workflows/merge-queue.yml
Renamed workflow, expanded triggers to include pull_request events, split single job into two (queue-visibility for PR updates and merge-queue-critical for merge-group validation), updated concurrency behavior (cancel-in-progress: false), simplified validation to deterministic install and critical test suite, and added step summary reporting.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 ✨ Workflows now dance to manual commands, no more cron's relentless hand,
Merge queue visibility shines with pride, posting updates far and wide,
Autopilot rests while GitHub's native queue takes the lead,
Complex orchestration—a rabbit's recipe indeed! 🚀

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description includes motivation, detailed technical description of changes, and testing performed. However, it is missing required template sections like Risk & Surface, Assumption Ledger, Evidence Bundle checklist items, and other governance sections. Complete the required template sections including Risk & Surface (risk level and surface area), Assumption Ledger, Evidence Bundle checklist, Security Impact, Green CI Contract, and Verification sections to meet repository standards.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and clearly describes the main changes: introducing deterministic merge queue gating and adding PR queue visibility, which aligns with the core objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/implement-merge-queue-system-in-ci/cd-ud4wxk

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 and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ccec0c3c8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

merge_group:
types: [checks_requested]
pull_request:
types: [enqueued, dequeued, synchronize, reopened, ready_for_review]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Trigger merge-queue workflow on PR open

The pull_request trigger omits opened, so a newly opened non-draft PR targeting main will not execute this workflow until a later action (like synchronize) occurs. Since this commit also adds merge-queue / merge-queue-critical to required checks, those PRs can sit in an "Expected" state with no reported context and be blocked from merge queue/merge unless another triggering action happens.

Useful? React with 👍 / 👎.

Comment on lines 14 to +16
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: merge-queue-main
cancel-in-progress: false
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Separate PR comment runs from merge-group concurrency

Workflow-level concurrency is now a single fixed group for both pull_request and merge_group runs with cancel-in-progress: false, so every queue-visibility comment run serializes with merge-group validation. In busy repos this can delay merge-queue-critical execution behind non-critical PR events and reduce merge throughput; the concurrency gate should be scoped to the merge-group job (or keyed by event) instead of the whole workflow.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
.github/workflows/merge-train-autopilot.yml (2)

5-17: Consider removing stale workflow inputs.

The batch_size, max_queue, and dry_run inputs are defined but no longer used since the autopilot logic was replaced with informational output. Removing them avoids confusion for operators who might expect these parameters to have an effect.

🧹 Suggested cleanup
 on:
   workflow_dispatch:
-    inputs:
-      batch_size:
-        description: 'Number of PRs to enqueue'
-        required: true
-        default: '10'
-      max_queue:
-        description: 'Halt if merge queue depth >= N'
-        required: true
-        default: '50'
-      dry_run:
-        description: 'Dry run mode'
-        type: boolean
-        default: false
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/merge-train-autopilot.yml around lines 5 - 17, Remove the
stale workflow inputs batch_size, max_queue, and dry_run from the inputs block
of the merge-train-autopilot workflow since they are no longer used; delete the
corresponding input entries named batch_size, max_queue, and dry_run and also
remove any remaining references to these input names elsewhere in the workflow
(e.g., uses of inputs.batch_size, inputs.max_queue, inputs.dry_run or
environment variables set from them) to avoid confusion for operators.

29-38: Checkout step is unnecessary for no-op workflow.

Since the workflow only echoes informational messages, the actions/checkout step (with fetch-depth: 0 and fetch-tags: true) adds unnecessary execution time. Similarly, pull-requests: write permission is unused.

🧹 Suggested cleanup
 permissions:
   contents: read
-  pull-requests: write
+  pull-requests: read

...

 jobs:
   autopilot:
     runs-on: ubuntu-22.04
     steps:
-      - uses: actions/checkout@v4
-        with:
-          fetch-depth: 0
-          fetch-tags: true
-
       - name: Run Autopilot
         run: |
           echo "Autopilot now manual-only to prevent unsupervised queue churn."
           echo "Use GitHub native merge queue for routine sequencing."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/merge-train-autopilot.yml around lines 29 - 38, Remove the
unnecessary checkout step and unused permission in this no-op workflow: delete
the actions/checkout@v4 step (and its with keys fetch-depth and fetch-tags)
since the job only echoes messages, and remove the unused repository permission
"pull-requests: write" from the workflow permissions block; keep only the "Run
Autopilot" step that prints the informational messages (references: the
actions/checkout step, its fetch-depth/fetch-tags keys, the "Run Autopilot"
step, and the pull-requests permission).
.github/workflows/merge-queue-feeder.yml (1)

6-8: Consider reducing pull-requests: write to read.

Since the workflow now only echoes informational messages without modifying any PRs, the pull-requests: write permission is no longer needed. Reducing to read (or removing entirely) follows least-privilege principles.

🔧 Suggested permission reduction
 permissions:
   contents: read
-  pull-requests: write
+  pull-requests: read
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/merge-queue-feeder.yml around lines 6 - 8, Change the
workflow permissions in the permissions: block by replacing the "pull-requests:
write" entry with "pull-requests: read" (or remove the pull-requests key
entirely) so the workflow only has read access; update the permissions stanza
that currently contains "contents: read" and "pull-requests: write" to instead
list "contents: read" and "pull-requests: read" to follow least-privilege
principles.
.github/workflows/merge-queue.yml (1)

14-16: Static concurrency group may cause unintended serialization.

Using a fixed group: merge-queue-main for both pull_request and merge_group events means PR visibility comments and merge-queue validations compete for the same concurrency slot. With cancel-in-progress: false, a long-running validation could delay queue visibility updates.

Consider event-specific concurrency groups:

♻️ Suggested fix for event-specific concurrency
 concurrency:
-  group: merge-queue-main
+  group: ${{ github.event_name == 'merge_group' && 'merge-queue-main' || format('queue-visibility-{0}', github.event.pull_request.number) }}
   cancel-in-progress: false

This serializes merge-queue validations while allowing independent queue-visibility updates per PR.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/merge-queue.yml around lines 14 - 16, The static
concurrency block uses the fixed keys "concurrency", "group: merge-queue-main",
and "cancel-in-progress", which serializes unrelated events (pull_request vs
merge_group); change the "group" to be event-specific so visibility updates and
merge validations don't compete (e.g., use an expression like group:
merge-queue-${{ github.event_name }} or include the PR identifier such as group:
merge-queue-${{ github.event_name }}-${{ github.event.pull_request.number ||
github.ref }}), keep "cancel-in-progress" as needed, and apply this updated
concurrency stanza so pull_request and merge_group workflows use distinct
concurrency groups.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/merge-queue.yml:
- Around line 125-129: The workflow step "Critical validation suite" uses pnpm
run lint/typecheck/test with --if-present which can silently skip those critical
checks; update the job to either remove the --if-present flags so failures occur
when scripts are missing (run pnpm run lint, pnpm run typecheck, pnpm run test)
or add a preceding verification step that asserts the package.json contains the
expected scripts ("lint", "typecheck", "test") (e.g. a small shell/node check
that exits non-zero if any script key is missing) before running the pnpm
commands so the merge gate fails explicitly if scripts are absent or misspelled.
- Around line 6-8: The pull_request trigger's types array contains invalid
activity types "enqueued" and "dequeued" which will break the workflow; edit the
pull_request section (the pull_request: types: [...] array) to remove "enqueued"
and "dequeued" and keep only valid types such as "synchronize", "reopened", and
"ready_for_review" (or any other valid pull_request events you need), and if you
intended to use merge queue signals, use the merge_group event with its
supported "checks_requested" activity instead of adding non‑existent
enqueued/dequeued types.

---

Nitpick comments:
In @.github/workflows/merge-queue-feeder.yml:
- Around line 6-8: Change the workflow permissions in the permissions: block by
replacing the "pull-requests: write" entry with "pull-requests: read" (or remove
the pull-requests key entirely) so the workflow only has read access; update the
permissions stanza that currently contains "contents: read" and "pull-requests:
write" to instead list "contents: read" and "pull-requests: read" to follow
least-privilege principles.

In @.github/workflows/merge-queue.yml:
- Around line 14-16: The static concurrency block uses the fixed keys
"concurrency", "group: merge-queue-main", and "cancel-in-progress", which
serializes unrelated events (pull_request vs merge_group); change the "group" to
be event-specific so visibility updates and merge validations don't compete
(e.g., use an expression like group: merge-queue-${{ github.event_name }} or
include the PR identifier such as group: merge-queue-${{ github.event_name
}}-${{ github.event.pull_request.number || github.ref }}), keep
"cancel-in-progress" as needed, and apply this updated concurrency stanza so
pull_request and merge_group workflows use distinct concurrency groups.

In @.github/workflows/merge-train-autopilot.yml:
- Around line 5-17: Remove the stale workflow inputs batch_size, max_queue, and
dry_run from the inputs block of the merge-train-autopilot workflow since they
are no longer used; delete the corresponding input entries named batch_size,
max_queue, and dry_run and also remove any remaining references to these input
names elsewhere in the workflow (e.g., uses of inputs.batch_size,
inputs.max_queue, inputs.dry_run or environment variables set from them) to
avoid confusion for operators.
- Around line 29-38: Remove the unnecessary checkout step and unused permission
in this no-op workflow: delete the actions/checkout@v4 step (and its with keys
fetch-depth and fetch-tags) since the job only echoes messages, and remove the
unused repository permission "pull-requests: write" from the workflow
permissions block; keep only the "Run Autopilot" step that prints the
informational messages (references: the actions/checkout step, its
fetch-depth/fetch-tags keys, the "Run Autopilot" step, and the pull-requests
permission).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5a4cb46c-3a91-4da0-891b-b46a9f55586a

📥 Commits

Reviewing files that changed from the base of the PR and between 12cad4a and ccec0c3.

📒 Files selected for processing (5)
  • .github/protection/main.required-checks.json
  • .github/workflows/merge-group-heavy.yml
  • .github/workflows/merge-queue-feeder.yml
  • .github/workflows/merge-queue.yml
  • .github/workflows/merge-train-autopilot.yml

Comment on lines +6 to +8
pull_request:
types: [enqueued, dequeued, synchronize, reopened, ready_for_review]
branches: [main]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

What are the valid activity types for GitHub Actions pull_request event trigger?

💡 Result:

The valid activity types (specified using the types key) for the GitHub Actions pull_request event trigger are: - assigned - unassigned - review_requested - review_request_removed - labeled - unlabeled - opened - edited - closed - reopened - synchronize - ready_for_review - locked - unlocked - auto_merge_disabled - auto_merge_enabled By default, workflows trigger on opened, synchronize, and reopened if no types are specified. These activity types correspond to the action values in the pull_request webhook payload, which GitHub Actions uses to trigger workflows. The full list is derived from official GitHub documentation on webhook events and confirmed by examples in events-that-trigger-workflows and blog posts referencing the docs. For the most up-to-date list as of 2026, refer to https://docs.github.com/en/webhooks/webhook-events-and-payloads#pull_request and https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request.

Citations:


🌐 Web query:

What are the valid activity types for GitHub Actions merge_group event trigger?

💡 Result:

The valid activity type for the GitHub Actions merge_group event trigger is checks_requested. Unlike many other events, the merge_group event does not support multiple activity types that can be filtered with the 'types' keyword. It triggers specifically when checks are requested for a merge group in a merge queue, with GITHUB_SHA set to the merge group SHA and GITHUB_REF to the merge group ref.

Citations:


enqueued and dequeued are not valid pull_request activity types.

The enqueued and dequeued events are not valid pull_request trigger types. Valid pull_request types include: opened, closed, synchronize, reopened, ready_for_review, labeled, unlabeled, assigned, unassigned, review_requested, etc.

This means lines 7-8 contain invalid syntax that will cause the workflow to fail.

Remove the invalid event types from the pull_request trigger:

   pull_request:
-    types: [enqueued, dequeued, synchronize, reopened, ready_for_review]
+    types: [synchronize, reopened, ready_for_review]
     branches: [main]

Note: The merge_group event trigger (used for GitHub merge queues) only supports the checks_requested activity type and does not support enqueued or dequeued filtering. These event types do not exist in GitHub Actions workflow triggers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/merge-queue.yml around lines 6 - 8, The pull_request
trigger's types array contains invalid activity types "enqueued" and "dequeued"
which will break the workflow; edit the pull_request section (the pull_request:
types: [...] array) to remove "enqueued" and "dequeued" and keep only valid
types such as "synchronize", "reopened", and "ready_for_review" (or any other
valid pull_request events you need), and if you intended to use merge queue
signals, use the merge_group event with its supported "checks_requested"
activity instead of adding non‑existent enqueued/dequeued types.

Comment on lines +125 to +129
- name: Critical validation suite
run: |
pnpm run lint --if-present
pnpm run typecheck --if-present
pnpm run test --if-present
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Using --if-present may silently skip critical validations.

If lint, typecheck, or test scripts are missing or misspelled in package.json, --if-present causes pnpm to silently skip them without failure. For a merge-queue gate, this could allow broken code to merge.

Consider failing explicitly if expected scripts are missing, or add verification that the scripts ran.

🛡️ Suggested verification approach
       - name: Critical validation suite
         run: |
-          pnpm run lint --if-present
-          pnpm run typecheck --if-present
-          pnpm run test --if-present
+          pnpm run lint
+          pnpm run typecheck
+          pnpm run test

Or if some scripts are genuinely optional, add explicit checks:

       - name: Critical validation suite
         run: |
+          # Verify critical scripts exist
+          jq -e '.scripts.lint and .scripts.typecheck and .scripts.test' package.json || { echo "Missing required scripts"; exit 1; }
           pnpm run lint --if-present
           pnpm run typecheck --if-present
           pnpm run test --if-present
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Critical validation suite
run: |
pnpm run lint --if-present
pnpm run typecheck --if-present
pnpm run test --if-present
- name: Critical validation suite
run: |
pnpm run lint
pnpm run typecheck
pnpm run test
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/merge-queue.yml around lines 125 - 129, The workflow step
"Critical validation suite" uses pnpm run lint/typecheck/test with --if-present
which can silently skip those critical checks; update the job to either remove
the --if-present flags so failures occur when scripts are missing (run pnpm run
lint, pnpm run typecheck, pnpm run test) or add a preceding verification step
that asserts the package.json contains the expected scripts ("lint",
"typecheck", "test") (e.g. a small shell/node check that exits non-zero if any
script key is missing) before running the pnpm commands so the merge gate fails
explicitly if scripts are absent or misspelled.

@BrianCLong
Copy link
Copy Markdown
Owner Author

Closing duplicate — superseded by #22298

@BrianCLong BrianCLong force-pushed the codex/implement-merge-queue-system-in-ci/cd-ud4wxk branch from ccec0c3 to 07c928a Compare April 9, 2026 04:26
@BrianCLong BrianCLong merged commit 805c96f into main Apr 9, 2026
6 of 34 checks passed
@BrianCLong BrianCLong deleted the codex/implement-merge-queue-system-in-ci/cd-ud4wxk branch April 9, 2026 04:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant