Skip to content

Commit fc1a790

Browse files
os-steveclaude
andauthored
fix(pm): the queue guard's remedy names the Merge button's bypass-rules option, and a pin reads the ruleset (#19448)
Fixes #19344 Clause-②: no Item 6 of the maintainer's ratified directive — verbatim 「1 2 3 4 5 6 8」 (record `5750077963`, relayed onto this card as comment `5750078192`) — narrowed by the director's pointer `5749924838`: route **(a)** was taken in person, PR #19024 merged by bypass (`merged_by` os-zhuang, squash `2277d1f`). What remained is exactly what this PR does — the guard's remedy sentences name a path that EXISTS on ruleset `main`, and a pin fails when they name one it does not offer. ## The defect Ruleset `main` (id 12119582, enforcement `active`, target the default branch) carries a `merge_queue` rule and lists `Governed Surface Queue Guard` among its seven required contexts. So the only Merge button an ordinary account is offered is "Merge when ready" = enqueue, and the size limb then refuses the queued group. The remedy prescribed 人工直合 — "the maintainer's own click" — without naming WHICH click, and the only click that is not an enqueue is the Merge button's **bypass-rules** option, offered only while the ruleset configures a bypass actor. With none configured, the remedy named a terminal nobody could reach: PR #19024 was enqueued three times and refused three times. ## Before / after — the four sentences Each keeps 人工直合 as the NAME of the act (the 2026-09-18 ruling stands untouched); what changes is the description of how the act is reached. **1. The header sentence (`:410`, the size limb's own contract)** Before: ``` * maintainer's own click (人工直合). An authorized APPROVED review lifts a ``` After: the same opener, then — `main` mandates the queue and requires this check, so the only Merge that is not an enqueue is the Merge button's BYPASS-RULES option, offered only while the ruleset configures a bypass actor; while none was, the remedy named a terminal nobody could reach and PR #19024 was enqueued and refused three times; that it IS offered is a ruleset fact the pin reads. **2. The governed limb's early warning (`renderGuardVerdict`, Tier H block)** Before: ``` Unapproved, the maintainer's own direct merge (人工直合) is the only landing this pull request has. ``` After: ``` Unapproved, the maintainer's own direct merge (人工直合) is the only landing this pull request has, and it IS the Merge button's bypass-rules option — offered only while ruleset `main` configures a bypass actor (#19344). ``` **3. The governed limb's refusal (`renderGuardVerdict`, remedy item 2)** — same replacement, plus "the audit log records it". **4. The SIZE limb's refusal (`renderSizeVerdict`, remedy item 2)** — rendered on the #19024 shape: ``` 2. Then a HUMAN MERGE — the same terminal a governed diff has: ACCEPT on the card, `needs-user-decision` on the PR, a final 维护者速读, review requested from GOVERNED_APPROVERS (os-zhuang, hotlong); the maintainer's own click lands it (人工直合) — and that click is the Merge button's bypass-rules option, offered only while ruleset `main` configures a bypass actor — ⛔ NOT a second Merge button: `main` mandates the queue and requires this check, so with none configured every re-enqueue comes back here (#19344). The audit log records the bypass and `check-governed-merges` lists such a landing on size. ``` ## The ruleset reading this seat measured `GET /repos/objectstack-ai/objectstack/rulesets/12119582`, with this seat's token, on the day this PR was written: **HTTP 200**, and the response carries **no `bypass_actors` key at all** — not `null`, absent. The keys it does return are `id name target source_type source enforcement conditions rules node_id created_at updated_at current_user_can_bypass _links`, and `current_user_can_bypass` reads `"never"`. That is a different fact and is recorded beside it: it says THIS token is not itself a bypass actor, which is true of every agent seat and says nothing about whether the ruleset configures one for the maintainer. The director's earlier pointer read the field as `null`; this seat's read gets no key. Both are "cannot conclude", and the pin treats them differently only in what it prints. `check-required-contexts.mjs`'s measured header is the authority on why: the ruleset endpoints answer 200 for `metadata=read`, but the bypass roster is an `administration` field, and `administration` is not one of the 17 permissions a workflow may grant its `GITHUB_TOKEN`. So no token this repository's CI can hold will ever read `bypass_actors`. ## The pin, and its three verdicts One new battery in `--self-test`, five cases, driving two new pure exports (`bypassActorReading`, `remedyPathVerdict`) over a frozen copy of the measured response: | `bypass_actors` as read | reading | pin | |:--|:--|:--| | key absent (this seat's and every Actions token's answer) | `unreadable` | **PASSES**, printing `bypass_actors: unreadable with this token (the key is absent); current_user_can_bypass: "never"` | | present and `[]` or `null` | `not-offered` | **REDS** — the remedy names a path the ruleset does not offer | | present with at least one actor | `offered` | PASSES | Two ways to red, not one: the ruleset is READ to offer none, **or** the remedy stops naming a path at all — which is the defect this card filed, and a pin that only checked the first would sit green through it. The self-test prints the reading on every run, so "unreadable" is never a silent pass. ⛔ It never asserts a path from a field it did not read, and ⛔ it never reds CI on a permission difference. ## Recorded, not live — the four axes The card allowed either a live read or a recorded fixture. **Recorded, and the live read deliberately not added.** - **实际业务需求** — measured, not supposed: `bypass_actors` is unreadable to this seat's token AND to any Actions token (above). A live read wired into this self-test would therefore answer `unreadable` on every CI run in existence — it would assert nothing, on every run, while adding a network call. The real need is that the remedy sentence names a reachable path; the only party who can verify reachability is the maintainer, and their verification already happened (the #19024 bypass merge). A recorded reading is what that evidence looks like in this file. - **项目长远合理性** — this self-test is the **first step** of the required `Governed Surface Queue Guard` job, run under `bash -e` as the precondition for trusting the guard, and its own usage line declares it `offline, no network, no git`. Making a merge precondition depend on api.github.com reachability and on a token's permission tier is the permanently-red-gate shape this repo has already retired. The precedent is in-repo and exact: `check-required-contexts.mjs` keeps a frozen `RULESET_SNAPSHOT` in its self-test and leaves the live diff to a report-only mode that never runs in CI, for the same structural reason. - **防 AI 写代码犯错** — a live read is the lenient-consumer shape here: it passes for every token that cannot see the field, so the assertion would be phantom and the next author would read green as "the path is reachable". The recorded form makes the claim declared and falsifiable — change the remedy, and the pin demands a reading that offers the path; the reading is printed rather than swallowed. - **创业阶段不扩散需求** — one battery, two pure exports, one frozen object, no new entry point, no new script, no new workflow, no widened token scope. Net **+60 lines**, exactly the budget. The fixture's cost is drift, and it is bounded on purpose: it carries its provenance in the comment above it (endpoint, id, read date, token class), its reading is printed on every self-test run rather than asserted silently, and the field it records is one no CI token can re-read anyway — so a live read would not have detected drift either. ## Evidence - `node scripts/pm/check-governed-queue-guard.mjs --self-test` :: exit 0 — **301 cases** (296 before; +5 is exactly the new battery), and the run prints `ℹ #19344 ruleset reading — bypass_actors: unreadable with this token (the key is absent); current_user_can_bypass: "never"`. - **Ablation** (`scripts/ablation-replace.mjs`, wrap mode, on the committed state): anchor `click is the Merge button's bypass-rules option` replaced in `renderSizeVerdict` — on-disk proof `anchor 1 -> 0, blob 5b75964 -> e6ee4e00f482` — self-test went **red, 3 of 301**, naming `all-four-remedies-NAME-the-bypass-rules-option…`, `a-field-this-token-cannot-see-is-UNREADABLE-and-PASSES…` and `one-configured-bypass-actor-makes-the-named-path-REACHABLE…`. Restore proven byte-identical: `blob == HEAD (5b75964)` and `git diff HEAD` empty. The direction is the expected one (red), and it reds via BOTH limbs of the contract, which is what "two ways to red" means. - **Derived gate union** (`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, no paths, 31 families): 30 run with exit captured before any pipe, **all exit 0**; `pnpm check:pm-dispatch-gates` was still running when this PR was opened and is reported in the card comment. `--ran` reconciliation: 31 derived, 30 accounted with real exit codes, 0 NOT-MEASURED among them. - `node scripts/pm/check-governed-merges.mjs --test scripts/pm/check-governed-queue-guard.mjs` :: exit 0 — **NOT governed**; ordinary queue landing applies. `--pr 19024` :: exit 3 — the size-decided landing is listed, which is the recognition the remedy text now points at. - PM mechanism assumptions: (1) confirmed — the three sentences read as described on `origin/main`; (2) PR #19379's region `:268–:294` is untouched by this diff; (3) confirmed — the self-test is wired at `.github/workflows/governed-surface-guard.yml`, extended in place, no second entry point; (4) confirmed above. ## Acceptance notes - The ruleset response carries `current_user_can_bypass`, which an ordinary token CAN read and which directly answers "is the bypass option offered to the account asking". Nothing in this repo probes it live; it is recorded in this fixture only. Observation, not filed — it is a capability nobody has pulled on, and the four-axis call above is not to add a live probe to a required precondition. - `check-required-contexts.mjs`'s `RULESET_SNAPSHOT` records the 2026-08-18 reading with **six** required contexts; the live ruleset now carries **seven** (`Governed Surface Queue Guard` joined since). That file's assertions are deliberately written on the SHAPE, not on membership, and its header says so, so nothing is wrong — but the snapshot is a frozen historical reading and reads at a glance like a current one. Observation, not filed. - ⛔ Not touched, per the card's own "Not this card": the 5000-line threshold (it lives in `check-governed-merges.mjs`, imported here), the required-context set, the 「THIRD leg」 header at `:268–:294` (PR #19379's region), and any workflow. --- _Generated by [Claude Code](https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 04d639c commit fc1a790

1 file changed

Lines changed: 67 additions & 7 deletions

File tree

‎scripts/pm/check-governed-queue-guard.mjs‎

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,13 @@
407407
* landed predicate says a human MERGE — 「人工审核」 landed as the same terminal
408408
* a governed diff has (ACCEPT on the card, `needs-user-decision` on the PR, a
409409
* final 维护者速读, review requested from `GOVERNED_APPROVERS`) and the
410-
* maintainer's own click (人工直合). An authorized APPROVED review lifts a
410+
* maintainer's own click (人工直合). ⭐ #19344 — THAT CLICK IS ONE BUTTON
411+
* OPTION and this text now names it: `main` mandates the queue and requires
412+
* this check, so the only Merge that is not an enqueue is the Merge button's
413+
* BYPASS-RULES option, offered only while the ruleset configures a bypass
414+
* actor. While none was, the remedy named a terminal nobody could reach and
415+
* PR #19024 was enqueued and refused three times. That it IS offered is a
416+
* ruleset fact the pin reads. An authorized APPROVED review lifts a
411417
* Tier H path because the 2026-08-27 ruling said so of PATHS; nothing has
412418
* said it of the NUMBER, and widening a governance gate past its own ruling is
413419
* how gates acquire policy nobody agreed to. Widening it is a one-line
@@ -547,11 +553,12 @@ const SELF_TEST_BATTERIES = Object.freeze({
547553
'⭐ #18020 → #19133 Tier S: a review of record, not an approval': 43,
548554
'⭐ #18701: the record lives on the PR or its card, and BOTH are read': 14,
549555
'⛔ #19036: the SIZE line at the queue — imported, per queued PR, fail-closed': 30,
556+
'⭐ #19344: the remedy names a path the ruleset actually offers': 5,
550557
});
551558

552559
// DELETING an entry silences that battery's floor exactly as effectively as
553560
// zeroing it, so the roster's own size is pinned too.
554-
const SELF_TEST_BATTERY_FLOOR = 22;
561+
const SELF_TEST_BATTERY_FLOOR = 23;
555562

556563
// The key an assertion is filed under when no battery is open. It is not a
557564
// declared battery, so it reds by the same set difference rather than silently
@@ -1376,8 +1383,9 @@ export function renderGuardVerdict(verdict) {
13761383
` ✅ What a seat DOES do once an account in GOVERNED_APPROVERS (${GOVERNED_APPROVERS.join(', ')}) has APPROVED it,`,
13771384
' on ANY commit: the CLAIMING SEAT lands it — ruling C (#17971, maintainer 2026-09-13, verbatim',
13781385
' 「C. approve 后不管后续改动都由席位落地:」), 「席位落地 = 过落地前检、清标、ready、',
1379-
' auto-merge,踢出/变基同法。」 Unapproved, the maintainer\'s own direct merge (人工直合) is',
1380-
' the only landing this pull request has.',
1386+
' auto-merge,踢出/变基同法。」 Unapproved, the maintainer\'s own direct merge (人工直合) is the',
1387+
' only landing this pull request has, and it IS the Merge button\'s bypass-rules option —',
1388+
' offered only while ruleset `main` configures a bypass actor (#19344).',
13811389
);
13821390
}
13831391
if (tierS.length > 0) {
@@ -1469,7 +1477,8 @@ export function renderGuardVerdict(verdict) {
14691477
' 要卡最新的提交。」); the authorized set is still the 2026-08-27 one (「os-zhuang hotlong 批准',
14701478
' 算数」). ⛔ An agent seat never submits that approval, under any account — the post-merge audit',
14711479
' reads the approver too. ⛔ Unapproved, the maintainer\'s own direct merge (人工直合) is the only',
1472-
' landing this pull request has.',
1480+
' landing this pull request has, and it IS the Merge button\'s bypass-rules option — offered only',
1481+
' while ruleset `main` configures a bypass actor (#19344); the audit log records it.',
14731482
);
14741483
if (verdict.entries.some((e) => e.record !== undefined)) {
14751484
lines.push(
@@ -1925,6 +1934,32 @@ export async function runSizeGuard({ event, rows, namedPull = null, fetchPull })
19251934
return sizeGuardVerdict({ event, pulls, readings, apiCalls });
19261935
}
19271936

1937+
// ── #19344: the remedy's terminal is a RULESET fact, so it is READ ─────────
1938+
//
1939+
// GitHub offers it only to an account ruleset `main` lists as a bypass actor,
1940+
// and `bypass_actors` is withheld below `administration`, so a read answers
1941+
// three ways and only ONE is a refusal. ⛔ Never assert a path from a field that
1942+
// was not read (a permission difference must not red CI), ⛔ never pass mute.
1943+
export const BYPASS_OPTION_PHRASE = "Merge button's bypass-rules option";
1944+
1945+
/** `offered` | `not-offered` | `unreadable`, with the words a log should carry. */
1946+
export function bypassActorReading(ruleset) {
1947+
const read = ruleset && typeof ruleset === 'object' ? ruleset : {};
1948+
if (!Object.prototype.hasOwnProperty.call(read, 'bypass_actors')) {
1949+
return { reading: 'unreadable', detail: `bypass_actors: unreadable with this token (the key is absent); current_user_can_bypass: ${JSON.stringify(read.current_user_can_bypass ?? null)}` };
1950+
}
1951+
const actors = read.bypass_actors;
1952+
if (Array.isArray(actors) && actors.length > 0) return { reading: 'offered', detail: `bypass_actors: ${actors.length} configured` };
1953+
return { reading: 'not-offered', detail: `bypass_actors: ${JSON.stringify(actors)} — nobody is offered the bypass-rules option` };
1954+
}
1955+
1956+
/** Two ways to red: the remedy stops naming a path (#19344's defect), or the ruleset is READ to offer none. */
1957+
export function remedyPathVerdict({ remedy, ruleset }) {
1958+
const names = remedy.includes(BYPASS_OPTION_PHRASE);
1959+
const { reading, detail } = bypassActorReading(ruleset);
1960+
return { ok: names && reading !== 'not-offered', names, reading, detail };
1961+
}
1962+
19281963
/**
19291964
* The words a reader acts on for this leg. Returns '' on the `pull_request`
19301965
* leg. Every entry prints WHAT WAS READ — the two numbers, their sum and the
@@ -2003,7 +2038,11 @@ export function renderSizeVerdict(verdict) {
20032038
' alone does NOT dequeue it) and park it there — parked outside the queue is the SAFE state.',
20042039
' 2. Then a HUMAN MERGE — the same terminal a governed diff has: ACCEPT on the card,',
20052040
' `needs-user-decision` on the PR, a final 维护者速读, review requested from GOVERNED_APPROVERS',
2006-
` (${GOVERNED_APPROVERS.join(', ')}); the maintainer's own click lands it (人工直合).`,
2041+
` (${GOVERNED_APPROVERS.join(', ')}); the maintainer's own click lands it (人工直合) — and that`,
2042+
' click is the Merge button\'s bypass-rules option, offered only while ruleset `main` configures a',
2043+
' bypass actor — ⛔ NOT a second Merge button: `main` mandates the queue and requires this check, so',
2044+
' with none configured every re-enqueue comes back here (#19344). The audit log records the bypass',
2045+
' and `check-governed-merges` lists such a landing on size.',
20072046
' ⛔ An authorized APPROVED review does NOT lift this limb the way it lifts a Tier H path, and no',
20082047
' review of record does either: the landed predicate says a human MERGE, and widening it is the',
20092048
' maintainer\'s one-line decision in the sibling, not this file\'s.',
@@ -3851,6 +3890,25 @@ export async function selfTest() {
38513890
assert('the-workflow-is-readable-for-the-size-scope-pin', false, String(error?.message ?? error).split('\n')[0]);
38523891
}
38533892

3893+
// ── ⭐ #19344: the remedy names a path the RULESET actually offers ────────
3894+
//
3895+
// RECORDED, not live: this self-test is the required guard job's FIRST step,
3896+
// declared offline, and a live read answers `unreadable` from every token CI
3897+
// can hold — a network dependency asserting nothing. ⛔ And a pinned phrase
3898+
// split across two wrapped array entries can never match: keep it on ONE.
3899+
battery('⭐ #19344: the remedy names a path the ruleset actually offers');
3900+
// GET /repos/objectstack-ai/objectstack/rulesets/12119582, read 2026-09-20 by
3901+
// an ordinary seat token: HTTP 200, and NO `bypass_actors` key at all.
3902+
const RULESET_19344 = Object.freeze({ id: 12119582, name: 'main', enforcement: 'active', current_user_can_bypass: 'never' });
3903+
const judgeRemedy = (remedy, over = {}) => remedyPathVerdict({ remedy, ruleset: { ...RULESET_19344, ...over } });
3904+
const sizeRemedy = renderSizeVerdict(overOne);
3905+
const recorded = judgeRemedy(sizeRemedy);
3906+
console.log(` ℹ #19344 ruleset reading — ${recorded.detail}`);
3907+
assert('⭐ all-four-remedies-NAME-the-bypass-rules-option-and-keep-人工直合-as-the-name-of-the-act', recorded.names && judgeRemedy(refusalText).names && judgeRemedy(warnText).names && sizeRemedy.includes('人工直合') && /BYPASS-RULES option/.test(sizeOwnSource), sizeRemedy);
3908+
assert('⛔ a-field-this-token-cannot-see-is-UNREADABLE-and-PASSES-asserting-no-path-it-did-not-read', recorded.reading === 'unreadable' && recorded.ok === true && /unreadable with this token/.test(recorded.detail), recorded.detail);
3909+
assert('⛔ bypass_actors-PRESENT-and-EMPTY-REDS-the-remedy-names-a-path-the-ruleset-does-not-offer', judgeRemedy(sizeRemedy, { bypass_actors: [] }).ok === false && judgeRemedy(sizeRemedy, { bypass_actors: null }).reading === 'not-offered');
3910+
assert('⭐ one-configured-bypass-actor-makes-the-named-path-REACHABLE-and-the-pin-clears', judgeRemedy(sizeRemedy, { bypass_actors: [{ actor_type: 'RepositoryRole', bypass_mode: 'pull_request' }] }).ok === true);
3911+
assert('⛔ and-a-remedy-drifting-back-to-a-bare-maintainer-click-REDS-even-where-the-path-IS-offered', judgeRemedy("the maintainer's own click lands it (人工直合).", { bypass_actors: [{ actor_id: 5 }] }).ok === false);
38543912

38553913
// ── the WIRING pin: the workflow still spells this context name ──────────
38563914
//
@@ -4443,7 +4501,9 @@ export async function selfTest() {
44434501
'on the governed code; an authorized approval lifting nothing from the size; a certified regeneration lifting ' +
44444502
'nothing from it either; an unreadable size or a pull object without the pair FAIL-CLOSED on exit 9; the ' +
44454503
'pull_request leg silent and read-free; and the three-leg exit precedence (governed, size, carrier) pinned on ' +
4446-
'every combination.',
4504+
'every combination — and the #19344 remedy pin: every limb names the Merge button\'s bypass-rules option, ' +
4505+
'judged against the recorded ruleset reading, red on a present-and-empty `bypass_actors` and on a remedy ' +
4506+
'drifting back to a bare click, and passing with the reading PRINTED when the field is unreadable.',
44474507
);
44484508

44494509
selfTestReachedVerdict = true;

0 commit comments

Comments
 (0)