Repository navigation
[finding] Merge-queue check-set parity for tree-global ratchets — measure which lint.yml jobs actually run on merge_group, then close the gap the stale-ledger outage rode through #12211
Description
Blocked-by: #12343
Filed by the spec PM seat (session_01NDGG54XF5gbTLdQzCtnaVV) after the 2026-08-25 stale-ledger outage (~70 min of fleet-wide red; incident cards: the p0 card, its two sibling filings, fix PRs #12186/#12192). Dedup: the incident cards asked triage to consider "the class fix" but no dedicated card exists; #4897 (closed) is the historical precedent that first wired merge_group into workflows.
⚠️ STATUS (PM seat #6023, 2026-08-25). Step 1 is done and it is a NEGATIVE result: step 2's premise is false. PR #12338 (9fffd327c7,Part of— deliberately notFixes) landed the measurement. No tree-global ratchet is missingmerge_groupcoverage, and adding a trigger anywhere would not have prevented the outage. Exactly four workflows carrymerge_groupas anon:trigger —ci.yml,governed-surface-guard.yml,lint.yml,spec-liveness-check.yml— all six required contexts live inci.yml+lint.yml, and no gate job or step inside them is event-gated. The two contradictory observations are resolved below. The residual is two repository SETTINGS facts, both maintainer-only, now in the decision box as #12343. This card is blocked on that ruling, not on any further measurement.
The mechanism this card closes
The gate that went red (check:exported-any-returns) is a tree-global ratchet: it judges the whole tree's consistency (ledger vs built dist), not the diff. For that gate class, PR-level green is a snapshot — a PR branched before a new gate lands (or before main's state changes) carries stale green. The only place that sees the REAL merge state is the merge queue. The outage happened because the closing PR (#12062, branched before the gate-adding #12115) passed the queue with an inconsistent tree and landed it on main.
Contradictory observations — which is why step 1 is a measurement, not a fix
- 11:50Z: fix(client): bind the three verifiable methods of the unannotated return-type erasure population (#11925) #12062 passes the merge queue carrying (binding + stale entry) — suggests the consumer-gates job does NOT run on
merge_group. - 12:26–13:05Z: five queue entries mass-dequeued without landing while main was red — CONSISTENT with the gate (or the same shared job) failing IN the queue.
Both cannot be true of a static check set. Possibilities to distinguish: the job runs on merge_group but #12062's queue run predates a required-status association; the kicks came from a different shared failure; queue batching semantics. ⛔ Do not wire anything until this is measured.
⚠️ RESOLVED by PR #12338 — and one of the two was not an observation.
- 11:50Z was a misreading. fix(client): bind the three verifiable methods of the unannotated return-type erasure population (#11925) #12062 produced no
merge_groupbuild at all (nogh-readonly-queue/main/pr-12062-*run in either workflow across 09:15–18:49Z). Positive control: the same listings carry builds forpr-12063,pr-12091,pr-12093,pr-12096,pr-12120,pr-12129and ~100 more. It never faced the queue. Its six PR-level required contexts were green at 07:20–07:35Z — about three hours before feat(devx): ratchet what packages/client's built exports resolve to #12115 added the gate at 10:21:58Z.- 12:26–13:05Z was real and is positively identified. In merge_group run
32847794799,Type Check · consumer gatesran and failed oncheck:exported-any-returns, and the requiredTypeScript Type Checkaggregate carried that red into the queue. CI was green on those same merge groups, ruling out "a different shared failure".- The third candidate — a required-status association postdating the queue run — is ruled out: the Required-Set Patrol reported registry-vs-live agreement in both directions at 04:35Z (before) and 16:35Z (after).
- The residual: four of the 29 PRs landing 09:20–12:10Z produced no
merge_groupbuild (fix(client): bind the three verifiable methods of the unannotated return-type erasure population (#11925) #12062, feat(metadata-core,objectql): publish assertEngineFindOnePredicate — the #4419 read-side guard engine doubles could not skip #12072, feat(cli): carry the computed advisory lists on everyos build --jsonfailure exit #12079, docs(spec): strip the internal issue-ids projected into the published skill catalog, and drop the gate exemption that hid them #12097), andstrict_required_status_checks_policy: falseon the main ruleset (check-required-contexts.mjs reasons from "no agent seat can read the ruleset" — measured false: the rulesets API answers 200, and the required SET is readable #9642).
Steps
- Measure: enumerate which jobs/checks actually execute on
merge_groupevents today (workflow triggers + a real queue run's check list), and diff that against the set of tree-global ratchets that run at PR level (consumer gates, spec-liveness family, the shrink-only ledgers). Also pull the queue's own logs for the 12:26–13:05 mass-dequeue to name what failed. — ✅ DONE, PR ci(lint): record the merge-queue check-set measurement — the queue already runs every tree-global ratchet #12338. - Close the gap: any tree-global ratchet missing from the queue's set gets
merge_groupcoverage (the merge queue 已启用但零 workflow 声明merge_group—— 队列里一个检查都不跑,进队列的 PR 只会空转并锁死自己的分支 #4897 pattern). After that, a fix(client): bind the three verifiable methods of the unannotated return-type erasure population (#11925) #12062-shaped race is KICKED in the queue instead of landing red on main. — ⛔ PREMISE FALSE: none is missing. The gap is settings; see [Decision] The merge queue is already at check-set parity — the 2026-08-25 outage rode a commit that never produced a merge_group build. Two settings toggles, or neither? #12343. - Explicitly out of scope: making ratchets diff-scoped (blinds them — their whole point is global invariants), and auto-re-running checks on all open PRs when a gate lands (expensive; queue parity covers the same hole at one chokepoint).
Why this is the structural layer
Detection was fast (11 min) and the repair was one line; most of the outage was the defect being ABLE to land, plus the fix queuing behind the outage's own wreckage. Queue parity removes the first; the second is a process convention (p0 fix-forward queue-jump / maintainer break-glass merge) that belongs to the PM/skills text, not to CI — noted for the maintainer separately.
⭐ That closing paragraph is now load-bearing on the decision: option A in #12343 (require the queue for
main) removes the first half and lengthens the second, because a p0 fix-forward could no longer be hand-merged past the wreckage.
Activity
yinlianghui commentedon Aug 25, 2026
Claim —
domain:devx @ objectstackseat (#6023), sessionsession_01UjM2ia8Av1v5NqfqQEQmC6.claude/issue-12211-merge-queue-check-parity../objectstack-12211(dedicated)Released from a serial hold. This card sat behind PR #12319, which was the open PR editing
.github/workflows/lint.yml's step list. #12319 merged ata6b6e54a26, so the file is free.Scope is triage's and the card's own, quoted rather than paraphrased (comment 5414498883):
Declared file surface:
.github/workflows/*.yml, and only after step 1 lands a measurement that names the gap.Serial constraint:
.github/workflows/lint.ymlis single-writer for this claim.Generated by Claude Code
ci(lint): record the merge-queue check-set measurement — no coverage …
yinlianghui commentedon Aug 25, 2026
{ "issue": 12211, "status": "needs_decision", "branch": "claude/issue-12211-merge-queue-check-parity", "pr": "https://github.com/objectstack-ai/objectstack/pull/12338", "premise_still_valid": false, "summary": "Step 1 (the measurement) is complete and it is a NEGATIVE result, so step 2's premise is falsified: no tree-global ratchet is missing merge_group coverage, and adding a trigger anywhere would not have prevented the outage. STATIC half: four workflows carry merge_group (ci, lint, governed-surface-guard, spec-liveness-check) and all six required contexts live in ci.yml + lint.yml. Inside them no gate job or gate step is event-gated — lint.yml's only github.event_name conjunct is on 'Save Turbo cache (main only)' (push), which judges nothing; ci.yml's only merge_group exclusion is the paths filter, which on a queue build WIDENS to 'everything changed'. DYNAMIC half (Actions access WAS reachable via the MCP tools, though not via direct REST): in merge_group run 32847794799 the 'Type Check · consumer gates' lane RAN and FAILED on check:exported-any-returns, and the required 'TypeScript Type Check' aggregate carried that red into the queue — that is the 12:26-13:05Z mass-dequeue, on innocent candidates, while main itself was red; CI was green on those same merge groups, ruling out 'a different shared failure'. The 11:50Z observation was a MISREADING: #12062 produced no merge_group build at all (no gh-readonly-queue/main/pr-12062-* run in either workflow across 09:15-18:49Z), so it never faced the queue; its six PR-level required contexts were green as measured at 07:20-07:35Z, ~3h BEFORE #12115 added the gate at 10:21:58Z. Four of the 29 PRs landing 09:20-12:10Z produced no merge_group build (#12062, #12072, #12079, #12097). The card's 'required-status association postdating the queue run' candidate is also ruled out: the Required-Set Patrol reported registry-vs-live agreement in both directions at 04:35Z (before) and 16:35Z (after). THE GAP IS SETTINGS, NOT WORKFLOWS — (1) a commit can reach main without producing a merge_group build, and (2) strict_required_status_checks_policy:false on the main ruleset (measured 2026-08-18, #9642). Both are maintainer-only and outside the declared file surface, so they are reported, not acted on. The PR lands the measurement only: one 39-line dated comment block in lint.yml's on: section, no behaviour change.", "tests": "Union re-derived AT the final commit 7a02e2d1ef with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (exit 0, no STALE TREE; stderr stamps repo + commit c48d46d70a merge base). 18 families named; 17 run at 7a02e2d1ef, ALL exit=0, every exit code captured before any pipe: check:agent-test-spelling, check:node-version, check:pnpm-acquisition, check:pnpm-filter-targets, check:required-contexts, check:shard-attestation, check:workflow-status-functions, check:type-check-coverage, check-aggregator-roster.mjs, check-required-contexts.mjs, check-self-test-wired.mjs, check-self-test-workflow-commands.mjs, check-shard-attestation.mjs, check-step-collectors.mjs, check-whole-set-label-write.mjs, docs-audit/check-drift-comment.mjs, pm/ci-failure.mjs --self-test. Gates' own verdict lines quoted: '✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s); 5 instruction surface(s) scanned against 2 retired name(s) (#9491).' and '✓ check-aggregator-roster: 3 aggregator(s) across 2 workflow(s); roster == needs: in both directions, and all 3 required-context aggregate(s) declared.' ⛔ check:type-check-debt = NOT MEASURED (neither pass nor fail) — its own refusal: '--re-measure cannot run: 56 workspace dependenc(ies) of the ledgered packages have no built type entry point on disk … measuring now would not fail, it would silently measure a DIFFERENT WORLD.' It needs the full workspace closure behind the shared verify lock, held throughout by another agent's packages/cli vitest run (os-verify-lock.sh --status: 'holder pid 8501, held 284s'). DECLARED NARROWING with its reason: the diff is a YAML comment in a workflow file; DEBT/TEST_DEBT are measured from TypeScript sources and package manifests, so no number this gate reads can move. CI runs it. `pnpm lint` — measured narrowing with all three evidences: (1) population read from the config itself, ESLint#isPathIgnored answers TRUE for .github/workflows/lint.yml; (2) lintFiles on it returns 1 result, 0 errors, 'File ignored because no matching configuration was supplied'; (3) positive control scripts/check-nul-bytes.mjs answers ignored=false, so the instrument distinguishes — a YAML comment cannot move any untouched file's verdict. check-nul-bytes exit=0 ('scanned 6833 text file(s) … no raw ASCII control bytes') plus a grep -naP self-scan of the changed file, 0 hits. NO ablation was run and none is claimed: the diff is inert comment text, so there is no behaviour to ablate. ⚠️ A workflow edit is the surface where a local green proves least — that caution is discharged only because no trigger, condition, job or step was touched; the diff is 39 added comment lines.", "open_questions": [ { "question": "The measurement says the merge queue's check set is already at parity, and that the outage rode a commit that never produced a merge_group build. Closing that requires a repository SETTINGS change, which is maintainer-only and outside this card's declared file surface. Which, if either, should be made?", "options": [ "A — Require the merge queue for main in Settings → Rulesets, so no commit can reach main without a merge_group build. Directly closes the measured hole: all four bypassing PRs would have been built on the real merge state, and #12062 would have been kicked instead of landing. Cost: every merge pays queue latency, and a p0 fix-forward can no longer be hand-merged past the wreckage — which is precisely the break-glass path the card's own closing section says belongs to the PM/skills text.", "B — Set strict_required_status_checks_policy: true, so a PR cannot merge on checks computed against an older base. Closes the stale-green half without removing the break-glass merge. Cost: every PR must be up to date with main before merging, which in a repo landing ~18 merges/day means near-continuous re-runs of the whole farm — expensive, and it is the cost the merge queue exists to avoid.", "C — Both A and B. Belt and braces; B becomes near-redundant once A holds, since a queue build is always computed on the real merge state.", "D — Neither; accept the residual and rely on fast detection plus the fix-forward convention. Costs nothing, changes nothing, and leaves the exact outage reproducible.", "E — Detect rather than prevent: a patrol that flags any main commit with no merge_group build. Keeps break-glass merges legal while making them visible. This is NEW mechanism the card did not authorize, so it would be its own card." ], "recommendation": "A, with E as its companion if the maintainer wants break-glass to stay legal. A is the only option that closes what was actually measured, and it is strictly stronger than B: a queue build is by construction computed on the real merge state, so A subsumes B's guarantee without B's per-PR re-run cost. The reason to pair it with E rather than take A alone is the card's own closing paragraph — most of the 70-minute outage was the FIX queuing behind the outage's own wreckage, so an unconditional queue requirement removes the hole and lengthens the repair path at the same time. B alone is the worst value of the four: it buys the smaller half of the guarantee at the higher recurring cost. ⛔ This seat did not act on any of them — all are settings, and a settings change is a maintainer decision, the same disposition triage prescribed for a measurement that argues for a change to the check regime." }, { "question": "`skip-changeset` could not be applied to PR #12338 from this seat: the additive endpoint POST /issues/12338/labels answers 403 ('GitHub access is not enabled for this session'), as does every api.github.com call from this container. It was deliberately NOT worked around with a whole-set label PUT — that shape is banned in this repo (check-whole-set-label-write) and races the size labeler.", "options": [ "A — A seat with API access adds the label additively; one call, then read back.", "B — Write an empty-frontmatter changeset instead (the objectui idiom), which this repo does not use for this case." ], "recommendation": "A. The label is this repo's declared mechanism for a PR that releases nothing, and the blocker is a transport fact about this container, not a judgment call. Until it is applied, `Check Changeset` is expected red on #12338 — that red is this gap, not a defect in the diff." } ], "out_of_scope_findings": [] }Generated by Claude Code
yinlianghui commentedon Aug 25, 2026
os-dev-report
(5415406013) was eaten by GitHub's body sanitizer after it landed — read back and confirmed
absent — which makes that copy invisible to a marker scan. The JSON below is identical; this is
the authoritative copy. There is no comment-edit tool on this seat, so the earlier one could not
be corrected in place.
{ "issue": 12211, "status": "needs_decision", "branch": "claude/issue-12211-merge-queue-check-parity", "pr": "https://github.com/objectstack-ai/objectstack/pull/12338", "premise_still_valid": false, "summary": "Step 1 (the measurement) is complete and it is a NEGATIVE result, so step 2's premise is falsified: no tree-global ratchet is missing merge_group coverage, and adding a trigger anywhere would not have prevented the outage. STATIC half: four workflows carry merge_group (ci, lint, governed-surface-guard, spec-liveness-check) and all six required contexts live in ci.yml + lint.yml. Inside them no gate job or gate step is event-gated — lint.yml's only github.event_name conjunct is on 'Save Turbo cache (main only)' (push), which judges nothing; ci.yml's only merge_group exclusion is the paths filter, which on a queue build WIDENS to 'everything changed'. DYNAMIC half (Actions access WAS reachable via the MCP tools, though not via direct REST): in merge_group run 32847794799 the 'Type Check · consumer gates' lane RAN and FAILED on check:exported-any-returns, and the required 'TypeScript Type Check' aggregate carried that red into the queue — that is the 12:26-13:05Z mass-dequeue, on innocent candidates, while main itself was red; CI was green on those same merge groups, ruling out 'a different shared failure'. The 11:50Z observation was a MISREADING: #12062 produced no merge_group build at all (no gh-readonly-queue/main/pr-12062-* run in either workflow across 09:15-18:49Z), so it never faced the queue; its six PR-level required contexts were green as measured at 07:20-07:35Z, ~3h BEFORE #12115 added the gate at 10:21:58Z. Four of the 29 PRs landing 09:20-12:10Z produced no merge_group build (#12062, #12072, #12079, #12097). The card's 'required-status association postdating the queue run' candidate is also ruled out: the Required-Set Patrol reported registry-vs-live agreement in both directions at 04:35Z (before) and 16:35Z (after). THE GAP IS SETTINGS, NOT WORKFLOWS — (1) a commit can reach main without producing a merge_group build, and (2) strict_required_status_checks_policy:false on the main ruleset (measured 2026-08-18, #9642). Both are maintainer-only and outside the declared file surface, so they are reported, not acted on. The PR lands the measurement only: one 39-line dated comment block in lint.yml's on: section, no behaviour change.", "tests": "Union re-derived AT the final commit 7a02e2d1ef with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (exit 0, no STALE TREE; stderr stamps repo + commit c48d46d70a merge base). 18 families named; 17 run at 7a02e2d1ef, ALL exit=0, every exit code captured before any pipe: check:agent-test-spelling, check:node-version, check:pnpm-acquisition, check:pnpm-filter-targets, check:required-contexts, check:shard-attestation, check:workflow-status-functions, check:type-check-coverage, check-aggregator-roster.mjs, check-required-contexts.mjs, check-self-test-wired.mjs, check-self-test-workflow-commands.mjs, check-shard-attestation.mjs, check-step-collectors.mjs, check-whole-set-label-write.mjs, docs-audit/check-drift-comment.mjs, pm/ci-failure.mjs --self-test. Gates' own verdict lines quoted: '✓ check-required-contexts: 6 required context name(s) pinned across 2 workflow(s); 5 instruction surface(s) scanned against 2 retired name(s) (#9491).' and '✓ check-aggregator-roster: 3 aggregator(s) across 2 workflow(s); roster == needs: in both directions, and all 3 required-context aggregate(s) declared.' ⛔ check:type-check-debt = NOT MEASURED (neither pass nor fail) — its own refusal: '--re-measure cannot run: 56 workspace dependenc(ies) of the ledgered packages have no built type entry point on disk … measuring now would not fail, it would silently measure a DIFFERENT WORLD.' It needs the full workspace closure behind the shared verify lock, held throughout by another agent's packages/cli vitest run (os-verify-lock.sh --status: 'holder pid 8501, held 284s'). DECLARED NARROWING with its reason: the diff is a YAML comment in a workflow file; DEBT/TEST_DEBT are measured from TypeScript sources and package manifests, so no number this gate reads can move. CI runs it. `pnpm lint` — measured narrowing with all three evidences: (1) population read from the config itself, ESLint#isPathIgnored answers TRUE for .github/workflows/lint.yml; (2) lintFiles on it returns 1 result, 0 errors, 'File ignored because no matching configuration was supplied'; (3) positive control scripts/check-nul-bytes.mjs answers ignored=false, so the instrument distinguishes — a YAML comment cannot move any untouched file's verdict. check-nul-bytes exit=0 ('scanned 6833 text file(s) … no raw ASCII control bytes') plus a grep -naP self-scan of the changed file, 0 hits. NO ablation was run and none is claimed: the diff is inert comment text, so there is no behaviour to ablate. ⚠️ A workflow edit is the surface where a local green proves least — that caution is discharged only because no trigger, condition, job or step was touched; the diff is 39 added comment lines.", "open_questions": [ { "question": "The measurement says the merge queue's check set is already at parity, and that the outage rode a commit that never produced a merge_group build. Closing that requires a repository SETTINGS change, which is maintainer-only and outside this card's declared file surface. Which, if either, should be made?", "options": [ "A — Require the merge queue for main in Settings → Rulesets, so no commit can reach main without a merge_group build. Directly closes the measured hole: all four bypassing PRs would have been built on the real merge state, and #12062 would have been kicked instead of landing. Cost: every merge pays queue latency, and a p0 fix-forward can no longer be hand-merged past the wreckage — precisely the break-glass path the card's own closing section says belongs to the PM/skills text.", "B — Set strict_required_status_checks_policy: true, so a PR cannot merge on checks computed against an older base. Closes the stale-green half without removing the break-glass merge. Cost: every PR must be up to date with main before merging, which in a repo landing ~18 merges/day means near-continuous re-runs of the whole farm — the cost the merge queue exists to avoid.", "C — Both A and B. Belt and braces; B becomes near-redundant once A holds, since a queue build is always computed on the real merge state.", "D — Neither; accept the residual and rely on fast detection plus the fix-forward convention. Costs nothing, changes nothing, and leaves the exact outage reproducible.", "E — Detect rather than prevent: a patrol that flags any main commit with no merge_group build. Keeps break-glass merges legal while making them visible. NEW mechanism the card did not authorize, so it would be its own card." ], "recommendation": "A, with E as its companion if the maintainer wants break-glass to stay legal. A is the only option that closes what was actually measured, and it is strictly stronger than B: a queue build is by construction computed on the real merge state, so A subsumes B's guarantee without B's per-PR re-run cost. The reason to pair it with E rather than take A alone is the card's own closing paragraph — most of the 70-minute outage was the FIX queuing behind the outage's own wreckage, so an unconditional queue requirement removes the hole and lengthens the repair path at the same time. B alone is the worst value of the four: it buys the smaller half of the guarantee at the higher recurring cost. ⛔ This seat did not act on any of them — all are settings, and a settings change is a maintainer decision, the same disposition triage prescribed for a measurement that argues for a change to the check regime.", "axes": { "real_business_need": "Real and measured, not speculative: one 70-minute fleet-wide red, and four commits in a single three-hour window that reached main without a queue build. The consumers are every seat whose PR was dequeued and every seat that read a red main.", "long_term_soundness": "A is the contract-first shape — the queue is already the declared chokepoint and every required context already reports there; A makes the declaration true instead of advisory. B patches the symptom at the PR layer. D leaves a known hole open, which is the workaround posture this project refuses.", "ai_authored_safety": "A is the option that makes the mistake structurally unavailable: an agent cannot land a stale-green tree by choosing the wrong merge button, because there is no such button. E only reports after the fact.", "startup_scope": "A and B are settings toggles, zero new mechanism and zero maintenance — the cheapest possible remedies. E is new mechanism and is correctly deferred to its own card rather than smuggled in here." } }, { "question": "`skip-changeset` could not be applied to PR #12338 from this seat: the additive endpoint POST /issues/12338/labels answers 403 ('GitHub access is not enabled for this session'), as does every api.github.com call from this container. It was deliberately NOT worked around with a whole-set label PUT — that shape is banned in this repo (check-whole-set-label-write) and races the size labeler.", "options": [ "A — A seat with API access adds the label additively; one call, then read back.", "B — Write an empty-frontmatter changeset instead (the objectui idiom), which this repo does not use for this case." ], "recommendation": "A. The label is this repo's declared mechanism for a PR that releases nothing, and the blocker is a transport fact about this container, not a judgment call. Until it is applied, `Check Changeset` is expected red on #12338 — that red is this gap, not a defect in the diff." } ], "out_of_scope_findings": [] }Generated by Claude Code
ci(lint): record the merge-queue check-set measurement — no coverage …
os-steve commentedon Sep 5, 2026
Unlock re-verification → closing completed. Every step of this card is discharged; nothing remains to dispatch.
domain:devx @ objectstackseat (#6023), sessionsession_01PU9zBGbH2s2ZtxSyu963M3, round 1, 2026-09-05T23:0xZ. Surfaced by the half-state patrol (#9857, sweep 2026-09-05T19:51Z, row H19): "pm:blockedwhile 1 of 1Blocked-by:target(s) is CLOSED (#12343, closed 2026-09-02T14:19:35Z): the block has outlived its blocker."This re-verification is the one the director seat named as this lane's: comment
5511018990on #12343 — "the devx seat re-verifies #12211's remaining scope before dispatch, since its own remedy was measured out by this card."放行双查 — both limbs pass
Blocked-by:target is [Decision] The merge queue is already at check-set parity — the 2026-08-25 outage rode a commit that never produced a merge_group build. Two settings toggles, or neither? #12343 and no later comment re-blocks this card on anything else; the last comment on this thread is the dev's own re-posted report (5415419002, 2026-08-25T19:12Z), which is what filed [Decision] The merge queue is already at check-set parity — the 2026-08-25 outage rode a commit that never produced a merge_group build. Two settings toggles, or neither? #12343. The condition is "[Decision] The merge queue is already at check-set parity — the 2026-08-25 outage rode a commit that never produced a merge_group build. Two settings toggles, or neither? #12343 is ruled", and it is: maintainer A (2026-08-26,5419553518, verbatim 「其他同意」), exit verified and the card closed completed by the director seat 2026-09-02 (5511018990, maintainer verbatim 「12343 已开」).closed_by_pull_requestsis empty; the card's only PR is ci(lint): record the merge-queue check-set measurement — the queue already runs every tree-global ratchet #12338 (Part of, the measurement, landed9fffd327c72026-08-25) — older than the conversion, not newer. Nothing on this card moved on past the condition.Why the exit is
completedand not a return topm:queueWalking the card's own three steps against the tree and the ruling:
merge_groupas anon:trigger; all six required contexts live inci.yml+lint.yml; no gate job or step inside them is event-gated.merge_groupcoverage, so there is no workflow edit to make. The real gap was two repository settings, split out to [Decision] The merge queue is already at check-set parity — the 2026-08-25 outage rode a commit that never produced a merge_group build. Two settings toggles, or neither? #12343 — where it was ruled A (require the merge queue onmain) and the maintainer performed it. That is the gap this card's title promised to close, and it is closed.⇒ The dispatchable residue is empty. Returning this to
pm:queuewould put a card in the queue whose only remaining instruction is one already proven false — the failure mode the unlock rule's re-verification exists to prevent (「解锁那一刻 PM 自己的判断最不可信」). Option E (a patrol flagging anymaincommit with nomerge_groupbuild) stays unruled and unowned exactly as the 08-26 ruling left it; per5511018990, with the queue required it detects something the setting now prevents, so ⛔ no follow-up card is filed here — the trigger to file one is observing a bypass merge, which this seat has not observed.mainruleset — rulesets are outside seat API access (403 from the containers). The evidence for the setting being live is the maintainer's own statement recorded by the director seat, which is that card's declared exit and ⛔ not this seat's to re-litigate.Paired write
pm:blockedstripped and the assignee cleared in the same stroke as the close (H24: a released card still carrying the parking seat's assignee is visible to the queue view and to the claim rule at once). The assigneeyinlianghuiis an agent identity, not a human — its own claim comment on this card (5415174559) declares 「domain:devx @ objectstackseat (#6023), sessionsession_01UjM2ia8Av1v5NqfqQEQmC6」 — so clearing it is in bounds.state_reason: completed, matching the close.Generated by Claude Code
ci: run the heavy workflows on pull_request for any base branch
ci: run the heavy workflows on pull_request for any base branch (obje…