ci: merge-queue readiness audit; fix the stale "Verify (Node 24)" required-check comment - #557
Conversation
…ue readiness audit The Verify matrix comment in ci.yml still named "Verify (Node 24)" as the required check on main; #549 replaced it with the static "Verify gate" job. Audit of every required-check workflow for merge_group readiness (#536) found no other gap; findings and the settings commands live in the PR body.
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
commit: |
Summary
Merge-queue readiness audit of every workflow that provides a required check on
main, plus the one defect it found: the Verify matrix comment inci.ymlstill namedVerify (Node 24)as the required context, which #549 replaced with the staticVerify gatejob.The functional work —
merge_group:triggers, SHA-keyed concurrency for queue entries, PR-only steps skipped while the required jobs still report — already landed in #536 (this morning) and #549. Nothing in the six required jobs needs to change for a queue; the audit table below records why, per workflow, so the next reader does not have to redo it.Blocker (settings, not workflows): the repository is owned by the user account
ScriptedAlchemy(GET /repos/…→owner.type: User). GitHub offers merge queues only to organization-owned repositories ("Pull request merge queues are available in any public repository owned by an organization, or in private repositories owned by organizations using GitHub Enterprise Cloud"), and #536 already observed422 Invalid rule 'merge_queue'when creating the ruleset here. Themerge_grouptriggers therefore stay dormant until the repository is transferred to an organization. The settings section below gives the exact commands for both the immediate option (drop the up-to-date requirement) and the queue option (after a transfer).Protection findings (as of this PR)
GET /repos/ScriptedAlchemy/agent-bundle/rulesets→[];GET …/rules/branches/main→[].main(GET …/branches/main/protection):required_status_checks.strict: true← the cascade: every merge tomaininvalidates every other open PR, which mustgh pr update-branchand re-run all six checks.app_id: 15368):Changeset present,Docs site (Node 22.19),Host install proofs (Node 22.19),Examples check (Node 22.19),Release gates (Node 22.19),Verify gate.enforce_admins: false,required_linear_history: false, force pushes and deletions blocked, conversation resolution / lock / block-creations off.Current classic protection JSON (
GET repos/ScriptedAlchemy/agent-bundle/branches/main/protection){ "required_status_checks": { "strict": true, "contexts": [ "Changeset present", "Docs site (Node 22.19)", "Host install proofs (Node 22.19)", "Examples check (Node 22.19)", "Release gates (Node 22.19)", "Verify gate" ], "checks": [ { "context": "Changeset present", "app_id": 15368 }, { "context": "Docs site (Node 22.19)", "app_id": 15368 }, { "context": "Host install proofs (Node 22.19)", "app_id": 15368 }, { "context": "Examples check (Node 22.19)", "app_id": 15368 }, { "context": "Release gates (Node 22.19)", "app_id": 15368 }, { "context": "Verify gate", "app_id": 15368 } ] }, "required_signatures": { "enabled": false }, "enforce_admins": { "enabled": false }, "required_linear_history": { "enabled": false }, "allow_force_pushes": { "enabled": false }, "allow_deletions": { "enabled": false }, "block_creations": { "enabled": false }, "required_conversation_resolution": { "enabled": false }, "lock_branch": { "enabled": false }, "allow_fork_syncing": { "enabled": false } }Per-workflow audit
merge_grouptodayci.ymlVerify gate,Examples check (Node 22.19),Release gates (Node 22.19),Host install proofs (Node 22.19)merge_group: branches: [main](#536).changes(docs-only classifier) is PR-only, so queue entries never skip heavy jobs; Verify runs the Node 24 leg for PRs and queue entries;verify-gaterunsalways();dependency-reviewis PR-only and not required. Concurrencyci-${{ github.event.pull_request.number || github.sha }}, cancellation only forpull_request.Verify gate(wasVerify (Node 24), stale since #549).changeset.ymlChangeset presentmerge_group: branches: [main](#536). Every step isif: github.event_name != 'merge_group'except a notice step, so the job reports success without evaluating: amerge_grouppayload has no PR labels and the commit stacks earlier queue entries; the requirement is enforced on the PR, which must be green to enter the queue.docs.ymlDocs site (Node 22.19)merge_group: branches: [main](#536). Build/lint/site-build run; Pages upload anddeploystay gated onpush/workflow_dispatchofrefs/heads/main. Queue refs (gh-readonly-queue/main/…) get SHA-keyed concurrency.package-preview.ymlpull_request+push: mainonly. Not required; pkg.pr.new previews are per-PR and per-main-commit.release.ymlpush: mainonly (Version Packages / publish).mcp-conformance.yml,native-host-smoke.ymlworkflow_dispatchonly.branches: [main]undermerge_groupfilters on the queue's base branch (confirmed by the Actions team in github/docs#32879), so the required workflows run forgh-readonly-queue/main/…refs.actionlintpasses on the changed file (the only repo-wide finding is the pre-existing, intentional SC2016 inrelease.yml).merge_group behaviours handled (all pre-existing, verified)
github.event.pull_requestobject: every read of it sits behind anif: github.event_name == 'pull_request'job/step or an||fallback togithub.sha.github.refisrefs/heads/gh-readonly-queue/main/pr-<n>-<sha>: no workflow compares it tomainexcept the deploy gates indocs.yml, which is the intended exclusion.Changeset presentreports success on queue entries instead of re-derivingskip-changesetand the release-branch exemption (already enforced on the PR).Detect changed paths,Dependency review,Publish pkg.pr.new previeware not in the protection).Settings change to apply after merge
There is no ruleset to
PUT/PATCH, and amerge_queuerule is rejected on a user-owned repository, so the requested ruleset command cannot be applied as-is. Two options; neither is applied by this PR.Option A — stop the cascade now (no queue): loose required checks
Effect: a PR merges once its own six checks are green, even when behind
main;gh pr merge --squash --automerges immediately with noupdate-branch. Trade-off: this reintroduces the failure mode #536 closed (individually green PRs that breakmainwhen combined — #486×#490, #518×#509); thepush: mainCI run (full Node matrix) would catch it after the merge instead of before. AGENTS.md's "branch up to date withmain(gh pr update-branch, …)" sentence would need a follow-up edit.Option B — the real merge queue (requires an organization-owned repository)
Transfer the repository to an organization (Settings → Danger Zone → Transfer, or
gh api --method POST repos/ScriptedAlchemy/agent-bundle/transfer -f new_owner=<org>). GitHub redirects the repository URL, but the Pages site moves fromscriptedalchemy.github.io/agent-bundleto<org>.github.io/agent-bundle(updatewebsite/base/links and the AGENTS.md URL), and the Codex review app, Actions secrets/variables, and Pages source should be re-verified after the transfer.Create the ruleset (none exists, so this is a
POST, not aPUT). It mirrors the current protection — deletion and force-push blocked, the same six contexts fromintegration_id15368, admin bypass to matchenforce_admins: false— withstrict_required_status_checks_policy: false(the queue provides the up-to-date guarantee) and themerge_queuerule:main-merge-queue-ruleset.json:{ "name": "main", "target": "branch", "enforcement": "active", "bypass_actors": [ { "actor_id": 5, "actor_type": "RepositoryRole", "bypass_mode": "always" } ], "conditions": { "ref_name": { "include": ["refs/heads/main"], "exclude": [] } }, "rules": [ { "type": "deletion" }, { "type": "non_fast_forward" }, { "type": "required_status_checks", "parameters": { "strict_required_status_checks_policy": false, "do_not_enforce_on_create": false, "required_status_checks": [ { "context": "Changeset present", "integration_id": 15368 }, { "context": "Docs site (Node 22.19)", "integration_id": 15368 }, { "context": "Examples check (Node 22.19)", "integration_id": 15368 }, { "context": "Host install proofs (Node 22.19)", "integration_id": 15368 }, { "context": "Release gates (Node 22.19)", "integration_id": 15368 }, { "context": "Verify gate", "integration_id": 15368 } ] } }, { "type": "merge_queue", "parameters": { "merge_method": "SQUASH", "grouping_strategy": "ALLGREEN", "max_entries_to_build": 5, "min_entries_to_merge": 1, "max_entries_to_merge": 5, "min_entries_to_merge_wait_minutes": 5, "check_response_timeout_minutes": 60 } } ] }Drop
bypass_actorsto make repository admins go through the queue too (AGENTS.md already forbids--adminbypass).Retire the classic protection so the ruleset is the single source of truth (otherwise its
strict: truekeeps demanding up-to-date branches). Run this only after step 2 succeeded, somainis never unprotected:Rollback:
PUT repos/<org>/agent-bundle/branches/main/protectionwith the JSON in the details block above (required_pull_request_reviews: null,restrictions: null).Once the queue is on,
gh pr merge --squash --autono longer merges directly: it enqueues the PR as soon as its own checks are green, the queue buildsmain+ earlier entries + the PR on agh-readonly-queue/main/pr-<n>-<sha>ref, the six required checks run there viamerge_group, and GitHub squash-merges the group (merge_method: SQUASH) when they pass — noupdate-branch, no per-PR re-run of everyone else's CI.Changeset
CI-only (
.github/workflows/ci.ymlcomment); no publishable package changes, soChangeset presentpasses without a label, as on #553.Self-review
Reviewer:
gpt-5.6-sol-medium(change-risk-reviewer), against the diff vsorigin/mainat ee27c41..github/workflows/ci.yml; YAML unaffected; job names verified asVerify (Node …)plus the staticVerify gate;ci.yml,changeset.yml, anddocs.ymlonorigin/mainall carrymerge_group: branches: [main](from ci: run required checks on merge_group for the merge queue #536).strict: true; contexts:Changeset present,Docs site (Node 22.19),Host install proofs (Node 22.19),Examples check (Node 22.19),Release gates (Node 22.19),Verify gate— the same six contexts listed in the audit table and details block above, withVerify gate(notVerify (Node 24)) as the required name. Raw output ofgh api repos/ScriptedAlchemy/agent-bundle/branches/main/protection/required_status_checks --jq '{strict, contexts}':{"contexts":["Changeset present","Docs site (Node 22.19)","Host install proofs (Node 22.19)","Examples check (Node 22.19)","Release gates (Node 22.19)","Verify gate"],"strict":true}.