pm-dispatch: name the review of record for default-tier lanes, make clearing cite it, and read it in check-clause2-carriers --pair (C6) - #17349
Conversation
…--pair reads it (C6) contract-review.md names the default-tier lanes' review of record — one comment on the PR or its card in the tier verdict's shape minus the tier line — and makes every clear cite it; SKILL.md and core-rules carry the twin lines. check-clause2-carriers --pair gains C6: on a completed pair it reads the PR's thread and the card's for that record (H51's heading + head-sha shape, plus a Reviewed-by: line) and answers 4 when none exists. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MoTv7pn338AZ71owsp19gQ
…e count The C6-RECORD note made renderPair print the C2-SIBLING wording; each note kind now speaks for itself, and a found record is named in the sentence. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MoTv7pn338AZ71owsp19gQ
维护者速读改了什么 —— 给默认档车道的「复核记录」定一个具名的载体和形状:一条评论落在 PR 或卡上,带 为什么改 —— 09-10 档位改制后,默认档车道的复核不再经契约复审档,通知里说「席位自审加门禁就是复核记录」,却没说记录长什么样、放在哪。总监席一扫:一个窗口里五次条款②合并没有任何复核记录,清标和从未复核在板上分不开,事后审计也无从审起。这是本席通知的漏洞,这张卡补上。 风险与代价(含回滚) —— 不进发布包。C6 是硬 4(该文件的退出码表里,对子上任何一个不利事实都是 4,不允许 0 带口信),只在「已完成」态才触发,不会重新挡住任何合法流程;巡查行仍只报告。代价:清标多写一行引用;各席 ACCEPT 评论要带题头——本席自己之前的 ACCEPT 就没带题头(dev 在板上量了:不算记录),从本 PR 的验收评论起改用同形。回滚 = revert 一个提交。 席位意见 —— 本席按契约复审档自审通过:三个技能文件的行与两条 ask 逐句对得上;C6 的识别形状复用 H51 的题头 + head 码段加 你要做的 —— 人工合并本 draft PR(受管面 Generated by Claude Code |
Fixes #17302
Summary
After the tier policy landed, the rule text said the lane seat's own default-tier review "plus the gates" is the review of record for every lane but spec and skills — and named neither where that review lives nor what it must contain. This PR names it, makes every clearing of
needs:contract-reviewcite it, and teachescheck-clause2-carriers --pairto read "a review of record exists on this head" as a row of its own (C6). Three governed rule files are rewritten in place at their ceilings (812 / 60 / 151, net zero); onescripts/pmgate gains one row, one battery and one read.The finding's evidence (quoted from #17302)
yesin prose, no line-start declaration, no card-side verdictCard #15951's thread, read for this PR: a
Claim:, three dispatch-failure notes, the dev'sos-dev-report, a PM correction, and 「Closing by hand — PR #17181 merged as6058cb2」 — no comment on either carrier that names a reviewer. Ask 3 is ruled on the card (the five merges are accepted under the transition) and nothing here touches them.The review of record — the shape, spelled once
ONE comment on the PR or on its card, on the merged/landing head, carrying:
## Contract review(H51's marker incheck-half-states.mjs, measured over four live dialects — the same heading may sit on a later line of a director adoption record);contractReviewHeadMatch: a 7–40 hex span that is a prefix of the PR's current head);Implemented-by:andReviewed-by:;That is the tier verdict's shape minus the tier line. Measured on the board this PR was written against, every 2026-09-09 tier verdict already satisfies it (PR #17073 comments 5597841101 and 5600239551, PR #17116 comment 5600627944, PR #17090 comment 5598904803: heading, head span,⚠️ The skills seat's own ACCEPT comments on cards #17285 / #17288 / #17308 (5613072104, 5614148443, 5614255952) carry the head and a
**Reviewed-by:**). A bareos-dev-reportnever does, nor does the implementer's own comment (the implementer is not the reviewer).Reviewed-by:line under a bold first line and NO heading — under this text they are not a record either, and the seat's next clearing must write the heading. The C6 self-test pins that exact shape as a control.What the gate READS is items 1, 2 and the
Reviewed-by:key line of item 4 — never the verdict word (the file's standing boundary: reading a verdict to clear a gate is 自查放行; H51 is verdict-agnostic by construction; and the live corpus already spells the word two ways — a fencedVERDICT: PASSon the 2026-09-01 board,**Verdict: PASS WITH FINDINGS**on the 2026-09-09 board — so a regex for it would be a third spelling), and never the ①②③ items (prose the seat reads). Exit 0 therefore means "a review of record exists on this head and names a reviewer", never "the review passed"; precondition ① of the landing check stays human.Before / after, per changed line, beside the ask it implements
Every edited line is ≤ 119 bytes (the ratchet's 120-byte cap); the three files stay at 812 / 60 / 151.
Ask 1 — name the review of record (
contract-review.md, twinned in SKILL.md and core-rules)references/contract-review.md— one line was freed inside the file so the shape could take two lines:get_reviews读空 ≠ 未复审。」 (118 B; absorbs old :23)get_reviews读空 ≠ 未复审。」 → retired (folded into :21 above); :24–:29 renumber by −1, so the dispatch's ":28" is now :27.os-dev-report恒不算。」 (118 B) + new :29 「- 同形 =## Contract review题头、所审 head sha 码段、①②③ 逐项、独立性对、PASS/FAIL 判词。」 (119 B)SKILL.md:641 before 「- 交付后复核由派发席席内完成:spec 席达档自审或派该档子任务,余席默认档自审加门禁。」 → after 「- 交付后复核由派发席席内完成:spec 席达档,余席默认档加门禁;记录 = 同形评论落 PR 或卡。」 (119 B)references/core-rules.md:123 before 「- 受管面 PR 留 draft 并向两个授权批准账户请审;无席内复核 PASS 的契约卡 ⛔ 禁止入队。」 → after 「- 受管面 PR 留 draft 并向两个授权批准账户请审;契约卡无同形复核记录 PASS ⛔ 禁止入队。」 (117 B)Ask 2 — clearing the carrier cites it
contract-review.md:38 before 「- 放行 = 清标即落地:PASS ⇒ 同席同笔剥双载体,清标同笔留 provenance 评论引该 PASS。」 → after 「- 清标即落地:PASS ⇒ 同席同笔剥双载体;凡清标同笔留 provenance 评论,引记录 id 与所判 head。」 (119 B) — every clear, PASS or FAIL (:20 already clears both on FAIL), names the record comment and the head it judged.contract-review.md:22 before 「- PASS + 无标 + head 未动 = 已清标不是被剥;head 后移或无结论才重挂。」 → after 「…;head 后移或无结论才重挂;清标缺引记录即半态。」 (117 B) — clearing without the citation is the half-state the sweep reads (H51/H53 are A timestamp a seat writes into GitHub must come from the clock read by the same act that writes it — make an estimated stamp unspellable (helper token and/or a report-only patrol row), after two recorded ~1h mis-estimates #17314's file and are not touched here).contract-review.md:43 before 「- 该命令 0 = 双肢一致且无放宽 tell,4 = 任一不成立,3 = 环境答不了;⛔ 3 不作干净。」 → after 「- 0 = 双肢一致、无放宽 tell、head 上有记录;4 = 任一不成立;3 = 环境答不了,⛔ 不作干净。」 (115 B) — the--paircontract now includes the record.SKILL.md:642 before 「- PASS ⇒ 同席剥标、ready、auto-merge;FAIL ⇒ 补丁轮;⛔ 免复核不放行。」 → after 「- PASS ⇒ 同席剥标并引记录、ready、auto-merge;FAIL ⇒ 补丁轮;⛔ 免复核不放行。」 (101 B)Ask 3 —
check-clause2-carriers --pairreads it (row C6)scripts/pm/check-clause2-carriers.mjs:needsRecordRead(pair)— owed by the COMPLETED state only (gateBindingStateunchanged: declaredyes, cleared on both carriers, head unmoved). A pending pair owes nothing yet; never-hung / half-bound / moved-after-clear stay C3's rows, so no fact is owned twice.reviewOfRecord(pair)— reads the PR's thread and the card's; the newest## Contract reviewcomment naming the current head (H51'sCONTRACT_REVIEW_HEADING_MARKER+contractReviewHeadMatch+latestMarkedComment, all imported fromcheck-half-states.mjs— no cycle: that file imports nothing from this one, verified by grep) that also carries aReviewed-by:line (C4's ownAUTHORSHIP_KEY_LINESregex, key presence only — the value is C4's row). States:not-owed/unreadable/absent/unsigned/found.c6NoReviewOfRecord(pair)— the FINDING row (absent, orunsignednaming the comment and the missing line);c6RecordNote(pair)— theC6-RECORDnote onfound, naming the comment id, thread and head span so the provenance comment can cite it.gather— a fourth pass buys the PR's own thread for completed pairs only, in BOTH modes, through the existingreadCardComments(a PR is an issue at/issues/N/comments), cached per PR; the offline document carries it in the samecommentsbag keyed by the PR number — no new field, no seventh reader method.pairUnjudged— an unread PR thread (or a head sha too short to match) on a completed pair is UNJUDGED (exit 2), never a missing record.renderPair— the success sentence is keyed by note CODE, not note count (the C6 note had otherwise borrowed the C2-SIBLING wording — caught by the on-time fixture run and fixed in the second commit); a found record is named in the sentence.os-dev-reportand the seat's headingless ACCEPT — the unsigned state, newest-governs, the check:react-declaration-parity 是唯一没接进任何 workflow 的源码审计门禁,且无 MANIFEST 时静默 skip 退出 0 —— 它现在永远不可能红 #4690 half, reporting order, and the offline bag), roster +1, floor 15 → 16; the [finding]check-clause2-carriers.mjs --pairanswers C3 / exit 4 on a LEGITIMATELY cleared clause-② pair — the completed state (declaration outlives the label) is indistinguishable from the fail-open it hunts #14155completedfixture now carries its head (9af92aa3) and its record on the PR thread, so 「the pair is CLEAN overall」 still holds and the landing check's ② still answers 0 after a legitimate clear.Hard-4, not advisory — the decision and why. The seat's reading was "advisory until the rule text has been live for a window"; the file's own exit table decides otherwise:
--pairis a predicate about THIS pair at its own landing moment, an adverse fact about it exits 4, and 「⛔ never 0-with-a-message: silence is what this whole file exists against」. C6 re-blocks no legal workflow — under the text the record precedes the clear, so a pair that followed it reads clean — and a pair cleared before the text landed owes exactly one comment (the review its seat already performed, written down) before--pairanswers 0. The sweep stays report-only (rows print, exit 0), so the board-wide transition costs nothing. A window would also be the staged option the decision frame rules out by default (「过渡也从紧 —— 创业阶段不渐进」).Offline runs on the final tree (
07887a781), the same document three ways (--pair 13864 --pair-json …):EXIT=0, stderr 「ℹ️ C6-RECORD — review of record on this head: PR thread, comment 3301 (…) is a## Contract reviewcomment naming9af92aa3and carrying aReviewed-by:line — cite it in the provenance comment beside the clear」, stdout 「✓ … both carriers agree, and a review of record names this head (the note above says which comment to cite; existence, not the verdict).」EXIT=4, 「✗ C6 — card The undeclared-field door sits in FRONT of the hooks, so a key a beforeInsert hook writes has no door at all — and the drivers then disagree (memory stores it, SQL throws a raw statement error) #13657 declaresClause-②: yes, its gate was bound and cleared on BOTH carriers, and its open PR Refuse an undeclared field a before-hook writes — the post-hook half of the declared-field door, one envelope on every driver #13864 still sits at the head that was cleared (9af92aa3de) -- and NO review of record exists on this head: 0 comment(s) on the PR thread and 1 on the card were read …」 then 「is NOT clause-② legible (exit 4)」.EXIT=2, 「UNJUDGED: PR Refuse an undeclared field a before-hook writes — the post-hook half of the declared-field door, one envelope on every driver #13864's comment thread (the review-of-record read) could not be read」.维护者速读(草稿)
改了什么 —— 三个协议文件各改几行、净零行:契约复核细则把「默认档车道的复核记录」定成一条评论(落 PR 或卡,形状 = 达档裁决同形去掉档位行),并要求每次清标的 provenance 评论引这条记录的 id 与所判 head;主文件与核心条款各改孪生行。
check-clause2-carriers --pair新增 C6 行:对已清标的条款②对子,读 PR 与卡两条线程找这条记录,没有就退出 4;找到就打印一条 NOTE 告诉席位该引哪条评论。为什么改 —— 总监席的漏网扫描在一个窗口里量到五个
Clause-②: yes合并没有任何复核记录,只有 dev 自己的报告。规则文本(本席上午落地的档位政策)说「车道席默认档自审加门禁就是复核记录」,却没说它住哪、长什么样,于是「清了标」和「没有审」在任何扫描里看起来一样,总监席的事后审计也没有可核对的对象。风险与代价(含回滚) —— 代价:每次清标多写一条评论(把已经做过的复核写下来)、
--pair对已清标对子多一次读;过渡期内已清标未落地的对子跑--pair会红一次,补一条记录即绿;本席自己现行的 ACCEPT 评论没带## Contract review题头,自下一次清标起须写成同形。风险:识别形状复用 H51 已量过的四种方言,不读裁决词、不读 ①②③;若某席写出第五种方言,C6 会报「无记录」(红而不是绿,fail-closed)。回滚:一次 revert,无发布物、无迁移。席位意见 ——
你要做的 —— 人工合并本 draft PR(受管面
.claude/**+scripts/pm/**,席位不翻 ready、不入队、不批准)。Acceptance notes
Gates (every command
dispatch-gates.mjs --commandsderived from the merge-base changeset, run on the final commit07887a781, exits captured before any pipe; the ledger is in the os-dev-report):pnpm check:pm-skill-ratchetexit 0 — 「✓ check-skill-line-ratchet: declared cross-file moves: 1, total ceilings down 9 lines.」 (812 / 60 / 151 at ceiling, headroom 0, none raised)pnpm check:skill-frame-syncexit 0 — 「✓ check-skill-frame-sync: 2 copies of the decision frame are structurally isomorphic across 2 files」; SKILL.md :734–:752 md522f2339f0acb64cdb50c7adc9db681c3unchangedpnpm check:skill-compatibilityexit 0 — 「✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 80 workspace packages」pnpm check:pm-skill-id-lintexit 0 — 「✓ check-skill-id-lint: 27 file(s) clean (pattern /#[0-9]{3,}/g).」 (no issue number, model name or date in any skill file)pnpm check:pm-governed-proseexit 0 — 「✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces … and claim no others.」pnpm check:nul-bytesexit 0 — 「check-nul-bytes: OK (scanned 8170 text file(s) -- 8170 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes).」pnpm check:pm-clause2-carriers(the self-test) exit 0 — 「✓ check-clause2-carriers self-test: 359 cases pass (… the review of record on the completed state with the two shapes that are not one …)」pnpm check:pm-dispatch-gatesexit 0 (710 s, detached +tail --pid) — 「✓ dispatch-gates self-test: 1674 cases pass.」pnpm check:pm-governed-mergesexit 0 — 「✓ check-governed-merges --self-test: 274 assertions …」 and the report-only sweepnode scripts/pm/check-governed-merges.mjs --test …exit 3 — 「⛔ GOVERNED — a human merge is the review record for this PR (governance: human merge IS the review record for governed surfaces — retire the per-PR ADR approval check, add a report-only post-merge audit #9495 regime). … .claude/** ×3」;scripts/pm/check-clause2-carriers.mjsreported as not on the registerpnpm --filter @objectstack/lint run check:doc-formula-expressionsfirst exit 3 PREREQUISITE NOT MET (@objectstack/formula/@objectstack/lintnot built — not a measurement); built both under the verify lock (「VERDICT command-exit 0 · held the lock 165s」) and re-ran: exit 0 — 「✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 440 files / 1374 TS blocks judged clean」--base origin/main+ self-test, ci-filter-parity, closing-keyword-parity, comment-mask-corpus, declaration-mirrors, scripts-symbol-anchors, self-test-wired, self-test-workflow-commands, whole-set-label-write, bare-root-worklist, governed-queue-guard, report-test-timings, agent-test-spelling, bash32-floor, changeset-gate-self-tests, cli-command-ids, cross-package-test-inputs, doc-authoring, driver-memory-census, entry-guard, parse-guard, pnpm-filter-targets, ratchet-remedy-authority, refd-timer-probe, watch-hint-literal) all exit 0dispatch-gates.mjs --ranreconciliation:Run reconciliation — 43 derived, 43 run, 0 NOT-MEASURED, 0 UNRUN.(recorded ascommand :: exit code, exits captured before any pipe; 43 derived, 43 run)--self-testabove; the one importer (scripts/check-changeset-no-major.mjs,readClause2Line) ran its self-test and its--base origin/mainrun green;lint.yml's step runs the self-test only, unchanged.Ceilings arithmetic:
contract-review.md60 → 60 (−1 old :23 folded into :21, −1 old :29 replaced, +2 new :28/:29);SKILL.md812 → 812 (two lines rewritten in place);core-rules.md151 → 151 (one line in place). Widest edited line 119 B against the 120-byte cap.Assumptions A–D, measured
contract-review.mdby folding the 39-byte :23 into :21 (118 B).--pairalready reads the PR thread; a new fetch class) — half false:--pairread the PR LISTING row, its labels, the card, the card's thread, both event streams, the head commit and (forno) the files — never the PR's own comment thread. The read is new, but it is the same endpoint the card thread uses (/issues/N/comments), so it goes through the existingreadCardCommentswith the PR number, bought once per completed pair in both modes and cached per PR. The offline document takes it in the samecommentsbag keyed by the PR number — no new field. An old fixture in the COMPLETED state that omits it now reads UNJUDGED (exit 2) rather than 0, by the file's check:react-declaration-parity 是唯一没接进任何 workflow 的源码审计门禁,且无 MANIFEST 时静默 skip 退出 0 —— 它现在永远不可能红 #4690 rule (a document can only make the file say less); every other state is unaffected. The in-file [finding]check-clause2-carriers.mjs --pairanswers C3 / exit 4 on a LEGITIMATELY cleared clause-② pair — the completed state (declaration outlives the label) is indistinguishable from the fail-open it hunts #14155 fixture gained its record.grepfor 复核记录 /Reviewed-by/ review of record inreferences/lanes/director.mdhits nothing; 职责一 :29 defers 归属与全链 to../contract-review.md.Declared deviations from the dispatch text: (1) C6 reads no verdict WORD — H51's heading + head-sha shape and the
Reviewed-by:key line instead (evidence above; the rule text still names the word for the seat); (2) hard-4 rather than advisory (reasoning above); (3) the live--pairrun is on this PR, whose card declaresClause-②: no— it exercises the read path and C5, not C6 (no completed-state pair was enumerated on the live board; a sweep costs the anonymous budget); the C6 reading is exercised by the three offline documents and 40 self-test cases; (4)contract-review.md:23–:29 renumber by −1.Out of scope, filed: #17346 — C4's
VERDICT:discriminator and session-onlyReviewed-by:grammar match none of the four 2026-09-09 verdicts (readVerdictAuthorship(body) === nullon each), so the independence carrier has no live population; C6 deliberately reads the key line only and is not blocked by it. Noted, not filed: the skills seat's own ACCEPT comments lack the heading — the rule text now names it, 承接者 = the skills seat at its next clearing.Changeset: none owed — nothing in any package's
files[]moves (.claude/**andscripts/pm/**are the fast lane);skip-changesetapplied by the dev per the standing contract. Governed: draft only, never ready / enqueued / auto-merged / approved by a seat.Generated by Claude Code
Generated by Claude Code