Skip to content

Commit 1f33392

Browse files
feat(governed): an authorized APPROVED review lifts the over-5000-line SIZE limb, as it lifts a Tier H path (#20159)
Fixes #20153 Clause-②: no ## What this lands The maintainer's ruling of 2026-09-27 (card #20153, verbatim, untranslated): 「所以阈值写死成 5000 行 , 维护者已经批准了就是可以合并。」 **An authorized APPROVED review now lifts the SIZE limb exactly as it lifts a Tier H path.** "Authorized" is an account in `GOVERNED_APPROVERS`; the predicate is the governed leg's own — latest-decisive review per account, on ANY commit (the 2026-09-04 unpinning), dismissed / superseded / unauthorized approvals never count, an unreadable review list fails closed. After the approval the owning seat lands the PR through the queue; the maintainer's direct merge stays the other landing. Unchanged, as the card requires: the threshold (5,000), the strict comparison, "generated files included", the FORK limb (no approval lifts a fork), the post-merge sweep (it still lists every oversized landing — it hands the predicate no approval), `GOVERNED_APPROVERS`, the Tier S rule, and the exit-code register (no new code). ### Mechanism — one derivation, one predicate, imported - `scripts/pm/check-governed-merges.mjs` (the predicate's home): `testVerdict(paths, { size, approval })` takes the approval verdict as DATA; `sizeVerdict(size, approval)` adds `lifted` (approvers, the commit each approval was given on, the ruling's citation) and `approvalState`; `sizeLiftFrom` reads only the verdict's `state` and its `approvals` field; `sizeLimbFires(size)` = over the line AND not lifted; `landsByHumanMerge` reads it. `exceeds` still reads true over the line — the lift is a second fact beside the number, never a change to the number. - `scripts/pm/check-governed-queue-guard.mjs` (the queue leg): the SIZE leg REUSES the governed leg's `authorizedApprovalVerdict` object for a pull request that leg already read, else runs the same derivation on one review read of its own — only for a pull request that is OVER the line (a within PR and an unreadable size make no review read; both pinned with throwing spies). `authorizedApprovalVerdict` now also returns `approvals: [{ login, commitId }]` — the field only the authorized reduction carries, so the generic `approvalVerdict` (which never asked WHO) cannot lift. The guard spells no lift condition of its own; a self-test pin reads its source to prove it. - Exit codes: lifted → 0 (the SIZE block prints approver, commit, and `objectstack#20153` with the ruling verbatim); no / unauthorized / dismissed / superseded approval → 8, as today; unreadable size → 9, as today; **an unreadable review list on an oversized PR → 8** (over the line, no lift proven; the words say the list could not be read). Code 9 stays "the SIZE could not be read". Precedence governed-then-size is unchanged. - The seat-side `check-governed-merges.mjs --pr N` reads no reviews (it never did, for the PATH limb either, and it cannot import the guard's derivation — the module cycle is measured in the file). It answers the SIZE question the way it answers the PATH question: over the line is exit 3 and the words name the two landings the queue leg then holds the PR to. On the same PR the two tools read one predicate; the queue additionally holds the approval record — the same relationship they have on a Tier H path today. ### PM mechanism assumptions — what the tree said - Assumption 3 (the authorized-approval derivation is exported by `check-governed-merges.mjs` and imported by the guard): **falsified**. `authorizedApprovalVerdict` and `GOVERNED_APPROVERS` live in the guard; the guard imports the sibling at module scope, and the reverse edge (static or lazy) deadlocks (`Detected unsettled top-level await`, measured in both files' headers). There is still exactly ONE derivation — it stays in the guard; the sibling receives its result as data and re-derives nothing. No second copy was added. - Assumption 4 (protocol text): `AGENTS.md` class (c) stated the old rule and is rewritten (same three-line block, +1 line; ratchet ceiling 1116, now 1106). `.claude/skills/pm-dispatch/SKILL.md:187` (「改动超 5000 行(含生成物)同换终局四件套」) and `references/landing-operations.md:58` (「超 5000 行(含生成物)照 Tier H」) already route an oversized PR to the Tier H terminal, whose two landings line 189 / line 60 already spell (「授权批准 ⇒ 席位落地」, 「获授权批准后认领席落地」) — consistent, untouched, so no `.claude/**` file changes in this PR. `scripts/pm/dispatch-gates.mjs`'s dispatch-time line said "lands only by a HUMAN MERGE" and is rewritten (its self-test pin updated). - Assumption 5 (`--pr 20125` as a reading): NOT MEASURED from this container — the changed-files walk answered HTTP 403 on page 2 and the tool refused rather than answering on a subset (its documented behaviour). By construction it would answer exit 3 with the words naming both landings, and the queue leg would answer 0 on `os-zhuang`'s approval on `e4ead748` (the self-test replays exactly that shape). - Assumption 8 (unreadable review list): landed as exit 8, pinned in both scripts. ### Grep table — `5,000` / `5000` / `HUMAN_MERGE_LINE_THRESHOLD` / `size limb` over `scripts/pm/**`, `AGENTS.md`, `.claude/**` at `8d1f7ab7` | file | verdict | note | |---|---|---| | `scripts/pm/check-governed-merges.mjs` | changed | predicate, header, words, 13 new pins (battery floor 30 → 44) | | `scripts/pm/check-governed-queue-guard.mjs` | changed | SIZE leg, header, words, 13 new pins + 3 rewritten (battery floor 30 → 54) | | `scripts/pm/dispatch-gates.mjs` | changed | `changedLineLines` OVER text stated "lands only by a HUMAN MERGE"; its pin updated | | `AGENTS.md` | changed | Multi-agent §7 class (c) stated "lands only by a human merge" | | `.claude/skills/pm-dispatch/SKILL.md` | consistent | line 187 routes an oversized PR to the 四件套 terminal; line 189 names its two landings | | `.claude/skills/pm-dispatch/references/landing-operations.md` | consistent | line 58 「照 Tier H」; line 60 names Tier H's two landings | | `scripts/pm/check-half-states.mjs` | consistent | "a human merge or an authorized approval is the review record"; other hits are rate-limit numbers | | `scripts/pm/check-skill-line-ratchet.mjs` | unrelated | a ceiling-ledger comment narrating the 2026-09-18 raise (history, not a rule statement) | | `scripts/pm/check-prior-rulings.mjs` | unrelated | "5,000 comments" page cap | | `.claude/skills/pm-dispatch/references/platform-readings.md`, `references/rest-channel.md` | unrelated | rate-limit quotas (5000/h) | | `board-snapshot.mjs`, `ci-failure.mjs`, `close-cards.mjs`, `fleet-token.mjs`, `issue-create.mjs`, `label-write.mjs`, `sweep-stale-finding.mjs`, `write-pace.mjs`, `check-dispatch-gates.mjs` | unrelated | numeric coincidences (fixture ids, timeouts, quota numbers) | ### New pins `check-governed-merges.mjs` — battery "⭐ the SIZE predicate": an authorized approval lifts (exceeds stays true, `landsByHumanMerge` false); threshold / strict comparison / inclusion unchanged; the words print approver, commit, `objectstack#20153` and the seat landing; exit is the NOT-governed code; no approval / `unapproved` / unauthorized / `unreadable` / the generic reduction (no `approvals` field) each still fire; an approval under the line lifts nothing; a governed PATH and a FORK head are untouched by the lift; the sweep still lists an oversized landing; the not-lifted words name both landings. `check-governed-queue-guard.mjs` — battery "⛔ #19036: the SIZE line at the queue": the governed leg's verdict object is REUSED (zero extra reads, group exits 0); #20125 replay — approval on the head and on an older commit both exit 0 with two reads; the block prints approver, commit, card and ruling; no / unauthorized / dismissed / superseded → 8 with the reason named; unreadable review list → 8 never 9; no review reader → 8; reviews are read only over the line (within PR: none; unreadable size: still 9, none); end to end governed clear + size lifted → 0, and with no approval → 8; `sizeReading` has four states; the authorized verdict carries `approvals` and the generic one does not; the guard's source spells no lift condition of its own; the remedy names both landings and keeps the bypass-rules option (#19344 battery unchanged and green). ### Verification Both self-tests green at head `52398a3b`: `check-governed-merges --self-test` 454 assertions (was 441), `check-governed-queue-guard --self-test` 292 cases (was 279). Reverse verification (ablation, committed state, `scripts/ablation-replace.mjs`, anchor hit 1 → 0, blob `4c5598c0d0c5` → `c21c9c1a3338`, restored to the HEAD blob with `git diff HEAD` empty, both legs): mutating the sibling's `sizeLimbFires` to ignore the lift reddens the guard's self-test (6 of 292 cases fail: reuse, #20125 replay, block words, end to end, four states) and the sibling's own (3 failures). Direction: 转红, as predicted. Gate list from `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` at `52398a3b` — 40 commands, all exit 0, reconciled with `--ran` (40 derived, 40 run, 0 NOT-MEASURED, 0 UNRUN; every line carries its exit code): | command | exit | |---|---| | `node scripts/check-ci-filter-parity.mjs` | 0 | | `node scripts/check-closing-keyword-parity.mjs` (+ `--self-test`) | 0 / 0 | | `node scripts/check-comment-mask-corpus.mjs` | 0 | | `node scripts/check-declaration-mirrors.mjs` (+ `--self-test`) | 0 / 0 | | `node scripts/check-scripts-symbol-anchors.mjs` (+ `--self-test`) | 0 / 0 | | `node scripts/check-self-test-wired.mjs` (+ `--self-test`) | 0 / 0 | | `node scripts/check-self-test-workflow-commands.mjs` (+ `--self-test`) | 0 / 0 | | `node scripts/check-skills-token-ratchet.mjs` (+ `--self-test`) | 0 / 0 | | `node scripts/check-whole-set-label-write.mjs` (+ `--self-test`) | 0 / 0 | | `node scripts/pm/bare-root-worklist.mjs --self-test` | 0 | | `node scripts/pm/check-governed-queue-guard.mjs --self-test` | 0 | | `pnpm check:agent-test-spelling`, `check:bash32-floor`, `check:cli-command-ids`, `check:closing-target-claim`, `check:cross-package-test-inputs`, `check:declared-population-live`, `check:docs-audit-scope`, `check:driver-memory-census`, `check:entry-guard`, `check:gitlink-declared`, `check:nul-bytes`, `check:parse-guard` | 0 each | | `pnpm check:pm-dispatch-gates` (894 s) | 0 | | `pnpm check:pm-governed-merges`, `check:pm-governed-prose`, `check:pm-skill-id-lint`, `check:pm-skill-ratchet`, `check:pnpm-filter-targets`, `check:ratchet-remedy-authority`, `check:refd-timer-probe`, `check:required-contexts`, `check:watch-hint-literal` | 0 each | Line budget: `AGENTS.md` 1105 → 1106 (ceiling 1116, headroom 10); `SKILL.md` and `landing-operations.md` unchanged (headroom 0 on both, untouched). `check-skill-line-ratchet` green. Changeset: none — the diff touches `scripts/pm/**` and `AGENTS.md` only, nothing any released package ships; `skip-changeset`. ## Acceptance notes - `check-governed-merges.mjs --pr 20125` could not be read from this container (page 2 of the files walk answered HTTP 403 through the env-token channel; the tool refused rather than answering on a subset). Not a defect; the container's credential asymmetry. - The sweep's `sizeCell` does not annotate an oversized landing with the approval that lifted it (the card allows, does not require, that note); the sweep reads `merged_by`, not reviews, so adding it would add a review read per oversized row. Left as is. - `check-skill-line-ratchet.mjs` carries a ceiling-ledger comment narrating the 2026-09-18 ruling as "takes the same terminal"; it is history of a count, not a rule statement, and is untouched. ## 维护者速读(草稿) **改了什么**:队列守卫的「超 5000 行」这一腿,现在和受管路径(Tier H)一样,承认你(或 `GOVERNED_APPROVERS` 里的账号)的 APPROVED 审查:批准过就放行,由认领席走队列落地;你直接合并这条路不变。阈值 5000、严格大于、含生成物,一个都没动;fork PR 不受此影响;事后审计照样把超 5000 行的落地列出来。 **为什么改**:你 2026-09-27 的裁决「所以阈值写死成 5000 行 , 维护者已经批准了就是可以合并。」——#20125 已获 os-zhuang 批准仍被队列两次踢出,就是这条旧规则(「只认人工合并」)造成的。 **风险与代价(含回滚)**:代价是队列对每个超线的 PR 多读一次 review 列表(已被治理腿读过的直接复用,不重复读);批准后再推的提交不再被这一腿复审——与 Tier H 路径已接受的成本同形。review 列表读不到时按「未解除」拒收(退出码 8),不会误放。回滚 = revert 本 PR,两份脚本的自测各自变红,不会静默。 **席位意见**:(留空,由席位定稿) **你要做的**:一个动作——本 PR 触及 `AGENTS.md`(Tier H),请 APPROVE 本 PR(或直接合并);批准后认领席走队列落地。 --- _Generated by [Claude Code](https://claude.ai/code/session_0148fenvVvyQV9HYxgVDQ33q)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 2bbebf5 commit 1f33392

4 files changed

Lines changed: 475 additions & 96 deletions

File tree

‎AGENTS.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -507,8 +507,9 @@ Even inside your own worktree, operate defensively:
507507
(**Prime Directive #14**, which names them and holds the current list — **this file and `CLAUDE.md` are on it**,
508508
so re-read it rather than recalling it); (b) the **Version Packages** PR, or any PR whose merge performs a
509509
release (**Prime Directive #15**); (c) a PR whose **changed lines exceed 5,000** (`additions + deletions`,
510-
generated files included) — it lands only by a human merge, which is its review record. Read the PR's file
511-
list (`get_files`), **its author and its size** before you arm anything.
510+
generated files included) — it lands the way a Tier H surface does: an authorized APPROVED review and then
511+
the owning seat, or a human merge. Read the PR's file list (`get_files`), **its author and its size** before
512+
you arm anything.
512513

513514
**Green means the gate-carrying jobs' `conclusion` is `success`** — not "no failure
514515
yet"; `in_progress` is not a pass. Arming a red PR does not queue it, it hides it:

0 commit comments

Comments
 (0)