Skip to content

pm-dispatch: make check-clause2-carriers C4 recognise the live contract-review verdict dialect, and name the session a reviewer writes - #17368

Draft
os-litant wants to merge 3 commits into
mainfrom
claude/issue-17346-c4-verdict-dialect
Draft

pm-dispatch: make check-clause2-carriers C4 recognise the live contract-review verdict dialect, and name the session a reviewer writes#17368
os-litant wants to merge 3 commits into
mainfrom
claude/issue-17346-c4-verdict-dialect

Conversation

@os-litant

@os-litant os-litant commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Fixes #17346

check-clause2-carriers row C4 — the independence carrier — discriminated "a contract-review verdict comment" with VERDICT_MARKER alone, measured on the 2026-09-01 board where a verdict opened a fenced VERDICT: PASS block. Every verdict written on the 2026-09-09 board uses the other dialect: a ## Contract review heading, the reviewed head as a code span, **Verdict: PASS WITH FINDINGS** in bold mixed case. C4 saw none of them, so it had no live population and --pair exit 0 said nothing about independence for any pair reviewed in the current dialect.

Probe — the four live comments the card names, before and after

Bodies read via repo-scoped REST on 2026-09-10 and judged offline with the file's own exported reader. BEFORE is readVerdictAuthorship(body) at e669e5ee; AFTER is readVerdictAuthorship(body, head) plus the C4 row on a pair carrying that comment.

comment PR / card author BEFORE AFTER (reader) AFTER (C4 row)
5597841101 #17073 / #16657 os-bill null malformed fires
5600239551 #17073 / #16657 os-sam null malformed fires
5600627944 #17116 / #16861 huangyiirene null malformed fires
5598904803 #17090 / #16335 huangyiirene null malformed fires

malformed is the correct reading, not a false positive: every one of the four writes its Reviewed-by: value as prose naming the reviewing MODEL, and none carries a session token. Two examples of the row's own detail text, verbatim from the run:

comment 5597841101
  `Implemented-by:` carries no readable identity — neither a session id nor a `claude/…` dev branch
     ("Implemented-by: branch `claude/issue-16657-raw-exec-operator-detail-cause`");
  `Reviewed-by:` carries no readable session ID
     ("Reviewed-by: director seat summon #20 (isolated fable subagent, transcript-verified before adoption)")

comment 5600239551
  `Reviewed-by:` carries no readable session ID
     ("- **Reviewed-by:** isolated review subagent [tier model named here], **transcript-verified**: 105 harness-stamped …")

The remedy is on the writing side, and the identity it needs already exists: specimen 5597841101 names session_01Tep4AYXZvyBA7jsvne5KZV in its own adoption sentence, one line above a Reviewed-by: line that names no session at all.

What changed, in three parts

1. Recognition — isVerdictComment, one shape shared with C6. A comment is a verdict if it carries the fenced VERDICT: marker (2026-09-01, kept) or H51's CONTRACT_REVIEW_HEADING_MARKER plus contractReviewHeadMatch against the pair's head. Both are IMPORTED from check-half-states.mjs, exactly as C6 imports them, so the two rows cannot disagree about what a verdict looks like. No regex for the verdict WORD in either dialect — the file's 自查放行 boundary is unmoved. The head is REQUIRED for the heading path, so a caller with no head in hand reads exactly the pre-#17346 behaviour rather than something looser.

2. Threads — measured, and a declared limit rather than a bought read. Zone 2 assumption A holds mechanically but its practical half is falsified: reusing C6's helpers is free, but a card-only C4 still fires on nothing. Measured 2026-09-10 over the three delivering cards:

card thread comments with a ## Contract review heading
#16657 16 0
#16861 3 0
#16335 15 0

All four live verdicts sit on the PR thread. C4 therefore judges verdictThreadRows(pair) — the card thread always, plus the PR thread when gather already holds it. Per pair state:

  • COMPLETED (needsRecordRead true, the pass C6 added): card thread + PR thread.
  • every other state: card thread alone — the same rows C2 already fetched.
  • PENDING pair, verdict on the PR thread only: invisible. Stated as a limit, ⛔ no fetch class added — that population is a pair whose gate is still hung, and the completed state re-reads it a moment later anyway.

3. Value decoration — a third gap the same corpus exposed. The key regexes tolerate **Implemented-by:** (bold wrapping the key and its colon), which is what every 2026-09-09 specimen writes. But the colon inside the bold leaves the captured value opening with the closing **, and the token regexes admitted a leading ** only when a backtick or the token followed with no space between. Measured:

