Repository navigation
pm: retire the needs:contract-review label from the tree (ruling B step ③) - #19737
Conversation
The label the leg read is retired (ruling record 5770886272 on #19061, letter B, step ③): exits 6/7, the label reader, the carrier verdict and rendering, the #17040 battery (floor 24 → 23) and the label mirror go; the module-eval-cycle explanation moves onto the surviving REVIEW_OF_RECORD_LOCATION mirror; the enumerator the size leg reads is renamed queuedPullsInGroup and its cases move into the size battery. The audit's Tier S prescriptions stop naming --pair N. Claude-Session: https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc Co-authored-by: Claude <noreply@anthropic.com>
…abel H31, H35, H51, H53 and H61 read the retired needs:contract-review label and go with it (ruling record 5770886272 on #19061, letter B, step ③): their rows, sweep sites, summary clauses, count keys, band entries and self-test sections, the gate-semantic label family, the repo-wide issue-event window and the label constant. The contract-review record readers (heading marker, head-sha span, newest-on-head finder) and bindingClosesCard stay, with their pins re-homed; the #13947 ledger fixtures move to a stall family; the gate band stays declared with no live member. Claude-Session: https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc Co-authored-by: Claude <noreply@anthropic.com>
…e legs ensure-pm-labels.sh no longer creates the label (the GitHub object is the seat's to remove); check-changeset-no-major reads the Clause-② line alone — the label carrier axis, the check-half-states import and the #17229 battery (floor 20 → 19) go; check-clause2-carriers.mjs keeps a LOCAL retired constant because its retired --pair sweep still compares it and the file cannot be deleted yet (the queue guard lazily imports its record recognisers); the label-desc-cap specimen, the workflow comments, the CONTRACT_REVIEW_TIER docblock and post-stamped's near-miss row stop naming the label or --pair. Claude-Session: https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc Co-authored-by: Claude <noreply@anthropic.com>
… ratchet rows os-dev.md, SKILL.md, the director and ui lane files, state-machine.md, dispatch-runbook.md, platform-readings.md and AGENTS.md Prime Directive #14 stop telling a seat to hang, read or expect the retired label, --pair, the double carrier or the downgrade fuse; the record-only contract stays. Ratchet rows for os-dev.md (403 → 402) and state-machine.md (42 → 41) follow the landed counts. Claude-Session: https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc Co-authored-by: Claude <noreply@anthropic.com>
…ep3-retire-clause2-label
Contract reviewServed-tier: ① Derived judgmentsRendered in-seat by the skills seat 1 session at the served tier the maintainer named on this date (the fable tier word at
② Semver levelNone — no release. ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
…ispatched claims (objectstack-ai#19792) Fixes objectstack-ai#18964 ## 维护者速读(草稿) **改了什么**:`.claude/skills/pm-dispatch/SKILL.md` 第 266 行删掉一个词「本车道」,其余一字不动,文件行数 815 不变。改前:「- 派发前在飞检查:读本车道 `pm:dispatched` 卡认领评论申报的文件面,本地求交、不另发查询。」改后:「- 派发前在飞检查:读 `pm:dispatched` 卡认领评论申报的文件面,本地求交、不另发查询。」`references/core-rules.md` 没有这句话的对应行,本 PR 不动它。 **为什么改**:执行裁决记录 5780497628(字母 B)。席位认领前的在飞检查原来只读本车道已派发卡申报的文件面,所以另一个车道里已认领、已推分支、但还没开 PR 的同文件工作单对它不可见。objectstack-ai#18314(spec 车道)与 objectstack-ai#18844(skills 车道)的双重派发就是这样漏掉的,objectstack-ai#17518 也是同一形态。改成读所有车道的已派发认领之后,申报的文件面会直接点名文件,两个实例都能命中。卡上原来提议的「按文件名词干扫描分支名」经实测证伪(两个实例 0 命中,开放 PR 上召回率 29%),裁决明确不采用(A、C 均不取)。 **风险与代价(含回滚)**:每次认领要多读其它车道已派发卡的认领评论,仍是本地求交、不另发查询;这项读取成本裁决没有实测,如果某个车道觉得太慢,另立一张带数字的卡,⛔ 不悄悄把这个词加回来。没有代码、门禁或发布面变化。回滚 = revert 这一个提交。 **席位意见**:(待席位填写) **你要做的**:无需操作。本 PR 属 Tier S(`.claude/**`),由席位出具 `## Contract review` 记录、全部检查通过后经合并队列落地。 Clause-②: no ## Summary Ruling record 5780497628 on the card (letter B, complete; A and C not taken) removes the lane qualifier from the pre-dispatch in-flight read, so a seat about to claim reads every lane's `pm:dispatched` claim comments for their declared file surfaces, still intersected locally with no extra query. One word, one line, net 0 lines. ```diff - - 派发前在飞检查:读本车道 `pm:dispatched` 卡认领评论申报的文件面,本地求交、不另发查询。 + - 派发前在飞检查:读 `pm:dispatched` 卡认领评论申报的文件面,本地求交、不另发查询。 ``` | site | before | after | |---|---|---| | `.claude/skills/pm-dispatch/SKILL.md` :266 | 121 bytes, contains 本车道 (anchor count 1) | 112 bytes, anchor gone (count 0), new sentence count 1 | | file length | 815 lines (ceiling 819) | 815 lines (ceiling 819) | Premise re-measured on base `2cf9db7c4` (the current `origin/main`): the sentence sat at :266 unchanged after PR objectstack-ai#19737 landed. ## Verification (head `8ead063f3`, the only commit) Family set derived with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` (21 commands, 1 path) and reconciled with `--ran`: 21 derived, 21 run, 0 NOT-MEASURED, 0 UNRUN, every line carrying its captured exit. All exits captured before any pipe. | command | exit | verdict line (excerpt) | |---|---|---| | `pnpm check:pm-skill-ratchet` | 0 | SKILL.md is 815 lines (ceiling 819; headroom 4); widest table row is 342 bytes (pin 342; headroom 0) | | `pnpm check:pm-skill-id-lint` | 0 | 30 file(s) clean | | `pnpm check:skill-frame-sync` | 0 | the one declared copy of the decision frame is internally coherent | | `pnpm check:skill-frame-freshness` (named by the dispatch, outside the derivation) | 0 | the decision frame in this tree is current with origin/main | | `pnpm check:doc-authoring` | 0 | 16196 customer-facing strings clean; sibling-package prose ids hold the baseline | | `pnpm check:nul-bytes` | 0 | 9262 text files, no raw ASCII control bytes | | `pnpm check:pm-governed-prose` | 0 | 2 instruction surfaces name all 6 registered governed surfaces | | `pnpm check:pm-settings-deny-roster` (roster under `.claude`, outside the derivation) | 0 | 17 content-write tools declared = enforced | | `pnpm --filter @objectstack/lint run check:doc-formula-expressions` | 0 | first run exit 3 PREREQUISITE NOT MET (formula and lint unbuilt, nothing measured); built both under the verify lock (VERDICT command-exit 0), re-run exit 0 | | `node scripts/check-closing-keyword-parity.mjs` and `--self-test` | 0 / 0 | 3 parsers agree on all 9 keywords | | `node scripts/check-comment-mask-corpus.mjs` | 0 | 7015 files, 0 disagree | | self-tests: governed-queue-guard, harness-current, pm-expected-skips, pm-governed-merges, pm-half-states | 0 each | 279 / 26 / 99 / 441 assertions / 4897 cases pass | | `pnpm check:agent-test-spelling`, `check:cross-package-test-inputs`, `check:driver-memory-census`, `check:gitlink-declared`, `check:refd-timer-probe`, `check:watch-hint-literal` | 0 each | OK | No package is touched, so there is no dependency-closure build and no package test or typecheck owed. There is no core-rules twin gate (`check:core-rules-*` does not exist in `package.json`). ## Changeset `skip-changeset`: the only path is under `.claude/**`, which is in no package's `files[]` and publishes nothing. ## Acceptance notes - `references/core-rules.md` is untouched. `grep -n '本车道'` there gives 1 hit, at :18, which is the round-opening mutex reading (the twin of SKILL.md :80), not this sentence. The core-rules line that summarises the cross-domain path (:68, 「跨域单 PR 由分诊席指定一个车道 PM 认领并申报完整文件面,在飞检查同域跨域皆跑。」) stays true after this change. - SKILL.md :267 (the cross-domain exception path adds every touched domain's in-flight cards) is now covered by :266 reading every lane. It is still true, and it stays as it is because the ruling moves nothing else. - The other 本车道 readings (SKILL.md :36, :80, :82, :230, :586, :587; `dispatch-runbook.md` :61; `seat-post-protocol.md` :28) are different rules (claim scope, round mutex, liveness baseline) and are outside the ruling. - The empty probe branch `claude/issue-18964-claim-time-branch-stem-scan` is neither reused nor deleted; the seat removes it. - Serial check at open: 16 open PRs, 308 file rows, 0 unreadable, none on `SKILL.md` or `core-rules.md` (control: 112 `.changeset/` rows read). `origin/main` has not moved from the base. This PR stays draft: `.claude/**` is Tier S, and the seat lands it after its contract-review record and a fully green run. --- _Generated by [Claude Code](https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc)_ Co-authored-by: Claude <noreply@anthropic.com>
…endered records, retriage, durable state (objectstack-ai#19795) Fixes objectstack-ai#19777 Clause-②: no ## What changed Three one-line edits, one per reference file, each paid in place under the file's `check-skill-line-ratchet.mjs` ceiling (241 / 469 / 91 — counts unchanged, every line ≤ 120 bytes, no re-wrap). Base `origin/main` at 2cf9db7. | file · section | line added | line paid | |---|---|---| | `dispatch-runbook.md` 〈接手中断的 dev(worktree 接手协议)〉 | `- 账号封禁即死会话:接手者重认领,消失的记录(认领/复核/裁决)按正文行在当前 head 重出。` | folded `- PM 会话已死 ⛔ 不推导其 dev 已死;跨账号活性只认 GitHub 产出读数。` and `- 死后恢复查三态:远程(\`git ls-remote\`)、仅容器磁盘、真没了。` into `- PM 会话已死 ⛔ 不推导其 dev 已死;死后恢复查三态:远程 \`ls-remote\`、仅容器磁盘、真没了。` — the dropped clause 跨账号活性只认 GitHub 产出读数 is line 135 of the same file (〈Routine 传输〉 block) | | `platform-readings.md` 〈API 配额〉 | `- 封号隐藏其全部评论、无 timeline 事件;assignee、PR、正文存活;分诊没了挂 \`pm:retriage\`。` | replaced the older suspension reading in the same block, `- 用户类写绑作者:封号则其评论与卡按作者 404,标签/状态/标题/正文存活。` — the director's measurement (104 cards, zero `comment_deleted` events; assignee, PRs and bodies persist) supersedes it; the `⇒ 耐久算按令牌类重算…` line under it stands | | `seat-post-protocol.md` 〈活性、写侧刷新与收班〉 | `- 耐久状态只住正文或以 App 写入;正文守中继上限 60,000 字节,超大贴由半状态巡查浮出。` | folded `- 超大贴由半状态巡查的 report-only 项浮出,⛔ 不等读取失败。` (〈贴的四段与派生视图〉) into it | Not touched: `contract-review.md` :13 / :19 (objectstack-ai#19061 step ④), `SKILL.md`, `os-dev.md`, `AGENTS.md`; no gate, hook, ratchet or roster. ## Landing Tier S (`.claude/**`) at `CONTRACT_REVIEW_TIER`: the director seat renders the `## Contract review` record on this head and lands it through the queue. `skip-changeset` — nothing published from any released package; the label is the seat's to apply (this dispatch forbids label writes by the dev). The two serial PRs the card named (objectstack-ai#19737, objectstack-ai#19771) are on `main`; nothing to rebase. ## Verification Gates derived by `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` on the edited tree at d192977; each run alone, exit captured before any pipe (`cmd > log 2>&1; ec=$?`). | command | exit | verdict line | |---|---|---| | `node scripts/check-closing-keyword-parity.mjs` | 0 | • packages/spec/CHANGELOG.md -- 6080503 bytes exceeds the sweep's 2097152-byte cutoff for UNREGISTERED files | | `node scripts/check-closing-keyword-parity.mjs --self-test` | 0 | ✓ check-closing-keyword-parity --self-test: 40 assertions, 5 mutations of the shipped parsers each driven to r | | `node scripts/check-comment-mask-corpus.mjs` | 0 | ✓ comment-mask corpus sweep [scripts/js-comment-mask.mjs]: 7015 files, 0 disagree, 0 unparseable, 89.9s (compa | | `node scripts/pm/check-governed-queue-guard.mjs --self-test` | 0 | ✓ check-governed-queue-guard self-test: 279 cases pass (register-driven verdicts, the queue/PR event split, la | | `node scripts/pm/check-harness-current.mjs --self-test` | 0 | check-harness-current --self-test: all 26 cases passed. | | `pnpm --filter @objectstack/lint run check:doc-formula-expressions` | 0 | objectstack-ai#11673). | | `pnpm check:agent-test-spelling` | 0 | which drives this same sweep RED over a temp tree on disk. | | `pnpm check:cross-package-test-inputs` | 0 | OK: 29 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob (6 of them | | `pnpm check:doc-authoring` | 0 | ✓ doc authoring guard: sibling-package prose ids hold the baseline — 819 pinned site(s) across 231 file(s), 90 | | `pnpm check:driver-memory-census` | 0 | check-driver-memory-census: OK — every declaration is ledgered, every ledger entry is live, and every ruled fi | | `pnpm check:gitlink-declared` | 0 | check-gitlink-declared: OK (9269 index entries -- 0 gitlink(s) at mode 160000; no .gitmodules in the index, so | | `pnpm check:nul-bytes` | 0 | check-nul-bytes: OK (scanned 9262 text file(s) -- 9262 tracked, 0 untracked-not-ignored; skipped 7 binary; no | | `pnpm check:pm-governed-merges` | 0 | live: the real generator declared 9 output(s) and certified this tree | | `pnpm check:pm-half-states` | 0 | ✓ check-half-states self-test: 4897 cases pass. Batteries: H66 released queue card 182/172, H19 judged-set fou | | `pnpm check:pm-skill-id-lint` | 0 | ✓ check-skill-id-lint: 30 file(s) clean (pattern /#[0-9]{3,}/g). | | `pnpm check:pm-skill-ratchet` | 0 | ✓ check-skill-line-ratchet: declared cross-file moves: 1, total ceilings down 9 lines. | | `pnpm check:refd-timer-probe` | 0 | 1 code site(s), all inside the approved module, which is present and still reads it. | | `pnpm check:required-contexts` | 0 | governed-surface-guard.yml:governed-surface-guard → 'Governed Surface Queue Guard' | | `pnpm check:skill-frame-sync` | 0 | binding sentence present in it; 1 count mention(s) agree; 86 markdown files scanned for undeclared copies. | | `pnpm check:watch-hint-literal` | 0 | ✓ check-watch-hint-literal: 71 declaration(s) across 4 rostered name(s) -- ROOT_DIR_WATCH_HINTS 47, ROOT_FILE_ | Also run on this head, named by the dispatch and outside the derived list: `pnpm check:skill-frame-freshness` exit 0 · `pnpm check:pm-governed-prose` exit 0. The doc-formula gate measured only after `@objectstack/lint` and its closure were built through `scripts/pm/os-verify-lock.sh` (VERDICT command-exit 0). `--ran` reconciliation: ✓ dispatch-gates --ran: 20 derived famil(ies) accounted for — 20 run, 0 NOT-MEASURED (a DERIVED zero — all 20 recorded an exit code and none of them is 3). --- _Generated by [Claude Code](https://claude.ai/code/session_01XPUwWGnmky4PXPofNsf2w7)_ Co-authored-by: Claude <noreply@anthropic.com>
…s; H43/H48 stand down on Tier S (objectstack-ai#19802) Part of objectstack-ai#19146 Clause-②: no ## 维护者速读(草稿) **改了什么**:两处。① `.claude/agents/os-dev.md` :286–:287 两行(净 0 行,402/402)从已废止的「事实层 = `references/` 目录、余为规则层」改写成登记表现行的两层:受管路径全在 `.claude/**` 者 Tier S,达档复核 PASS 在案即由席位入队落地;余皆 Tier H 等人批;`## 维护者速读(草稿)` 两层同欠(第二行不再豁免「事实层」)。② `scripts/pm/check-half-states.mjs` 的 H43(受管 PR 未向授权账户请审)与 H48(ACCEPT 后缺 `needs-user-decision` 标签或速读评论)在 Tier S PR 上停手:懒加载的登记表多带出 `landingTierOf` 与 `GOVERNED_TIER_S`,一个 `governedLandsOnRecord` 助手在两行已匹配的切片上问登记表,S 则不判;混合 diff 有一条 Tier H 命中仍判;登记表没加载则一律不停手。自测新增 15 例(4897 → 4912),用真实登记表自己的切片驱动;⛔ 不新增巡查行、不新增电池。 **为什么改**:这两行是每个 dev 子代理都读的自我定义,写的是 2026-09-18 分层裁决之前的边界;H43/H48 在 Tier S PR 上开的处方(请授权账户审、挂维护者收件箱标签)正是裁决取消的那一下点击,且 H43 的理由句「队列守卫仍拒收未批准的受管入队」对 Tier S 为假(PR objectstack-ai#19351 零批准、凭复核记录经队列落地)。 **风险与代价(含回滚)**:文字面零行为变化。H43/H48 在 Tier S PR 上不再报告——这是裁决的意图,不是丢失:Tier S 的落地由队列守卫按 `## Contract review` 记录把关。Tier H 与混合 diff 的行为字节不变;登记表缺席时仍照旧报 NOT MEASURED。消融证明:把 tier 读取删掉,5/4912 例转红,还原后 blob == HEAD。回滚 = revert 两个提交(各一类,可单独回退)。 **席位意见**:(席位填写) **你要做的**:本 PR 为 Tier S(`.claude/**`),由归属席位在 `## Contract review` PASS 记录 + 全绿后经队列落地,⛔ 不需要您点击。卡上余项一条(`SKILL.md:618`,见下方 On the card),由 skills 席位自处置。 ## Summary The two `os-dev.md` lines still spelled the pre-tiering split (fact layer = the `references/` directory, everything else rules layer). They are re-keyed to the register's rule as `AGENTS.md` Prime Directive objectstack-ai#14 states it: a PR whose governed paths ALL lie under `.claude/**` is Tier S and lands on the owning seat's `## Contract review` record; every other governed surface is Tier H and waits for the maintainer's word. The maintainer-brief draft is owed on both tiers (SKILL.md :623 has no tier split; the seat fills 席位意见 on both), so the second line simply stops exempting a "fact layer". The card also names `check-half-states.mjs` H48 and H43. Measured on the base: both rows still exist and are tier-blind (`governedTierFor` / `landingTierOf`: 0 hits in the file; H43 reads `GOVERNED_APPROVERS` only). On a Tier S PR each remedy asks for the click the tiering removed, so both stand down there. The tier is the register's own answer on the slice the matcher already returned — no second list of surfaces lives in the patrol. ## Per-site before → after ### `.claude/agents/os-dev.md` (402 → 402 lines, net 0; both lines within the 120-byte cap) | line | before | after | bytes | |---|---|---|---| | :286 | 「- 受管路径全在 `.claude/skills/pm-dispatch/references/` 者为事实层,席位复审即记录;余为规则层。」 | 「- 受管路径全在 `.claude/**` 者 Tier S,达档复核 PASS 在案即由席位入队落地;余皆 Tier H 等人批。」 | 118 → 120 | | :287 | 「- 规则层 PR 正文带 `## 维护者速读(草稿)` 节,中文、业务角度,席位意见留空;事实层不欠。」 | 「- 受管面 PR 正文带 `## 维护者速读(草稿)` 节,中文、业务角度,席位意见留空;两层同欠。」 | 117 → 114 | The rule they now mirror: `AGENTS.md` :272–:280 (Tier H = `docs/adr/**`, `docs/NORTH-STAR.md`, `skills/**`, `AGENTS.md`, `CLAUDE.md`, an authorized APPROVED review; Tier S = all of `.claude/**`, a `## Contract review` record for the current head with `Served-tier: CONTRACT_REVIEW_TIER` and a PASS verdict, the owning seat lands it through the queue) and SKILL.md :623 (「草稿归 dev:受管面 PR 正文带 `## 维护者速读(草稿)`」, no tier split). `grep -n 事实层 .claude/agents/os-dev.md` on the head: 0 hits. ### `scripts/pm/check-half-states.mjs` (H43 / H48) | site | before | after | |---|---|---| | `loadGovernedRegister` | reads `governedPathsIn` + `GOVERNED_APPROVERS` | also reads `landingTierOf` + `GOVERNED_TIER_S` (`tierOf`, `recordTier`); a register missing any of the four is "did not export what this row reads", as before | | new `governedLandsOnRecord(governed, register)` | — | `true` only when the register is available AND `landingTierOf(slice) === GOVERNED_TIER_S`; `false` for a Tier H or mixed slice, an empty or tier-less slice, or an unloaded register | | `h43NeedsReviewProbe(pr, governedCount, approvers)` | took a COUNT | takes the matched SLICE, stands down on Tier S — a Tier S PR buys no review page and takes no slot under the oldest-first cap | | `h43GovernedReviewRequestGap` | fired on every governed PR short of coverage | `null` on a Tier S slice; the sentence reads "open and GOVERNED on Tier H" and "refuses an unapproved Tier H enqueue" | | `h48SpeaksAbout` | population = governed ∧ open | ∧ not Tier S — so `h48GovernedVerdictWithoutBrief` is `null` there and the sweep buys no PR comment thread for it | | H43 / H48 headers, both summary clauses | tier-blind prose | name Tier H as the population; Tier S stated as out | | sweep call site | `h43NeedsReviewProbe(pr, governedByPr.get(n)?.length ?? 0, …)` | `h43NeedsReviewProbe(pr, governedByPr.get(n) ?? [], …)` | Self-test: 15 new `t()` cases (no new battery, no floor moved): the Tier S and mixed slices come from `GOVERNED_REGISTER.matcher(...)` on the real register, so the tier answer is the register's; the hand-built `GOV43` / `GOV48` fixtures carry no `tier` and read as H (fail closed), which the comments now say. Register pin extended: `tierOf(matcher(['.claude/agents/os-dev.md'])) === recordTier`. Case counts: 4897 on the base → 4912. Why stand down rather than re-aim: the card offered both. Re-aiming H43 at "a Tier S PR without a review of record" would be a new patrol row in disguise (新增门禁默认否), and the queue guard already refuses a Tier S enqueue without the record — nothing ships through that gap. Standing down is the minimal, mechanical repair the card's item 3 spells for H48 and it is the same change class for H43, so the two ride together. ## Measurement the change rests on (reads taken 2026-09-23T05:24Z–05:36Z against `origin/main` = `2cf9db7c4`; each item names its own clock) - 2026-09-23T05:24Z — `.claude/agents/os-dev.md` :286–:287 read byte-identical to the card's quotation (premise valid). - 2026-09-23T05:25Z — `check-half-states.mjs` @ `2cf9db7c4`: H48 row at :10888–:11100, H43 row at :9607–:9850; `governedTierFor` / `landingTierOf` / `recordTier`: 0 hits in the 34,841-line file; `GOVERNED_APPROVERS` is H43's only firing control. PR objectstack-ai#19737 retired H31/H35/H51/H53/H61 and left both rows in place. - 2026-09-23T05:30Z — the seat's practice on a landed Tier S PR (objectstack-ai#19351, all `.claude/**` + `scripts/pm/`): 0 reviews, no review request, no `**ACCEPT**` on the thread, no `needs-user-decision`, no `## 维护者速读` comment — one `## Contract review` PASS record, landed through the queue. H43's shape fires on exactly that PR; it fired on objectstack-ai#19379 too (card comment 5750573385). - 2026-09-23T05:36Z — register verdict on this PR's two paths: `check-governed-merges.mjs --test` → `GOVERNED — Tier S(席内达档复核落地)`, exit 3 (= EXIT_TEST_GOVERNED); `scripts/pm/check-half-states.mjs` is not on the register. - 2026-09-23T05:25Z — no open PR touches either file (all 16 open PRs' file lists read over REST at claim time). ## Reverse verification (ablation), run 2026-09-23T05:37Z at head `bd5bbd2bb` (the file is byte-identical at `c9617adde`) `node scripts/ablation-replace.mjs --file scripts/pm/check-half-states.mjs --anchor ' return register.tierOf(list) === register.recordTier;' --replacement ' return false; // ABLATION: tier reading removed' -- node scripts/pm/check-half-states.mjs --self-test` - mutation landed on disk: anchor 1 → 0, marker 0 → 1, blob `d2d9ba38ac63` → `52c8e2e35f0d` - direction observed: RED — `✗ check-half-states self-test: 5 of 4912 case(s) failed` (the H43 Tier S clean case, the H43 Tier S probe case, the register-answer join case, the H48 Tier S population case, the H48 Tier S no-finding case); the mixed-slice controls stayed green - restore proven: blob after restore `d2d9ba38ac63` == blob at HEAD; `git diff HEAD` empty; re-read on the absolute path: anchor 1, marker 0 - no `dist/` is involved (the patrol runs from source), so no build leg ## Gates on the final head `c9617adde` (run 2026-09-23T06:02Z–06:19Z; exit codes captured before any pipe; verdict lines from the gate logs) Derived with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` on this head (47 commands, list identical to the derivation at `bd5bbd2bb`); `--ran` reconciliation: `✓ dispatch-gates --ran: 47 derived famil(ies) accounted for — 46 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3).`. | # | command | exit | verdict line (from the gate log) | |---|---|---|---| | 01 | `node scripts/check-ci-filter-parity.mjs` | 0 | OK: all 185 declared cross-package glob(s) (132 unique) are covered by `core` or `crosspkg`, every `crosspkg` entry still covers one, and the `test` j | | 02 | `node scripts/check-closing-keyword-parity.mjs` | 0 | • packages/spec/CHANGELOG.md -- 6080503 bytes exceeds the sweep's 2097152-byte cutoff for UNREGISTERED files | | 03 | `node scripts/check-closing-keyword-parity.mjs --self-test` | 0 | ✓ check-closing-keyword-parity --self-test: 40 assertions, 5 mutations of the shipped parsers each driven to red. | | 04 | `node scripts/check-comment-mask-corpus.mjs` | 0 | ✓ comment-mask corpus sweep [scripts/js-comment-mask.mjs]: 7015 files, 0 disagree, 0 unparseable, 60.0s (comparator self-test: 26 cases pass). | | 05 | `node scripts/check-declaration-mirrors.mjs` | 0 | scripts/invoked-as.d.mts | | 06 | `node scripts/check-declaration-mirrors.mjs --self-test` | 0 | All 29 self-test cases passed. | | 07 | `node scripts/check-scripts-symbol-anchors.mjs` | 0 | ✅ check-scripts-symbol-anchors: 3684 anchors across 280 scripts resolve — 52 symbol (52 declaration, 0 literal), 3632 file-level, 0 cross-repo, 1 exem | | 08 | `node scripts/check-scripts-symbol-anchors.mjs --self-test` | 0 | ✅ check-scripts-symbol-anchors --self-test: every finding class provoked, comment-prose projection wired, declined shapes counted not missed, allowanc | | 09 | `node scripts/check-self-test-wired.mjs` | 0 | ✓ check-self-test-wired: every one of the 229 script(s) CI runs that ship a `--self-test` has that self-test run by CI. | | 10 | `node scripts/check-self-test-wired.mjs --self-test` | 0 | check-self-test-wired --self-test: 3 live ledger row(s) verified, plus the comment mask, the right boundary, alias resolution and both audit direction | | 11 | `node scripts/check-self-test-workflow-commands.mjs` | 0 | scope: 229 script(s) CI runs ship a `--self-test` (0 of them package-local gate(s) CI names by path, present because this population is the one chec | | 12 | `node scripts/check-self-test-workflow-commands.mjs --self-test` | 0 | check-self-test-workflow-commands --self-test: both measured parse rules pinned (legacy form anywhere in a line, current form only at line start), the | | 13 | `node scripts/check-whole-set-label-write.mjs` | 0 | PROSE_PROBES make `run()` refuse rather than pass if it ever stops finding them. | | 14 | `node scripts/check-whole-set-label-write.mjs --self-test` | 0 | ✓ check-whole-set-label-write --self-test: all cases pass (24 fixture trees + 5 refusals + 1 allowlist hatch) | | 15 | `node scripts/pm/bare-root-worklist.mjs --self-test` | 0 | OK self-test: 81 live row(s), 59 unreachable as spelled, 46 recorded verdict(s) — none stale, none missing, none contradicted (12 row(s) whose gate c | | 16 | `node scripts/pm/board-snapshot.mjs --self-test` | 0 | OK board-snapshot self-test: 156 cases pass across 12 batteries (open-first walk order, the delta-first run order and its budget split driven end to e | | 17 | `node scripts/pm/check-governed-queue-guard.mjs --self-test` | 0 | ✓ check-governed-queue-guard self-test: 279 cases pass (register-driven verdicts, the queue/PR event split, latest-decisive approval reduction, the 20 | | 18 | `node scripts/pm/check-harness-current.mjs --self-test` | 0 | check-harness-current --self-test: all 26 cases passed. | | 19 | `node scripts/pm/sweep-closed-cards.mjs --self-test` | 0 | ✓ sweep-closed-cards self-test: 87 cases pass across 9 batteries (the imported residue set, the offline screen, the two closing routes with the measur | | 20 | `pnpm --filter @objectstack/lint run check:doc-formula-expressions` | 3 | Exit status 3 | | 21 | `pnpm check:agent-model-declared` | 0 | ✓ check-agent-model-declared: 1 agent definition(s) under .claude/agents/ all declare a model | | 22 | `pnpm check:agent-test-spelling` | 0 | ✓ check-agent-test-spelling: 0 violations — 560 file(s) · 9601 bare `--` token(s) · 1810 launcher-rooted run(s) · 13 separator(s) JUDGED · 6 vitest-ba | | 23 | `pnpm check:bash32-floor` | 0 | ✓ check-bash32-floor: 33 tracked shell file(s) under scripts/**, .claude/hooks/**, .githooks/** name no bash 4+ construct outside a comment, a guarded | | 24 | `pnpm check:cli-command-ids` | 0 | ✓ check-cli-command-ids: 63 module(s) under packages/cli/src/commands examined, all of them default-export a class whose inheritance chain reaches ocl | | 25 | `pnpm check:closing-target-claim` | 0 | ✓ check-closing-target-claim self-test: 105 cases pass. | | 26 | `pnpm check:commit-card-trailers` | 0 | ✓ check-commit-card-trailers self-test: 81 cases pass. | | 27 | `pnpm check:cross-package-test-inputs` | 0 | All 255 self-test cases passed. | | 28 | `pnpm check:doc-authoring` | 0 | ✓ doc authoring guard: sibling-package prose ids hold the baseline — 819 pinned site(s) across 231 file(s), 90595 string(s) read in 1247 parsed source | | 29 | `pnpm check:driver-memory-census` | 0 | check-driver-memory-census: OK — every declaration is ledgered, every ledger entry is live, and every ruled file states "objectstack-ai#6664 census: 2 ruled consume | | 30 | `pnpm check:entry-guard` | 0 | ✓ check:entry-guard: 280 scripts/ file(s) — every entry guard goes through invoked-as.mjs; 219 export bindings, 219 of them inert on import (0 known-u | | 31 | `pnpm check:gitlink-declared` | 0 | ✓ check-gitlink-declared --self-test: 36 assertions over throwaway git repos (real scan() path) | | 32 | `pnpm check:issue-citations` | 0 | ✅ check-issue-citations --self-test: grammar narrowed, four 404 causes kept apart, both board strategies agree, diff scope red AND green, scope contra | | 33 | `pnpm check:nul-bytes` | 0 | ✓ check-nul-bytes --self-test: 75 assertions over a temp git repo (real scan() path) | | 34 | `pnpm check:parse-guard` | 0 | packages/cli/test/published-subpath-hook-body.pin.test.ts:417 ts.createSourceFile | | 35 | `pnpm check:partof-closing-keyword` | 0 | ✓ check-partof-closing-keyword self-test: 45 cases pass. | | 36 | `pnpm check:pm-governed-merges` | 0 | ✓ check-governed-merges --self-test: 441 assertions (the unified governed predicate + near misses, subject→PR spellings, window parsing, the objectstack-ai#12633 la | | 37 | `pnpm check:pm-half-states` | 0 | ✓ check-half-states self-test: 4912 cases pass. Batteries: H66 released queue card 182/172, H19 judged-set founding 37/34, H65 tier declaration spelli | | 38 | `pnpm check:pm-post-stamped` | 0 | ✓ post-stamped self-test: 610 cases pass across 21 batteries — offline, no network, no token. | | 39 | `pnpm check:pm-skill-id-lint` | 0 | ✓ check-skill-id-lint: 30 file(s) clean (pattern /#[0-9]{3,}/g). | | 40 | `pnpm check:pm-skill-ratchet` | 0 | ✓ check-skill-line-ratchet: declared cross-file moves: 1, total ceilings down 9 lines. | | 41 | `pnpm check:pnpm-filter-targets` | 0 | ✓ check:pnpm-filter-targets: 152/207 `--filter` occurrence(s) across 41 file(s) resolve against 81 workspace package(s); 55 not judged (2 foreign, 30 | | 42 | `pnpm check:ratchet-remedy-authority` | 0 | OK self-test: the lexer holds, messages are bounded, both offer word orders and path-named registries are reached, declaration registries are not, th | | 43 | `pnpm check:refd-timer-probe` | 0 | ✓ check-refd-timer-probe self-test: 11 cases pass, negative controls included. | | 44 | `pnpm check:single-claim-paths` | 0 | ✓ check-single-claim-paths self-test: 93 cases pass. | | 45 | `pnpm check:skill-frame-sync` | 0 | ✓ check-skill-frame-sync: the one declared copy of the decision frame is internally coherent (.claude/skills/pm-dispatch/SKILL.md; no second copy to c | | 46 | `pnpm check:watch-hint-literal` | 0 | ✓ check-watch-hint-literal: 71 declaration(s) across 4 rostered name(s) -- ROOT_DIR_WATCH_HINTS 47, ROOT_FILE_WATCH_HINTS 13, ROOT_WATCH_HINTS 3, DECL | | 47 | `pnpm check:pm-dispatch-gates` | 0 | ✓ dispatch-gates self-test: 1905 cases pass. (738.5s on this box) | Row 20 is exit 3 = PREREQUISITE NOT MET (the gate's own NOT-MEASURED code, see Acceptance notes); every other row exit 0. The same 47 ran at `bd5bbd2bb` with the same readings before the merge of `origin/main`. ## Line budget - `.claude/agents/os-dev.md`: 402 / ceiling 402 before and after (headroom 0, net 0 lines); `check:pm-skill-ratchet` exit 0 on the head. Max content bytes per line 120 before and after. - `skills/**` (the published catalog) is not touched, so no whole-file / whole-package token readings are owed. - `.claude/**` and `scripts/pm/**` publish nothing from any package's `files[]` (fast lane), so `skip-changeset` applies and no changeset is written. ## On the card - `landing-operations.md` :27–:28 and the queue guard's SUCCESS line: landed by PR objectstack-ai#19379 (merged `1f53b0b685`); the guard's :236 hit is a verbatim ruling quotation and stays. - `os-dev.md` :286–:287, H48, H43: this PR. - REMAINDER, measured on `origin/main` at `fae870352` and not in this PR's claimed file surface: `.claude/skills/pm-dispatch/SKILL.md:618` (the size clause ending 「⛔ 无事实层例外」) still spells the retired word (the skills seat's addendum 5737973707 joined it to this card), and 「规则层」 survives as a synonym for Tier H at `SKILL.md:617`, `references/core-rules.md:122`, `references/landing-operations.md:26` and `references/lanes/skills.md:17` (vocabulary only; each rule stays true). That is why the first line is `Part of` rather than a closing keyword: objectstack-ai#19146 remains open after this PR merges, with its own addendum item still owed. The dispatch asked for a closing first line on the premise that the two `os-dev.md` lines were the whole remainder; the tree-wide grep says otherwise, and os-dev.md's rule (a PR whose merge should not close the card uses `Part of`) wins. ## Acceptance notes (observations, not filed) - `check-half-states.mjs` H48's sentence still says the handoff exists because "a Tier H surface lands only on the maintainer's word" — accurate for Tier H under PD objectstack-ai#14 (the maintainer's hand or an authorized approval); the pre-existing "by hand" wording was narrowed to that in the same edit. - `pnpm --filter @objectstack/lint run check:doc-formula-expressions` answers exit 3 PREREQUISITE NOT MET in this worktree (the gate needs `@objectstack/formula` / `@objectstack/lint` built; this diff touches no package, so no build closure is owed). Recorded as NOT MEASURED, not as a failure; its population (docs formula expressions) is disjoint from both changed paths. - Landing: Tier S — draft stays draft; the owning seat renders the `## Contract review` record for head `c9617adde` and lands it through the queue after every check is green. --- _Generated by [Claude Code](https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Part of #19061
维护者速读(草稿)
改了什么:按裁决记录 5770886272(B 字母,第 ③ 步)把
needs:contract-review标签从代码树里退役。ensure-pm-labels.sh不再创建它;队列守卫check-governed-queue-guard.mjs的标签腿(退出码 6/7、标签读取、载体判定与渲染、#17040 电池)整段删除;check-half-states.mjs里围绕该标签巡查的五行(H31/H35/H51/H53/H61)连同扫描点、汇总句、计数键、分带登记与自测一起删除,仓库级 issue-event 窗口读取随之消失;check-changeset-no-major.mjs只读 PR 正文的Clause-②:行,标签载体轴与对check-half-states.mjs的 import 删除;.claude/**、AGENTS.md、两个 workflow 注释里叫 agent 去挂/读/等这个标签、--pair、双载体或降档保险丝的句子改成只认## Contract review记录。每个受管 PR 一条记录的契约原样保留。为什么改:维护者原话「不需要 AI 不能自审契约改动 这种」与「我们系统开发了太多无用的门禁,反而在浪费时间」;裁决 B 把三层(标签 +
--pair+ 记录)收成一层,只留记录给队列守卫读。第 ① 步(抽出readClause2Line)和第 ② 步(规则文本)已落地;这是最后一步。风险与代价(含回滚):队列守卫少一条腿,
groupExitCode变成两腿(governed → size),退出码 6/7 从登记表移除;半态巡查少五个家族(自测 5170 → 4897 例,gate分带保留但暂无成员);changeset 门禁不再把标签当声明载体,以后没写Clause-②:行的 PR 读作未声明。回滚 = revert 本 PR 的四个提交(每类一个提交,可单独回退)。⛔ GitHub 上的标签对象本 PR 不删,由席位在合并后、确认没有开着的卡或 PR 还挂着它时移除。一处残留:check-clause2-carriers.mjs把该标签常量改为文件内局部常量——它的--pair扫描已被裁决退役、无人运行,但队列守卫仍懒加载它的记录识别器与--template,所以文件还不能删;把识别器抽成小模块后整文件连同这个常量一起删,是下一步(见下方 Remainder)。席位意见:建议批准并合并。 这是裁决 5770886272(B)的最后一步,做的是「减」:标签的创建者、读者、巡查行、changeset 门禁的标签载体轴和九处叫 agent 去挂/读/等标签的句子全部退休,净 −2650 行;裁决要保留的东西一样没少 —— 队列守卫仍先看授权批准、再看
## Contract review记录(席位在头上逐段核过守卫的两腿与半态巡查保留的记录读取器),AGENTS.md:275–:281 把 Tier S 写成只认记录。四个自测(279 / 4897 / 339 / 1140 例)与十二个门禁族在席位工作树上重跑全绿。一处残留是量出来的而非选的:check-clause2-carriers.mjs还不能删,因为队列守卫懒加载它的六个记录识别器与--template;dev 给它留了本文件内的退休常量并禁止新引用。席位把「抽出识别器、整文件删除」定为 #19061 的第 ④ 步(合并后由Release:记在卡上,不另立卡),所以本 PR 首行是Part of。合并后席位删除 GitHub 上的标签对象、关闭因它而起的 objectui#9867,并放行压在这些文件后面的 #19146 / #19129 ② / #19244 ② ③。复核记录:PR 评论 5779366929(PASS,在席按服务档渲染);ACCEPT 在卡 #19061。CI 读数:33 latest-per-name check runs — 24 success, 9 skipped, 0 in progress, 0 other (the seat's read at 00:13 UTC of this date; the lint-and-repo-gates job success)。你要做的:本 PR 是 Tier H(
AGENTS.md在登记表上),草稿状态由您手动合并;合并后席位移除 GitHub 标签对象,并为「抽出记录识别器、删除check-clause2-carriers.mjs」立单。Summary
Ruling record 5770886272 on #19061 (letter B), step ③: the
needs:contract-reviewlabel leaves the tree. Every mechanism that created, read, hung, cleared or expected it is retired; the one## Contract reviewrecord per governed PR — the thing the queue guard reads to release.claude/**in the merge group — stays exactly as it was.Part ofrather thanFixes: one measured remainder is named below.Per-path disposition (18 label sites on the base, plus the prose riders)
scripts/pm/ensure-pm-labels.shneeds:contract-reviewrow (comment block +gh label create) removed; the pointer in therepo:*block reworded. The GitHub label object is NOT deleted here.scripts/pm/check-governed-queue-guard.mjsEXIT_REFUSED_CARRIER(6) andEXIT_REFUSED_CARRIER_UNREADABLE(7),CONTRACT_REVIEW_LABEL,CARRIER_LEG_NAME,carrierVerdict,runCarrierGuard,renderCarrierVerdict,makeLabelReader, the main-dispatch call, the exit table rows, the header's SECOND-leg section;groupExitCodeis two-legged (governed, size);carrierPullsInGroup(still read by the size leg) renamedqueuedPullsInGroup; the module-eval-cycle explanation moved onto the survivingREVIEW_OF_RECORD_LOCATIONmirror; the#17040battery (39 cases) removed, floor 24 → 23, its enumeration cases and the two zero-cost-clear scoping pins re-homed in the#19036size battery; the Tier S prescriptions stop naming--pair N.scripts/pm/check-half-states.mjsGATE_SEMANTIC_LABELS,isGateSemanticLabel, the event-window constants andlistRecentIssueEvents), H51 (verdict without label stroke), H53 (carrier without increment) and H61 (landed carrier) removed: rows, sweep sites, summary clauses and count keys, band entries and self-test sections;CONTRACT_REVIEW_LABELremoved. KEPT:bindingClosesCard, the record readers (CONTRACT_REVIEW_HEADING_MARKER,H51_SHA_MIN_HEX,H51_SHA_SPAN,contractReviewHeadMatch,latestContractReviewOnHead) with their pins re-homed under a "record readers" section. The#13947ledger fixtures move from H31 to astallfamily (H12); thegateband stays declared, rank 0, with no live member; the H52 reservation pin now asserts the spent number is never re-used.scripts/check-changeset-no-major.mjsdeclarationFromPullRequestreads theClause-②:body line only (nolabelsread, nocarrierfield),judgeLevel/renderLeveldropcarrier/carrierUnreadand every sentence that named the label; thecheck-half-states.mjsimport goes (the gate's first-party closure is nowclause2-line.mjsalone); the#17229battery (25 cases) removed, floor 20 → 19; the payload-snapshot docblock rewritten around the body.scripts/pm/check-clause2-carriers.mjscheck-governed-queue-guard.mjslazily imports six record recognisers from it (locateReviewOfRecord,deliveredCardNumber,servedTierStands,isModelIdentifierToken,REVIEW_OF_RECORD_THREADS,REVIEW_OF_RECORD_LOCATION) andcontract-review.mdpoints at its--template, so the ruling's deletion precondition ("nothing but the extracted module is imported") does not hold on this base. Its two imports of the retired symbols become a LOCALCONTRACT_REVIEW_LABEL/isGateSemanticLabel, docblocked as retired and import-forbidden; nothing else in it moves. This is the one CODE site still spelling the label.scripts/pm/check-widening-tells.mjsscripts/pm/check-label-desc-cap.mjsMIN_DESCRIPTIONS12 vs 38 found — untouched.scripts/pm/check-skill-line-ratchet.mjsos-dev.md403 → 402,state-machine.md42 → 41 (AGENTS.mdstays 1116 — the paragraph re-wrapped to the same count).scripts/pm/dispatch-gates.mjsCONTRACT_REVIEW_TIERdocblock no longer names the re-review sub-round, the fuse or the label bullets; the rulebook pointer goes toreferences/contract-review.md.scripts/pm/clause2-line.mjsscripts/pm/check-governed-merges.mjs--testrendering stop prescribing--pair N; two self-test pins flipped to assert its absence; the mirror docblock points atREVIEW_OF_RECORD_LOCATION.scripts/pm/post-stamped.mjs--pair..github/workflows/lint.yml.github/workflows/pr-automation.yml.claude/agents/os-dev.md:303.claude/skills/pm-dispatch/SKILL.md:769references/lanes/director.md:27/:31/:33/:35pm:*label, record stays on PR or card.references/lanes/ui.md:38../contract-review.md.references/state-machine.md:8/:10references/dispatch-runbook.md:161references/platform-readings.md:26mergeable_state: blockedreading.references/contract-review.md:13/:19--templatepointers stay valid because the script stays; they follow the file at the extraction step.AGENTS.md:278--pair Nclause removed, paragraph re-wrapped at the 120-byte budget..changeset/console-87af769e9a3e.md,docs/adr/0131-…,docs/audits/**What stays, on purpose
## Contract reviewrecord per governed PR,Served-tier:line, the queue guard's Tier S leg and its lazy import of the recognisers — ruling B, not A.CONTRACT_REVIEW_TIERindispatch-gates.mjs(path-mandate role) andreadClause2Lineinclause2-line.mjs(step ①).Remainder (why
Part of)check-clause2-carriers.mjsstill spells the label in a local constant because its deletion — the ruling's own end state for the file — waits on extracting the six record recognisers and--templateinto a module the queue guard can lazily import (a sibling of step ①, roughly the 2,700-3,000 to 4,300 line band of that file plus its record batteries). Retiring the C1/C3/gate-history rows inside a file that is slated for deletion would rewire the retired--pairsweep for nothing. The seat files that extraction as its own card; with it the last label site goes andobjectui#9867falls moot.Tests
All on the merged head
8671754c9(base106d4c8dd,origin/main342808cf5merged clean, no file overlap), exits captured before any pipe:node scripts/pm/check-governed-queue-guard.mjs --self-test— exit 0 —✓ check-governed-queue-guard self-test: 279 cases passnode scripts/pm/check-half-states.mjs --self-test— exit 0 —✓ check-half-states self-test: 4897 cases pass(5170 before; batteries H66 182/172 and H67 152/142 each lost one cross-family pin)node scripts/check-changeset-no-major.mjs --self-test— exit 0 —339 assertions;--base origin/mainexit 0 (level axis NOT APPLICABLE with nopull_request)node scripts/pm/check-clause2-carriers.mjs --self-test— exit 0 —1140 cases passpnpm check:pm-governed-mergesexit 0 ·pnpm check:pm-post-stamped596 cases ·pnpm check:pm-dispatch-gates1905 cases (748 s) ·pnpm check:pm-widening-tells525 cases ·pnpm check:pm-label-desc-capself-test + gate (38 descriptions, all ≤100) ·pnpm check:pm-skill-ratchetexit 0 (total ceilings down 9 lines) ·pnpm check:pm-skill-id-lint30 files clean ·pnpm check:pm-governed-prose6/6 surfaces ·pnpm check:nul-bytes9231 files clean ·pnpm check:commit-card-trailers5 commits cleannode scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsderives 84 commands (identical before and after the merge);--ranreconciled — run locally: 80 of them; declared to CI:pnpm --filter @objectstack/lint run check:doc-formula-expressions(needs the package build),pnpm check:partof-closing-keyword(reads the PR body),pnpm check:pm-expected-skips(reads the board);pnpm check:type-check-debtexit 3 = PREREQUISITE NOT MET (needs the packages build closure; this diff touches no package) — NOT MEASURED.pnpm exec eslint --no-inline-config --format jsonover the 11 touched.mjsfiles — exit 0, 11 files, 0 errors, 0 warnings. Population read fromeslint.config.mjs(the**/*.{ts,…,mjs,cjs}block); the config never enables type-aware linting (eslint.config.mjs:326-:328, "noparserOptions.project, no typed@typescript-eslintrules for ANY file"), so this diff moves no untouched file's verdict; the whole-repopnpm lintis CI's run.node scripts/pm/check-harness-current.mjs: STALE before and after — it compares the shared checkout's HEAD withorigin/main, which this branch does not move.node scripts/pm/check-governed-merges.mjs --pr N: run after the PR exists (expected GOVERNED, Tier H viaAGENTS.md); reported on the card.Deviations
check-clause2-carriers.mjskeeps a local retired-label constant (see Remainder) — the one departure from "the label retired from the tree", measured and named rather than forced.pnpm check:type-check-debtnot measured locally (build prerequisite);pnpm install --frozen-lockfile && pnpm buildafter the merge was not run because this diff touches no package and every gate run here reads scripts, workflows or.claude/**.Acceptance notes
scripts/pm/check-widening-tells.mjsstill describes--pair's C5 row as its live consumer (:85, :241, :1338) — that consumer is retired by ruling B; the gate's own self-test is what CI runs. Not touched here (not the label); carrier: the extraction card above. Dedupe words: widening-tells --pair C5 consumer retired.scripts/pm/check-expected-skips.mjs:118 still namescheck-clause2-carriers.mjsas the read ladder it mirrors — true while the file exists; follows the extraction.Generated by Claude Code
Generated by Claude Code