Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/protection/main.required-checks.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
"branch": "main",
"required_status_checks": [
"meta-gate",
"CI Core Gate ",
"CI Core Gate \u2705",
"Unit Tests",
"gate",
"Release Readiness Gate",
"SOC Controls",
"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.

],
"strict": true,
"require_pull_request": true,
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/merge-group-heavy.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
name: merge-group-heavy

on:
merge_group:
workflow_dispatch:

jobs:
heavy:
if: github.event_name == 'merge_group'
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
Expand Down
46 changes: 4 additions & 42 deletions .github/workflows/merge-queue-feeder.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
name: Merge Queue Feeder

on:
schedule:
- cron: "*/2 * * * *"
workflow_dispatch:

permissions:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
contents: write
contents: read
pull-requests: write

env:
Expand All @@ -16,43 +13,8 @@ env:
jobs:
feed-queue:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install GitHub CLI
uses: cli/cli-action@v2

- name: Fetch eligible PRs
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Intentional no-op
run: |
gh pr list \
--label "queue:merge-now" \
--state open \
--json number \
> mergeable.json

- name: Determine queue depth
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr list \
--search "is:queued" \
--json number \
> queue.json

- name: Feed merge queue
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TARGET=20
CURRENT=$(jq length queue.json)

if [ "$CURRENT" -lt "$TARGET" ]; then
NEEDED=$((TARGET-CURRENT))
jq -r '.[].number' mergeable.json | head -n $NEEDED | while read pr; do
gh pr merge $pr --auto --squash
done
fi
echo "Native GitHub merge queue is authoritative."
echo "Manual feeder is retained for emergency one-off operation only."
154 changes: 116 additions & 38 deletions .github/workflows/merge-queue.yml
Original file line number Diff line number Diff line change
@@ -1,59 +1,137 @@
name: Merge Queue CI
name: merge-queue

on:
merge_group:
types: [checks_requested]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
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 👍 / 👎.

branches: [main]
Comment on lines +6 to +8
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.


permissions:
actions: read
checks: read
contents: read
pull-requests: write

concurrency:
group: merge-queue-main
cancel-in-progress: false
Comment on lines 14 to +16
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 👍 / 👎.


jobs:
merge-heavy:
name: Heavy Checks
queue-visibility:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
- name: Publish queue state comment
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const pr = context.payload.pull_request;
if (!pr) {
core.info('No pull_request payload, skipping.');
return;
}

const marker = '<!-- merge-queue-status -->';
const state = context.payload.action;
const branch = 'main';

let queueSize = 0;
let positionText = 'Not currently in queue';
let reason = 'No dequeue reason reported.';

try {
const queue = await github.request('GET /repos/{owner}/{repo}/merge-queue', {
owner: context.repo.owner,
repo: context.repo.repo,
branch,
});

const entries = queue.data?.entries ?? [];
queueSize = entries.length;
const index = entries.findIndex((entry) => entry.number === pr.number);
if (index >= 0) {
positionText = `${index + 1} of ${queueSize}`;
}
} catch (error) {
core.warning(`Unable to read merge queue: ${error.message}`);
}

if (state === 'dequeued') {
reason = context.payload.reason || 'Validation failed or PR no longer mergeable.';
}

const body = [
marker,
`### Merge Queue Status`,
`- **PR:** #${pr.number}`,
`- **Event:** ${state}`,
`- **Queue position:** ${positionText}`,
`- **Queue depth:** ${queueSize}`,
`- **Removal reason:** ${reason}`,
'',
'_Queue is FIFO and each candidate is validated on latest `main` through `merge_group` before merge._',
].join('\n');

const comments = await github.paginate(github.rest.issues.listComments, {
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
per_page: 100,
});

const existing = comments.find((comment) => comment.body?.includes(marker));

if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body,
});
}

merge-queue-critical:
if: github.event_name == 'merge_group'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout merge candidate
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 9.15.4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: 24
cache: 'pnpm'

- name: Check for PR Validation Artifact
id: validate
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
- name: Setup Node
uses: actions/setup-node@v4
with:
name: ci-validation-${{ github.event.merge_group.head_sha }}
path: .
continue-on-error: true

- name: Install
if: steps.validate.outcome != 'success'
run: pnpm install

- name: Build
if: steps.validate.outcome != 'success'
run: pnpm -r build || echo "Build skipped or no scripts"
node-version: 24
cache: pnpm

- name: Test
if: steps.validate.outcome != 'success'
run: pnpm -r test || echo "Test skipped or no scripts"
- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Audit
if: steps.validate.outcome != 'success'
run: pnpm audit || true
- name: Critical validation suite
run: |
pnpm run lint --if-present
pnpm run typecheck --if-present
pnpm run test --if-present
Comment on lines +125 to +129
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.


- name: Generate SBOM
if: steps.validate.outcome != 'success'
run: node scripts/generate_sbom.mjs || echo "SBOM generation failed"
- name: Publish merge-group summary
if: always()
run: |
echo "### Merge Queue Validation" >> "$GITHUB_STEP_SUMMARY"
echo "- Merge group SHA: ${{ github.event.merge_group.head_sha }}" >> "$GITHUB_STEP_SUMMARY"
echo "- Base ref: ${{ github.event.merge_group.base_ref }}" >> "$GITHUB_STEP_SUMMARY"
echo "- Trigger: ${{ github.event_name }}" >> "$GITHUB_STEP_SUMMARY"
35 changes: 2 additions & 33 deletions .github/workflows/merge-train-autopilot.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
name: Merge-train Autopilot

on:
schedule:
- cron: '*/30 * * * *'
workflow_dispatch:
inputs:
batch_size:
Expand All @@ -19,7 +17,6 @@ on:
default: false

permissions:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
contents: read
pull-requests: write

Expand All @@ -36,34 +33,6 @@ jobs:
fetch-tags: true

- name: Run Autopilot
id: drain
run: |
# Use inputs if provided, otherwise defaults
BATCH="${{ github.event.inputs.batch_size || '10' }}"
MAXQ="${{ github.event.inputs.max_queue || '50' }}"
DRY="${{ github.event.inputs.dry_run }}"

ARGS="--batch-size $BATCH --max-queue $MAXQ"
if [ "$DRY" == "true" ]; then ARGS="$ARGS --dry-run"; fi

# If triggered by schedule, use defaults explicitly
if [ "${{ github.event_name }}" == "schedule" ]; then
ARGS="--batch-size 10 --max-queue 50"
fi

chmod +x .github/scripts/merge-train-autopilot.sh
./.github/scripts/merge-train-autopilot.sh $ARGS | tee autopilot.log
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Step Summary
if: always()
run: |
echo "### Merge-train Autopilot Report" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
if [ -f autopilot.log ]; then
cat autopilot.log >> $GITHUB_STEP_SUMMARY
else
echo "Error: autopilot.log not found." >> $GITHUB_STEP_SUMMARY
fi
echo '```' >> $GITHUB_STEP_SUMMARY
echo "Autopilot now manual-only to prevent unsupervised queue churn."
echo "Use GitHub native merge queue for routine sequencing."
Loading