"- **Implemented-by:** `claude/issue-x`"        key match: true  value rest: "** `claude/issue-x`"  branch: null
"- **`Implemented-by`**: `claude/issue-x`"      key match: true  value rest: " `claude/issue-x`"    branch: claude/issue-x

So a comment whose author had written a perfectly good identity read malformed — a false positive produced by the reader, and a different fact from the corpus's own prose values. VALUE_DECORATION now strips spaces, ** and backticks symmetrically. It strips decoration only, never a word: branch +token, the dev on claude/… and isolated +model+ subagent all still refuse.

Rulings held

  • Reviewed-by: still admits a session only (2026-09-02 reading a, 「同意」). ⛔ Not widened to prose, a branch or a model name. Admitting the prose would retire the reading outright: a value that names no identity compares to nothing, so the equality test that is the independence clause would answer about every pair the way it answers about none.
  • The equality rule is unchanged — same session on both lines ⇒ SELF-REVIEW.
  • Implemented-by: keeps both grammars (session id, or a mode:subagent dev's branch).
  • No model identifier is spelled anywhere in the diff: the tier constant keeps its single spelling in dispatch-gates.mjs, and the fixtures carry the SHAPE of a prose reviewer value, never the model name (maintainer, 2026-08-16: 「needs:fable-review 这个标签不好,下次模型升级怎么办」).

Zone 2 B — one direction falsified, and pinned

B says recognising more verdicts "can only turn a silent 0 into a 4, never a 4 into a 0". Newest-governs makes one narrow exception real: a newer INDEPENDENT verdict, previously invisible because it was in the heading dialect or on the PR thread, displaces an older card-thread self-review and the row clears. That is C4's own declared remedy arriving through a widened reading — the row's text already prescribes exactly it ("an independent re-review CLEARS this row rather than leaving the pair red forever"). It is documented on verdictAuthorship and pinned in both directions in the self-test rather than left to be discovered. The --pair exit table itself is untouched: malformed and self-review are still exit 4.

references/contract-review.md :35–:37 — per line, with byte counts

Net-zero: 60 lines before, 60 after. Ceiling 60, unchanged. Every line at or under the 120-byte cap.

:35 BEFORE [114 B] - 裁决载独立性对(机读):产出 diff 的身份写 `Implemented-by:`,出裁决的席位写 `Reviewed-by:`。
:35 AFTER  [120 B] - 独立性对(机读):`Implemented-by:` 写产 diff 者身份;`mode:subagent` 记分支,`mode:remote` 记 session id。

:36 BEFORE [117 B] - `mode:subagent` dev 记其分支 `claude/issue-…`(子代理无自有 session);`mode:remote` dev 记 session id。
:36 AFTER  [116 B] - `Reviewed-by:` 写渲染或采纳裁决的席位 session;隔离复核子代理无 session,记采纳它的席位。

:37 BEFORE [102 B] - 两者同 session ⇒ 报 SELF-REVIEW,⛔ 不作独立复核;两行皆无的历史裁决恒静默。
:37 AFTER  [117 B] - 两者同 session ⇒ 报 SELF-REVIEW;值紧跟冒号,前置词即不可读;两行皆无的历史裁决恒静默。

The layout moved to one key per line so the new fact fits without a new line: :35 now carries Implemented-by: and both dev grammars, :36 carries Reviewed-by: and the isolated-reviewer rule (the deliverable), :37 carries the comparison, the legacy silence and — newly — the placement rule the corpus fails 4 times out of 4 (值紧跟冒号,前置词即不可读).

Self-test roster delta

before after
C4 battery floor 52 89
total cases 390 396

+37 C4 cases, in five groups: the second dialect and its controls (a head is required; another head is not this one; a ### sub-heading is not the marker; the verdict WORD alone is still not a discriminator); the reviewer grammar held (bold **Reviewed-by:** + session ⇒ judged normally; prose ⇒ malformed, naming the missing session token and the writing-side remedy); the decoration asymmetry with its word-stripping controls; the thread set per pair state including the declared limit; and newest-governs across the two threads in both directions. Fixtures are the live bodies, trimmed to what the reader reads — one per dialect (adoption record with the heading on a later line; bold-bullet; verdict word bolded inside the heading) plus one written the way :36 now names.

In-surface bounded fix, declared: the C6 reference fixture RECORD wrote - **Implemented-by:** branch +token — a word before the token, which C4's grammar has always refused. It was invisible while C4 could neither see the heading dialect nor read the PR thread; with this change the reference pair reads malformed and the #14155 clean-specimen pin goes red. Corrected to put the token first, with a comment saying why and a new pin asserting the fixture is legal under both rows. The defective spelling is deliberately kept on the ADOPTION fixture, which is a live-shaped specimen. Same defect class, mechanical, same gate family, no other claim on the file.

Verification

Recorded in the report comment on #17346, with each exit code captured before any pipe.

Acceptance notes

  • readVerdictAuthorship gained an optional second parameter and cardVerdictAuthorship was renamed to verdictAuthorship (it never was card-specific, and it now reads both threads — a name that lies is the drift this file exists against). Grep confirms no caller outside this file.
  • Importing CONTRACT_REVIEW_TIER from dispatch-gates.mjs was tried and rejected: it makes check:pm-clause2-carriers name a path while its own no-path-population marker declares none, which reds a different case in the same self-test. The fixtures carry the shape instead.
  • Noted, not filed: GET /repos/{o}/{r}/issues/comments/5600627944 answers 404 twice while the same row is served fine by GET /repos/{o}/{r}/issues/17116/comments; a known-good control id on the same endpoint answers 200 in the same session. The card's stated probe recipe is not reproducible for that one row. A platform reading, not a repo defect, and references/platform-readings.md is outside this card's file surface. Successor: the next card that touches the REST comment-read channel.
  • Noted, not filed: 4 of 4 live specimens also write Implemented-by: with a word before the token (branch +token, the +seat+dev+session, backticked handle first). The reader is right and the corpus is wrong; :37 now states the placement rule, which is the whole remedy available inside this card's byte budget.

维护者速读(草稿)

改了什么 — 契约复核裁决的机读判别器只认 2026-09-01 那版写法(围栏块里一行大写 VERDICT:)。9 月 9 日起所有席位改用另一种写法(## Contract review 题头 + head 码段 + 加粗 **Verdict: …**),判别器一条都不认。本 PR 让 C4 同时认这两种写法(题头那半直接复用 C6 已导入的 H51 判据,不新写正则),并顺带修好一处读值缺陷:键名可以加粗、值却不能,导致写法完全正确的裁决也被判成残缺。参考文档 contract-review.md 三行原地改写,行数不变。

为什么改 — 改之前 C4 在真实看板上一条都没触发过:--pair 答 0 时,对「复核人是不是自己审自己」这件事什么都没说。四条真实裁决现在全部触发,读数是 malformed(裁决里没写复核席位的 session)——这是真实的载体缺陷,不是误报,补救在写的一侧,所以参考文档同轮点明该写谁的 session:渲染或采纳该裁决的席位自己的 session(隔离复核子代理没有 session,采纳它的席位有,采纳记录里本来就带着)。

风险与代价(含回滚) — 主要风险是判别面变宽后误伤历史裁决:两条防线未动 —— 两行皆无的老裁决恒静默(legacy),Reviewed-by: 仍只收 session、⛔ 没有放宽成散文。一处方向确实变了并已写明:更新的独立复核可以清掉更早的自审读数(那正是这行规则自己写的补救办法),自测双向钉住。改动只在一个门禁脚本和一份参考文档里,不动任何发布包;回滚 = revert 本 PR 的提交,门禁即回到今天的沉默状态。

席位意见 — (留空,待席位定稿)

你要做的 — 人工合并本 draft PR(.claude/** 属受管面,AI 席位不合并、不入队、不 approve)。

Generated by Claude Code


Generated by Claude Code

…review verdict dialect

C4 (the independence carrier) discriminated a verdict comment with
`VERDICT_MARKER` alone -- measured on the 2026-09-01 board, where a verdict
opened a fenced `VERDICT: PASS` block. Every verdict on the 2026-09-09 board is
written the other way: a `## Contract review` heading, the head as a code span,
`**Verdict: PASS WITH FINDINGS**` in bold. All four live specimens read `null`,
so C4 had no live population and `--pair` exit 0 said nothing about
independence for any pair reviewed in the current dialect.

Three halves, all measured offline against the live comment rows:

1. Recognition: `isVerdictComment` accepts EITHER the fenced marker OR H51's
   heading plus `contractReviewHeadMatch` against the pair's head -- both
   IMPORTED from `check-half-states.mjs`, the same two facts C6 already reuses,
   so the two rows cannot disagree about what a verdict looks like. No regex for
   the verdict WORD in either dialect.

2. Threads: C4 judges the card thread always and the PR thread when `gather`
   already holds it (COMPLETED pairs). Measured 2026-09-10: all four live
   verdicts sit on the PR thread and none of the three delivering cards carries
   a `## Contract review` heading at all, so a card-only C4 stays silent however
   good its discriminator is. A pending pair's PR-thread verdict is a declared
   limit, not a bought read.

3. Value decoration: the key regexes tolerate `**Implemented-by:**` -- the
   colon inside the bold -- but the value readers admitted a leading `**` only
   with no space after it, so `- **Implemented-by:** `+backticked token read as
   unreadable. Decoration is now stripped symmetrically; words are not, so
   `branch `+token and prose values stay refused.

`Reviewed-by:` still admits a session only (2026-09-02 reading a, unchanged).
The live prose values therefore read `malformed`, which is the true reading of a
verdict written without its reviewer's session; the remedy is on the writing
side, and `references/contract-review.md` :35-:37 now name it -- the seat that
renders or ADOPTS the verdict writes its own session, and an adoption record
already carries one.

Self-test: C4 battery 52 -> 89 cases (390 -> 396 total), fixtures taken from the
live bodies, one per dialect. The C6 reference record's `Implemented-by:` value
is corrected to put its token first after the colon: written `branch `+token it
reads `malformed` the moment C4 can see the dialect, which is a real carrier
defect and belongs on the defective specimen, never on the reference one.

Claude-Session: https://claude.ai/code/session_01YKEjmbYNvYWJvWGSWx26zK
Co-authored-by: Claude <noreply@anthropic.com>
@os-litant os-litant added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 10, 2026 — with Claude
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 10, 2026
…tures

`dispatch-gates --self-test` holds the tier constant's VALUE to exactly one
spelling under `.claude/skills/pm-dispatch` + `scripts/pm` -- the maintainer's
own rule, 「needs:fable-review 这个标签不好,下次模型升级怎么办」. The C4
fixtures added for the 2026-09-09 dialect quoted the model id out of the live
bodies (five sites), which reds that case.

The fixtures carry the SHAPE, not the id: a `Reviewed-by:` value that is prose
with no session token is what the reader is being pinned on, and the model name
is decoration. Importing the constant was tried and rejected -- it makes
`check:pm-clause2-carriers` name a path while its own marker declares
no-path-population, which reds a different case in the same self-test.

Claude-Session: https://claude.ai/code/session_01YKEjmbYNvYWJvWGSWx26zK
Co-authored-by: Claude <noreply@anthropic.com>

Copy link
Copy Markdown
Collaborator Author

维护者速读

改了什么 —— 一个 PM 门禁脚本(check-clause2-carriers.mjs 的 C4 行)与参考文档 contract-review.md 三行(原地改写,60 行不变)。C4 是「复核人是不是自己审自己」的机读判别器,原来只认 09-01 那种写法(围栏块里一行大写 VERDICT:);09-09 起所有席位改用 ## Contract review 题头 + head 码段的写法,判别器一条都不认。本 PR 让 C4 同时认两种写法,题头那半直接复用 C6 已导入的判据,不新写正则;并修好一处读值缺陷:键名可以加粗、值却不能,写法正确的裁决也被判残缺。参考文档同轮写明复核记录的 Reviewed-by: 该填谁的 session:渲染或采纳该裁决的席位自己的 session(隔离复核子代理没有 session,采纳它的席位有);值紧跟冒号。

为什么改 —— 改之前 C4 在真实看板上一条都没触发过:--pair 答 0 时对独立性什么都没说。改后四条真实裁决全部触发,读数都是 malformed(裁决里没写复核席位的 session)——这是席位写法的真实缺陷,不是误报,补救在写的一侧,参考文档同轮点明。09-02 的裁决(Reviewed-by: 只收 session)原样保留,没有放宽成散文。

风险与代价(含回滚) —— 判别面变宽后的误伤防线两条未动:两行皆无的历史裁决恒静默;Reviewed-by: 仍只收 session。「最新裁决为准」是原有规则,本 PR 只是让它跨 PR 线程与卡线程两边生效(自测双向钉住)。只改一个门禁脚本和一份参考文档,不动发布包;自测 359 → 396 例,CI 在 head 2afeff04 全绿;回滚 = revert,门禁回到今天的沉默状态。

席位意见 —— 通过。本席在契约复审档对照 diff 自读,并在 head 的独立检出上复跑:自测 396 例通过;对本 PR 的实况 --pair 退出 0;Reviewed-by: 的读法确实只认 session(新增用例钉住散文值仍被拒);参考文档三行 120 / 116 / 117 字节。dev 顺带量到:四条真实裁决的 Implemented-by: 也把值写在前置词后面,同属写法缺陷,参考文档第三行已写明「值紧跟冒号」。受管面(.claude/**):本席不翻 ready、不入队、不批准。

你要做的 —— 一个动作:人工合并本 draft PR。

skills 席,session session_01YKEjmbYNvYWJvWGSWx26zK,2026-09-10T10:35Z。


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation needs-user-decision size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants