From c93bb8b3607195a232ae5ee2549f036b764179e2 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 18 Sep 2026 04:46:41 +0000 Subject: [PATCH 1/3] =?UTF-8?q?skills(pm-dispatch):=20key=20the=20clause-?= =?UTF-8?q?=E2=91=A1=20contract=20review=20by=20LANE=20again=20=E2=80=94?= =?UTF-8?q?=20spec=20and=20skills=20owe=20it=20on=20every=20round,=20other?= =?UTF-8?q?=20lanes=20owe=20none?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The maintainer's lane rule, restated on the card: the contract review at CONTRACT_REVIEW_TIER is owed in the spec and skills lanes only, on every delivered round (in-seat when the seat is served at that tier, otherwise by the at-tier review subagent the seat spawns — the 09-17 route stays); every other lane lands on the three pre-checks and the gates with no contract review, and a clause-② limb hit outside those lanes is lane routing (spec-lane work) rather than a self-review demand. When the subagent cannot start the review is unavailable: the PR stays draft, out of the queue, and the maintainer's own review is the only bypass. Net 0 lines per file (812 / 60 / 151). The one added SKILL.md line (the unavailable-tier state) is paid by retiring the default-tier clause-② FAIL rate line, whose population the rule empties. Claude-Session: https://claude.ai/code/session_01BTeBejoPUvRHN8WdAJC6oF Co-authored-by: Claude --- .claude/skills/pm-dispatch/SKILL.md | 12 ++++---- .../pm-dispatch/references/contract-review.md | 28 +++++++++---------- .../pm-dispatch/references/core-rules.md | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.claude/skills/pm-dispatch/SKILL.md b/.claude/skills/pm-dispatch/SKILL.md index 11826a29b29..2b06d444742 100644 --- a/.claude/skills/pm-dispatch/SKILL.md +++ b/.claude/skills/pm-dispatch/SKILL.md @@ -509,7 +509,7 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报 - 发布的 `skills/**` 整根随 `npx skills add` 发运,⛔ 无一行级豁免,逐行判机械不作数。 - 纯机械一行 PM 酌定可至下限档;降档施工的补偿控制 = 复核席跑契约复审档。 - 降档施工只经契约复审档复核到达维护者,⛔ 不新增标签不新增链。 -- 强制条款②:放宽接受集或扩大公开面的卡默认判断档施工;达档复核归派发席席内。 +- 强制条款②:放宽接受集或扩大公开面的卡默认判断档施工;命中即 spec 车道的活。 - 条款②判据即代裁的机械边界测试与 `references/lanes/spec.md` 席内分派判据,⛔ 不另抄。 - 负边界:运行时权限/安全行为变更不是条款②,归人工地板安全/权限边界类。 - 条款②只指已发布契约面,拉回已声明契约不触它;卡面复述仍是条款②。 @@ -519,7 +519,7 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报 - 机械放宽判别门禁落地前,入队前的席内契约复核是方向自述的补偿控制。 - 豁免够不到的地板只有维护者裁决能设。 - 席位档策略:skills 车道外的执行席与分诊席默认判断档会话。 -- 条款②复核按实测档:达档席内审;未达档席 ⛔ 不自审,起隔离达档子代理转录核档采信。 +- 条款②复核按车道:spec 与 skills 席达档席内审;未达档 ⛔ 不自审,起隔离达档子代理。 - 降档出口两条:额度耗尽豁免,与主动预降(余量吃紧可预先降档)。 - 额度耗尽豁免仅当契约复审档实测不可用才落默认判断档,⛔ 不再往下。 - 降档的档位与理由记入认领评论 Container & model 行;档位逐次派发显式传参,永不省略。 @@ -633,17 +633,18 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报 - 细则见 `references/landing-operations.md`,落地窗口查阅。 - 条款②入队闸门:翻 ready / 入队前先取 PR 实际 diff;diff 是事实,卡片语义是预测。 -- `--tier` 嫌疑行是提示非裁定;双肢命中任一 ⇒ 无席内条款②复核 PASS 在案 ⛔ 禁止入队。 +- `--tier` 嫌疑行是提示非裁定;双肢命中任一 ⇒ 无达档条款②复核 PASS 在案 ⛔ 禁止入队。 - 路径肢 = diff 触及契约面 `packages/spec/src/**`,含 error-code-ledger 与 `*.zod.ts` 契约 schema。 - 声明肢 = 认领评论声明 `Clause-②: yes`,与路径无关;错误的 `no` 是可审计的假申报。 -- 交付后复核归派发席:达档席内审,未达档循保险丝起子代理;记录 = 同形评论落 PR 或卡。 +- 交付后复核只 spec 与 skills 车道欠,每轮达档:席内审或起子代理;双肢命中即 spec 车道。 +- 子代理起不来 ⇒ 复核缺席,PR 留 draft 队列外等档;唯一旁路是维护者亲审,逐次为准。 - PASS ⇒ 同席剥标并引记录、ready、auto-merge;FAIL ⇒ 补丁轮;⛔ 免复核不放行。 - 真正设计分叉照旧进决策箱,席内复核 ⛔ 不替代维护者裁定。 - 外部评审链降为可选事后审计,非放行前提。 - `needs:contract-review`(恒英文)由席位同笔挂:PR 一现即挂 PR;报告先到则先挂卡。 - `Clause-②: yes` 认领同笔卡上挂标;开 PR `PM_SWEEP_REPO=仓 check-clause2-carriers --pair N` 0 才请审。 - 挂标后复核完成前短暂停靠;⛔ 不前瞻预挂。 -- 席内复核的适用面、载体纪律、资格与归属、降档保险丝见 `references/contract-review.md`。 +- 契约复核的适用面、载体纪律、资格与归属、降档保险丝见 `references/contract-review.md`。 - 碰生成物的 PR 入队前先同步 + 整体重生成:四步序 `bash scripts/pm/os-regen-merge.sh`。 - os-regen 的陷阱与锚点禁令见 landing-operations A。 - 跟到 MERGED 为止,入队后的看护归车道 PM 的落地窗口:每轮同时读队列分支与 `origin/main`。 @@ -669,7 +670,6 @@ PM 的工作是循环:选卡 → 认领 → 派发 → 收集 → 复核 → 报 - 每轮向维护者打中文轮次报告(chat 通道):issue → 判决 → PR 链接 → 备注的表。 - 报告加升级项、代裁清单(分诊)、awaiting a human merge 项、governed 合并审计清单。 -- 报告席记条款②默认档 FAIL 率入复审清单;超改制前达档史值 ⇒ 决策卡交维护者定回退。 - 审计清单实跑 `node scripts/pm/check-governed-merges.mjs --since <上轮>`,⛔ 不凭记忆汇总。 - 车道审计是早警;权威合并窗口与认定/回滚处置归总监席,见 `references/lanes/director.md`。 - 报告含 `UNRECOGNISED` 行:对本轮门禁日志 grep `UNRECOGNISED` 逐行照录,`NOT APPLICABLE` 行也在内。 diff --git a/.claude/skills/pm-dispatch/references/contract-review.md b/.claude/skills/pm-dispatch/references/contract-review.md index 42faa4dc40e..cd2524ee939 100644 --- a/.claude/skills/pm-dispatch/references/contract-review.md +++ b/.claude/skills/pm-dispatch/references/contract-review.md @@ -1,4 +1,4 @@ -# 契约复核细则(席内) +# 契约复核细则(按车道) 见 SKILL.md 〈入队与落地〉的条款②闸门;本文只放载体纪律、归属资格与降档保险丝。 @@ -6,12 +6,12 @@ - 内容肢及于 published `skills/**`:作可证伪的算子或契约语义主张的改动挂标走本复核。 - ⛔ 判据不是提到契约:纯算子清单、拼写、格式不触发。 -- `Clause-②: yes | no` 按设计临时:只定是否必过席内契约复核的保守方向,⛔ 非终审。 +- `Clause-②: yes | no` 按设计临时:只定是否必过达档契约复核的保守方向,⛔ 非终审。 - 删误拒的 `Clause-②: no` 附 `Contract-text:` 引已发布契约文本,双载体同载;缺引即缺申报。 -- 真闸门在 PR 或报告时点的席内复核;声明被复核推翻 ⛔ 不作席位过失。 -- 机械地板 claim 时可查树:新导出符号或已发布载荷上的新键恒 `yes`,锁席内契约复核。 +- 真闸门在 PR 或报告时点的达档复核;声明被复核推翻 ⛔ 不作席位过失。 +- 机械地板 claim 时可查树:新导出符号或已发布载荷上的新键恒 `yes`,锁达档契约复核。 - conformance 类 ⛔ 不机械化:填充已声明字段、在两个已发布码之间重选输入类都需判断。 -- claim 拿不准 ⇒ 按 `yes` 挂标走席内契约复核;⛔ 不建全量分类学与 claim 时决策程序。 +- claim 拿不准 ⇒ 按 `yes` 挂标走达档契约复核;⛔ 不建全量分类学与 claim 时决策程序。 - PR 与卡双载体同笔挂:PR 一存在即挂;报告先于 PR 到达则先挂卡侧,ACCEPT 时补齐 PR 侧。 - 同笔在卡上记一行条款②认定;停靠只防误入队,⛔ 无等外部席位的无限期状态。 - 前瞻的条款②事实住卡上裁决与分诊评论、`Clause-②` 申报和 `--tier` 输出。 @@ -20,16 +20,16 @@ - 重挂前先查裁决:闸门标签缺失 ⇒ 先 grep 卡评论找复审结论;`get_reviews` 读空 ≠ 未复审。 - PASS + 无标 + head 未动 = 已清标不是被剥;head 后移或无结论才重挂;清标缺引记录即半态。 -## 复核归属与资格(席内) +## 复核归属与资格(按车道) -- 归属该卡派发席,交付后收集复核当轮席内完成;借复核不移卡,新 spec 工作恒归 spec 席。 -- 按档位:达档席内审契约增量;未达档 ⛔ 不自审,走保险丝路;豁免仅独立性件与保险丝。 -- 复核记录 = 一条评论落 PR 或卡,达档与默认档同形;散文、dev 自评、`os-dev-report` 恒不算。 +- 归属派发席,交付后收集复核当轮完成;只 spec 与 skills 车道欠,新 spec 工作恒归 spec 席。 +- 按车道:spec 与 skills 席审契约增量;达档席内审,未达档 ⛔ 不自审,起达档子代理。 +- 复核记录 = 一条评论落 PR 或卡,席内与子代理同形;散文、dev 自评、`os-dev-report` 恒不算。 - 同形 = `## Contract review` 题头、所审 head sha 独占码段、①②③ 逐项、独立性对、PASS/FAIL。 - 同形含首行 `Served-tier:`:值写常量名 `CONTRACT_REVIEW_TIER`;无此行不成裁决,模板见 `--template`。 - ① derived judgments 逐项:diff 引出的接受集与公开面变化逐条点名判对错。 - ② semver 定级与 changeset 声明一致;③ 边界旗:dev 挂旗与 `open_questions` 逐旗答复或升级。 -- 独立性件:契约真分叉、dev 挂旗或派发后的跨车道面(含 spec)⇒ 起隔离的达档复核子代理。 +- 独立性件(契约真分叉、dev 挂旗)与保险丝只免席内审,不免复核:起隔离达档子代理。 - 只喂卡片、既有裁决与 PR 本体,⛔ 不喂派发令与派发席自己的结论;简报写成对抗性。 - 隔离复核子代理暂存全写按所审 PR 命名的 `/pr-/`,⛔ 不读非本轮自写的暂存。 - 独立性对(机读):`Implemented-by:` 写产 diff 者身份;`mode:subagent` 记分支,`mode:remote` 记 session id。 @@ -37,7 +37,7 @@ - 两者同 session ⇒ 报 SELF-REVIEW;只 `mode:remote` 可达,`mode:subagent` 席内审是设计;值紧跟冒号。 - 清标即落地:PASS ⇒ 同席同笔剥双载体;清标同笔落 PR provenance 评论,引记录 id 与所判 head。 - 轮次报告设复审清单专节,形状与代裁清单同为强制审计。 -- 落地前检三条:① 席内条款②复核 PASS 在案,即 PR 或卡上同形的复核记录(档位按实测)。 +- 落地前检三条:① 达档条款②复核 PASS 在案,即 PR 或卡上同形复核记录(spec、skills 每轮)。 - ② 双载体已清,逐对机读 `PM_SWEEP_REPO=仓 node scripts/pm/check-clause2-carriers.mjs --pair N`。 - 0 = 双肢一致、无放宽 tell、head 上有记录;4 = 任一不成立;3 = 环境答不了,⛔ 不作干净。 - 放宽 tell 由 `scripts/pm/check-widening-tells.mjs` 判,`no` 撞新键/成员/导出/登记即拒,附 file:line。 @@ -47,10 +47,10 @@ ## 降档保险丝(机读) -- 保险丝管每个出条款②裁决的席:每场前必读服役档(`platform-readings.md`),未达档 ⛔ 不自审。 +- 保险丝只管 spec 与 skills 席的条款②复核:每场前必读服役档(`platform-readings.md`)。 - 总监席裁决非达档裁决,⛔ 不受本丝;总监席档位由维护者逐场定。 -- ⛔ 自述档位与传参皆非读数;条款②的 `mode:subagent` 派发恒保留标至席内复核完成。 -- 读数不达档 ⇒ 改走转录核验的达档复核子代理;标签原样留置,队列外等待是安全态。 +- ⛔ 自述档位与传参皆非读数;条款②的 `mode:subagent` 派发恒保留标至达档复核完成。 +- 读数不达档 ⇒ 改走转录核验达档复核子代理;起不来即无复核,标签原样、队列外等档。 - 子代理档只取其转录 harness 逐请求 `model` 盖章;`get_session` 量的是派发会话,⛔ 不作互证。 - 清标前 `--pair`:`Served-tier:` ≠ 常量名 ⇒ exit 4,点名 PR、评论、读数;型号串按 `AGENTS.md` 拒。 - 施工档只取 harness `model` 盖章或认领 Container & model 行;`Co-Authored-By` = 署名常量 ⛔ 非证据。 diff --git a/.claude/skills/pm-dispatch/references/core-rules.md b/.claude/skills/pm-dispatch/references/core-rules.md index de1117229f6..5b9894d6987 100644 --- a/.claude/skills/pm-dispatch/references/core-rules.md +++ b/.claude/skills/pm-dispatch/references/core-rules.md @@ -109,7 +109,7 @@ - 认领原子对:一次标签写入完成认领与状态对调,随后留 `Claim:` 开头的评论并重读全线程。 - 更早的他会话认领即让行并交出已诊断的一切;认领逾一天且无合并证据即疑死。 - dev 自死不等于维护者中止,需显式信号;回收前先救工作树,有提交的活分支 ⛔ 永不回收。 -- 一单一次派发,档位逐卡显式传参;语义面卡恒契约复审档施工,契约卡达档复核归派发席。 +- 一单一次派发,档位逐卡显式传参;语义面卡恒契约复审档施工,契约复核只 spec、skills 欠。 - 派发词 ⛔ 不整段粘贴 issue 正文,只带增量,并要求子代理自查正文完整性。 - 派发词分三区:裁决不可重裁、机制假设须实测、建议路线可换,⛔ 不把假设写成裁决。 - 标准非协商条款 ⛔ 不抄进派发词,清单、路径与行号在派发那一刻从树上取。 From 5e1f09b129a4b1e03ea6810d16fe04f46bc616e2 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 18 Sep 2026 04:52:24 +0000 Subject: [PATCH 2/3] =?UTF-8?q?fix(pm):=20dispatch-gates=20names=20the=20L?= =?UTF-8?q?ANES=20that=20owe=20the=20clause-=E2=91=A1=20review,=20not=20a?= =?UTF-8?q?=20seat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The clause-② note and the suspect tail printed by `--tier` (quoted into claim comments) said "spec seat; default-tier build" and "in the spec seat" — the 2026-09-10 seat key, never re-keyed by the 09-16 tier PR. They now say what the charter says: the review is owed in the spec and skills lanes, in-seat at tier or by the at-tier subagent, and a contract-surface hit outside those lanes is spec-lane work that moves there. The docblock above MANDATORY_TIER_GLOBS carries the same rule; four self-test pins hold both renderings to the lane key and refuse the two retired spellings. Claude-Session: https://claude.ai/code/session_01BTeBejoPUvRHN8WdAJC6oF Co-authored-by: Claude --- scripts/pm/dispatch-gates.mjs | 48 +++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/scripts/pm/dispatch-gates.mjs b/scripts/pm/dispatch-gates.mjs index fae7aae37bc..483d9617525 100644 --- a/scripts/pm/dispatch-gates.mjs +++ b/scripts/pm/dispatch-gates.mjs @@ -11879,11 +11879,12 @@ export function residueLines( /** * The single source of truth for the model tier the PM lane's governance * reads — clause ②'s CONTRACT-REVIEW tier: the tier the clause-② REVIEW runs - * at, both halves of it — the spec seat's review of a card that changes - * contract accept/reject behaviour or widens the public surface, and the - * `needs:contract-review` re-review sub-round (its opening self-check reads - * this). The BUILD of such a card is at the default judgment tier, so this - * constant is a review tier and never a dispatch mandate. Declared HERE + * at, both halves of it — the spec and skills lanes' review of every round + * they deliver (a card that changes contract accept/reject behaviour or + * widens the public surface is spec-lane work, whichever seat found it), and + * the `needs:contract-review` re-review sub-round (its opening self-check + * reads this). The BUILD of such a card is at the default judgment tier, so + * this constant is a review tier and never a dispatch mandate. Declared HERE * and only here, as a constant, so a model upgrade is a one-line change in one * file — the clause-① mandate rows below read it, the self-test compares * against it, and the PM skill's prose names it, so the model id is spelled as @@ -11945,12 +11946,22 @@ export const CONTRACT_REVIEW_TIER = 'claude-fable-5-1'; * a file-surface predicate, and exactly what this script takes as argv; * - clause ②, NOT encoded and deliberately not: a card that changes contract * accept/reject behaviour or widens the public surface is built at the - * default tier and REVIEWED at `CONTRACT_REVIEW_TIER` — in the spec seat - * only, since the 2026-09-10 ruling; every other lane's clause-② review is - * that lane's own default-tier review plus the gates, and neither the - * triage seat nor the maintainer-summoned director spawns a - * contract-review-tier subagent for anything. That is judged from the - * card's CONTENT — what the change + * default tier and REVIEWED at `CONTRACT_REVIEW_TIER`. WHO owes that + * review is keyed by LANE — the maintainer's lane rule, keyed by seat on + * 2026-09-10, re-keyed by served tier on 2026-09-16 and restated as the + * lane rule on 2026-09-17 (「曾经要求只有 spec 和 skills 需要 fable,其他 + * opus 就够了,理论上其他车道不需要契约复审」): the spec and skills lanes + * owe it on every round they deliver — in-seat when the seat's served + * tier is that tier, otherwise by the at-tier review subagent the seat + * spawns (the fastest route, per the maintainer) — and every other lane + * owes NO contract review: its whole bar is the three landing pre-checks + * and the gates, ⛔ no default-tier "self-review" record is demanded of + * it and ⛔ no at-tier subagent is spawned from it (neither the triage + * seat nor the maintainer-summoned director spawns one for anything). A + * clause-② hit outside those two lanes is lane ROUTING, never a review + * demand on the lane that found it: the work is the spec lane's, + * whichever seat found it, and moves there. Clause ② itself is judged + * from the card's CONTENT — what the change * does to the contract — and a path cannot answer it. An ordinary-looking * surface (one package's source file) is the NORMAL shape of a clause-② * card. The closest a path can honestly get is SUSPICION: @@ -12141,8 +12152,9 @@ export function tierLines(result) { } const clause2 = ' Clause ② is NOT reachable from paths: a card that changes contract accept/reject behaviour or widens the public' + - ' surface owes a contract-review-tier REVIEW too (spec seat; default-tier build), judged from the card CONTENT.' + - ' This line is a FLOOR, never a clearance.'; + ' surface owes a contract-review-tier REVIEW too (owed in the spec and skills lanes, in-seat at tier or by the' + + ' at-tier subagent; default-tier build; a hit outside those lanes is spec-lane work and moves there), judged from' + + ' the card CONTENT. This line is a FLOOR, never a clearance.'; // The suspicion tail prints only on a hit — unlike the clause-② note above, // which prints always: "no suspicion" and "no suspect table" must not share a // spelling, and the note is what keeps silence from reading as a clearance. @@ -12151,7 +12163,7 @@ export function tierLines(result) { : [ ` Clause ② SUSPECT surface — a hint, not a verdict: judge the tier from the card CONTENT as best you can` + ` (a card changing contract accept/reject behaviour or widening the public surface is reviewed at ${CONTRACT_REVIEW_TIER}` + - ' in the spec seat, built at the default tier);' + + ' in the spec lane — a contract-surface hit is spec-lane work whichever seat found it — built at the default tier);' + ` whichever tier is dispatched, the PR's actual diff passes the clause-② enqueue gate before the card may enqueue.`, ...suspects.map((s) => ` - ${s.path} ⇢ '${s.glob}' — ${s.why}`), ]; @@ -24578,6 +24590,13 @@ function selfTest() { t('the no-mandate rendering claims no mandate', !plainLines.includes('MANDATORY')); t('the no-mandate rendering names the floor and the default, so the judgment call has its band', plainLines.includes(TIER_FLOOR) && plainLines.includes(TIER_DEFAULT)); t('BOTH renderings state that clause ② is out of reach of paths — a no-mandate line is not a clearance', plainLines.includes('Clause ②') && mandLines.includes('Clause ②')); + // The lane key (#18536): the maintainer's lane rule restated — the review is + // owed in the spec and skills lanes, in-seat at tier or by the at-tier + // subagent, and in no other lane; the 2026-09-10 SEAT key and the + // 2026-09-16 TIER key are both retired spellings and must not come back. + t('BOTH renderings key the clause-② review by LANE — the spec and skills lanes, in-seat at tier or by the at-tier subagent', [plainLines, mandLines].every((l) => l.includes('spec and skills lanes') && l.includes('at-tier subagent'))); + t('…and neither spells a retired key — no "spec seat" (2026-09-10) and no default-tier review or self-review (2026-09-16)', [plainLines, mandLines].every((l) => !l.includes('spec seat') && !l.includes('default-tier review') && !l.includes('self-review'))); + t('…and both say a clause-② hit outside those lanes is spec-lane work that MOVES there — lane routing, never a review demand on the lane that found it', [plainLines, mandLines].every((l) => l.includes('spec-lane work and moves there'))); t('the no-mandate rendering says how many globs it checked, so an empty table cannot read as a clearance', plainLines.includes(`${MANDATORY_TIER_GLOBS.length} declared glob`)); // Refusals: a contradiction is not printed, and an ambiguity is not guessed. let tierRefused = false; @@ -24645,6 +24664,7 @@ function selfTest() { t('the suspicion rendering sends the seat to the card CONTENT for the tier call', suspectRendered.includes('judge the tier from the card CONTENT')); t('the suspicion rendering routes EVERY dispatch through the enqueue gate on the ACTUAL diff', suspectRendered.includes('whichever tier is dispatched') && suspectRendered.includes('enqueue gate')); t('the suspicion rendering names the contract-review tier from its single-source constant', suspectRendered.includes(CONTRACT_REVIEW_TIER)); + t('the suspicion rendering keys the review by LANE — "in the spec lane", the work being the spec lane\'s whichever seat found it — never by seat (#18536)', suspectRendered.includes('in the spec lane') && suspectRendered.includes('whichever seat found it') && !suspectRendered.includes('spec seat')); const noSuspicion = fableOf(['packages/runtime/src/kernel.ts']); t('an ordinary non-contract surface raises no suspicion', noSuspicion.suspects.length === 0); t('no suspicion ⇒ no suspect line — absence and clearance must not share a spelling with a hit', !tierLines(noSuspicion).join('\n').includes('SUSPECT')); From bc0c2ec41e8c93f6ef1a9eefa33a72d393292264 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 18 Sep 2026 04:52:25 +0000 Subject: [PATCH 3/3] fix(pm): check-clause2-carriers keys the OWED review of record by lane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `needsRecordRead` — C6's population gate, and the sweep's read budget — owed a record only in the completed state (a cleared `Clause-②: yes`). Under the lane rule the spec and skills lanes owe the contract review on EVERY round they deliver, `no` included, and a `no` round hangs no carrier to mark its review pending: PRs #18530 / #18529 (spec-lane `no` rounds) read 0 here with no record on either head. The population now adds the `no` rounds of the two lanes, read off the card's `domain:*` labels (`LANES_OWING_REVIEW`, `laneOwesReview`; unreadable labels stay UNJUDGED). A `no` elsewhere still owes nothing. A cleared `yes` outside the two lanes keeps its row and its exit — the `yes` is a limb hit and limb-hit work is owed — but its remedy is lane routing (re-lane to spec, or correct a false `yes`), never a default-tier self-review and never an at-tier subagent from that lane. The C6-RECORD note prescribes the clear-citation only where a clear exists. New floored battery, 34 cases; roster floor 32 → 33. Claude-Session: https://claude.ai/code/session_01BTeBejoPUvRHN8WdAJC6oF Co-authored-by: Claude --- scripts/pm/check-clause2-carriers.mjs | 266 ++++++++++++++++++++++---- 1 file changed, 225 insertions(+), 41 deletions(-) diff --git a/scripts/pm/check-clause2-carriers.mjs b/scripts/pm/check-clause2-carriers.mjs index 3a270ef2eb5..3c32e631fcd 100644 --- a/scripts/pm/check-clause2-carriers.mjs +++ b/scripts/pm/check-clause2-carriers.mjs @@ -316,11 +316,18 @@ * PRINTS rather than going quiet, and why it is a fourth reading rather than a * silent pass. * - * ## C6 — a cleared gate with no review of record behind it (#17302) - * - * The tier policy names the lane seat's own default-tier review, plus the gates, - * as the review of record for every lane but spec and skills — and until #17302 - * nothing named WHERE that review lives or what it must contain. Measured on one + * ## C6 — a record owed on this head, and none behind it (#17302; lane-keyed by #18536) + * + * The lane rule (the maintainer's, restated on #18536 — 「曾经要求只有 spec 和 + * skills 需要 fable,其他 opus 就够了,理论上其他车道不需要契约复审」) owes the + * contract review at `CONTRACT_REVIEW_TIER` in the spec and skills lanes on + * EVERY delivered round, `Clause-②: yes` or `no`, and in no other lane: there + * the three landing pre-checks and the gates are the whole bar, ⛔ no + * default-tier "self-review" record is demanded and ⛔ no at-tier subagent is + * spawned. A `yes` outside those two lanes is a limb hit, and limb-hit work is + * the spec lane's whichever seat found it — it MOVES there rather than being + * reviewed where it sits. Until #17302 nothing named WHERE a review of record + * lives or what it must contain. Measured on one * window by the director's leak sweep: five `Clause-②: yes` merges whose * carriers were hung and cleared (or never hung) with NO review-like comment on * the PR or its card except the dev's own `os-dev-report`. Clearing the carrier @@ -329,12 +336,14 @@ * * `references/contract-review.md` now names the record: ONE comment on the PR * or its card, in the shape the tier verdict already has minus the tier line — - * 「复核记录 = 一条评论落 PR 或卡,达档与默认档同形」, 「同形 = `## Contract + * 「复核记录 = 一条评论落 PR 或卡,席内与子代理同形」, 「同形 = `## Contract * review` 题头、所审 head sha 独占码段、①②③ 逐项、独立性对、PASS/FAIL」 — and * makes every clear cite it (「凡清标同笔留 provenance 评论,引记录 id 与所判 * head」, 「清标缺引记录即半态」). C6 is the machine half of that sentence: on a * pair in the COMPLETED state (declared `yes`, cleared on both carriers, head - * unmoved — `gateBindingState`, unchanged) it reads the PR's thread and the + * unmoved — `gateBindingState`, unchanged) — and, since #18536, on a `Clause-②: + * no` pair whose CARD sits in a lane that owes the review on every round + * (`laneOwesReview`, read off the card's `domain:*` labels) — it reads the PR's thread and the * card's for a comment in H51's measured shape — a level-2 heading beginning * `## Contract review` and this head's sha as a code span, both IMPORTED from * `check-half-states.mjs` rather than restated — that also carries a @@ -622,8 +631,9 @@ * rendering an ADVERSE verdict as 0, and this reading is not one. * 2 also the answer when a C3 candidate's event stream or head commit could * not be read, when a `Clause-②: no` pair's changed-file listing could - * not be, or when a PR thread could not be — a COMPLETED pair's, which C6 - * owes (#17302), or, on the `--pair` path, ANY pair's, whose record C7 + * not be, or when a PR thread could not be — a COMPLETED pair's or a + * spec/skills-lane `no` pair's, which C6 owes (#17302, #18536), or, on + * the `--pair` path, ANY pair's, whose record C7 * judges (#18174): an unread * stream is not a never-hung gate, an unread diff is not a narrow one and * an unread thread is not a missing record, so all are UNJUDGED rather @@ -631,7 +641,10 @@ * 4 they do not — or, since #16448, the declaration reads `no` while the * diff carries a widening tell (row C5) — or, since #17302, the gate was * cleared on both carriers and no review of record names the head (row - * C6) — or, since #17915 and on every pair carrying a record since #18174, + * C6) — or, since #18536, the card sits in the spec or skills lane, the + * declaration reads `no`, and no review of record names the head (row C6 + * as well: the lane owes the record on every round) — or, since #17915 + * and on every pair carrying a record since #18174, * the record's `Served-tier:` line does not read at the declared tier (row * C7). One exit code with several * adverse reasons is the shape this table already had: the ROW says which, @@ -710,6 +723,33 @@ import { // tier and the served one differ unnoticed (#17915). import { CONTRACT_REVIEW_TIER } from './dispatch-gates.mjs'; +/** + * The lanes that OWE a review of record on EVERY round they deliver -- the + * maintainer's lane rule, restated on #18536 and carried into + * `references/contract-review.md` 「按车道」: the contract review at + * `CONTRACT_REVIEW_TIER` is owed in the spec and skills lanes, `Clause-②: yes` + * or `no`, and in no other lane. Read off the CARD's labels: `domain:*` is + * produced by triage and lives on the card, never on the PR. ⛔ Not a second + * statement of the policy -- the reference is the rule; this list is the one + * predicate `--pair` reads from it, and the self-test pins it at exactly two. + */ +export const LANES_OWING_REVIEW = Object.freeze(['domain:spec', 'domain:skills']); + +/** + * Does this pair's CARD sit in a lane that owes the review of record on every + * round? `null` when the card's labels could not be read -- already an UNJUDGED + * gap in `pairUnjudged`, so no reader here turns a missing read into 「not + * owed」. ⛔ Says nothing about a `yes`: a `Clause-②: yes` is a limb hit and is + * owed wherever it sits (limb-hit work is the spec lane's, whichever seat found + * it -- see `c6NoReviewOfRecord`); this predicate only widens the owed + * population to the `no` rounds of the two lanes. + */ +export function laneOwesReview(pair) { + const labels = pair?.cardLabels; + if (!Array.isArray(labels)) return null; + return labels.some((name) => LANES_OWING_REVIEW.includes(name)); +} + // -- Why this file no longer declares that it has NO path population (#17915) -- // // It carried the `no-path-population` marker until C7 landed, on the reading @@ -790,6 +830,7 @@ const SELF_TEST_BATTERIES = Object.freeze({ '#18683: the card-comment read pages to a cap — past 100 is UNJUDGED, ⛔ never a truncated pool': 27, '#18764: a DECORATED claim ENTERS the pool — ONE reading, and it is the sibling\'s': 24, '#18828: a SECOND `Claim:` by ONE seat — the writer-side prohibition, finally READ': 52, + '#18536: the lane-keyed owed population — spec and skills owe the record on EVERY round, other lanes owe none, a `yes` outside them is spec-lane work': 30, }); // DELETING an entry silences that battery's floor exactly as effectively as @@ -802,8 +843,8 @@ const SELF_TEST_BATTERIES = Object.freeze({ // one #18174 adds, and by the one #18141 adds, and by the one #17919 adds, and // by the one #16833 adds, and by the one #18456 adds, and by the one #18719 // adds, and by the one #18683 adds, and by the one #18764 adds, and by the one -// #18828 adds. -const SELF_TEST_BATTERY_FLOOR = 32; +// #18828 adds, and by the one #18536 adds. +const SELF_TEST_BATTERY_FLOOR = 33; // The key an assertion is filed under when no battery is open. It is not a // declared battery, so it reds by the same set difference rather than silently @@ -3414,16 +3455,28 @@ export function wideningUnjudged(pair, repo) { /** * Does this pair owe the review-of-record read -- its PR's own comment thread? * - * ⭐ ONLY the completed state: declared `yes`, the gate bound and cleared on - * both carriers, head unmoved since (`gateBindingState`, unchanged). That is the - * one state in which `references/contract-review.md` says a record must already - * exist -- 「复核记录 = 一条评论落 PR 或卡」, 「清标缺引记录即半态」 -- and it is + * ⭐ TWO populations, and only these. First, the completed state: declared + * `yes`, the gate bound and cleared on both carriers, head unmoved since + * (`gateBindingState`, unchanged). That is the state in which + * `references/contract-review.md` says a record must already exist -- + * 「复核记录 = 一条评论落 PR 或卡」, 「清标缺引记录即半态」 -- and it is * exactly the state the filing sweep measured five times over: `Clause-②: yes`, * carriers cleared, merged, and the only review-like comment anywhere the dev's * own report. A pair still carrying the gate owes nothing yet (the review is * pending, not missing); a never-hung, half-bound or moved-after-clear pair is * C3's row already, and two rows for one fact is the drift this file avoids. * + * ⭐ Second, since #18536: a `Clause-②: no` pair whose CARD sits in the spec or + * skills lane (`laneOwesReview`). The lane rule owes the review at tier on + * EVERY round those two lanes deliver, `yes` or `no` -- 「交付后复核只 spec 与 + * skills 车道欠,每轮达档」 -- and a `no` round hangs no carrier, so there is no + * label to mark its review "pending": the record either names the head or the + * pair is not landable (it stays draft and out of the queue, the charter's safe + * state). The measured pair is the card's own: PRs #18530 / #18529 (cards + * #18010 / #18301, `domain:spec`, `Clause-②: no`) read 0 here with no record on + * either head while the rule text owed one. A `no` outside those lanes still + * owes nothing -- 「余车道零契约复核」 -- and that half is pinned unmoved. + * * Exported and read by BOTH the fetch and the UNJUDGED accounting, the way * `needsGateHistory` and `needsWideningRead` are, so the set that owes the * thread and the set that gets one cannot drift apart. It reads the binding @@ -3438,7 +3491,9 @@ export function wideningUnjudged(pair, repo) { * `pairUnjudged` accounts for as against `locatedRecordUnjudged`. */ export function needsRecordRead(pair) { - return gateBindingState(pair).state === 'completed'; + if (gateBindingState(pair).state === 'completed') return true; + const d = cardDeclaration(pair?.cardComments ?? null); + return d.state === 'declared' && d.value === 'no' && laneOwesReview(pair) === true; } /** The `Reviewed-by:` key line, exactly as C4 reads it -- one spelling, not two. */ @@ -3954,11 +4009,12 @@ export function locateReviewOfRecord(pair) { * The review of record C6 judges -- the locator above, under C6's population. * * ⭐ ONE extra state, `not-owed`, and it is the whole difference: C6's row is a - * fact about a CLEARANCE (`needsRecordRead`'s completed state), so a pair that - * never hung the gate owes no record and is never refused for lacking one. - * That scope is the ruling's own and #18174 leaves it exactly where it was -- + * fact about a record OWED (`needsRecordRead`: the completed state, and since + * #18536 the `no` rounds of the spec and skills lanes), so a pair that owes + * none is never refused for lacking one. #18174 left the scope where it was -- * what that card moved is C7, which reads the locator directly because the fact - * IT judges belongs to the record rather than to the clear. + * IT judges belongs to the record rather than to the clear; #18536 widened the + * scope by lane, and the rows read the same one comment. * * ⛔ Both rows still read ONE comment, chosen once, by one recognition: this * function adds a gate in front of `locateReviewOfRecord` and changes nothing @@ -4032,32 +4088,52 @@ export function headSpanHoldsKey(pair) { } /** - * C6 -- a gate cleared on both carriers with no review of record on the head. - * - * The rule this row carries is the one #17302 landed: the default-tier lanes' - * review of record is ONE comment on the PR or its card, in the tier verdict's - * own shape minus the tier line, and every clear cites it. Before that text, - * clearing the carrier was indistinguishable from never reviewing -- measured - * five times in one window by the director's leak sweep -- and this file's own - * `--pair` read every one of those pairs as the completed state and answered 0. + * C6 -- a record owed on this head, and none behind it. + * + * The rule this row carries is the one #17302 landed and #18536 re-keyed by + * lane: the review of record is ONE comment on the PR or its card, in the tier + * verdict's own shape, and it is owed in the spec and skills lanes on every + * round they deliver -- a cleared `yes` cites it in the provenance comment + * beside the clear; a `no` round there owes it before the pair is landable. + * Before that text, clearing the carrier was indistinguishable from never + * reviewing -- measured five times in one window by the director's leak sweep + * -- and this file's own `--pair` read every one of those pairs as the + * completed state and answered 0; the lane half was measured on PRs #18530 / + * #18529, spec-lane `no` rounds that read 0 with no record on either head. + * + * ⭐ Three remedies, one row, chosen by where the pair SITS: a cleared `yes` + * inside the spec or skills lane writes the review it already performed down; + * a `no` round inside those lanes gets the review at tier (in-seat or by the + * at-tier subagent) before landing; a cleared `yes` OUTSIDE them is a limb hit + * on another lane's card, and the remedy is lane ROUTING -- the work is the + * spec lane's, whichever seat found it -- ⛔ never a default-tier self-review + * and ⛔ never an at-tier subagent spawned from that lane. The exit is the + * same 4 in all three: the pair is not landable as it stands. * * ⛔ A FINDING, and the file's exit table decides that rather than a preference: * the row is an adverse fact about THIS pair at its own landing moment, and an * adverse fact rendered as 0-with-a-message is the silence this file exists * against. It re-blocks no legal workflow -- under the text the record precedes - * the clear -- and a pair cleared before the text landed owes exactly one - * comment: the review its seat already performed, written down. + * the clear, and precedes the landing of a spec/skills `no` round -- and a pair + * cleared before the text landed owes exactly one comment: the review its seat + * already performed, written down. */ export function c6NoReviewOfRecord(pair) { const v = reviewOfRecord(pair); if (v.state === 'not-owed' || v.state === 'unreadable' || v.state === 'found') return null; const short = String(pair?.headSha ?? '').slice(0, 10); - const head = - `card #${pair?.card} declares \`Clause-②: yes\`, its gate was bound and cleared on BOTH carriers, and its ` + - `open PR #${pair?.pr}${pair?.draft ? ' (draft)' : ''} still sits at the head that was cleared (\`${short}\`)`; + const cleared = gateBindingState(pair).state === 'completed'; + const inLane = laneOwesReview(pair) === true; + const lanes = (Array.isArray(pair?.cardLabels) ? pair.cardLabels : []).filter((name) => LANES_OWING_REVIEW.includes(name)); + const draft = pair?.draft ? ' (draft)' : ''; + const head = cleared + ? `card #${pair?.card} declares \`Clause-②: yes\`, its gate was bound and cleared on BOTH carriers, and its ` + + `open PR #${pair?.pr}${draft} still sits at the head that was cleared (\`${short}\`)` + : `card #${pair?.card} declares \`Clause-②: no\` and carries ${lanes.map((l) => `\`${l}\``).join(', ')}, a lane that ` + + `owes the contract review on EVERY round it delivers, and its open PR #${pair?.pr}${draft} is at head \`${short}\``; const shape = - 'The record is the comment `references/contract-review.md` names -- 「复核记录 = 一条评论落 PR 或卡,达档与默认档' + + 'The record is the comment `references/contract-review.md` names -- 「复核记录 = 一条评论落 PR 或卡,席内与子代理' + '同形」 -- read here in H51\'s measured shape: a level-2 heading beginning `## Contract review`, this head\'s sha ' + 'as a code span of ITS OWN (「所审 head sha 独占码段」: a span carrying the key as well is not a sha and names no ' + 'head), and a `Reviewed-by:` line naming the reviewer. Existing tier verdicts already carry all three; a ' + @@ -4098,6 +4174,37 @@ export function c6NoReviewOfRecord(pair) { `${boundary} ${NEVER_WRITES}` ); } + if (!cleared) { + // #18536: a `no` round of the spec or skills lane. No carrier ever rode + // it, so nothing marks its review pending: the record either names the + // head or the pair is not landable. + return ( + `${read} Under the lane rule every round the spec and skills lanes deliver gets the contract review at the ` + + 'contract-review tier, `Clause-②: yes` or `no`, and until its record exists the PR is not landable: it stays ' + + `draft and out of the queue (the charter's safe state). ${shape} Remedy: the lane seat reviews at tier -- in-seat ` + + 'when its served tier is the constant, otherwise by the at-tier review subagent it spawns -- and posts the record ' + + 'on the PR or the card (`--template` prints it). When that subagent cannot start, the wait IS the state, and the ' + + `maintainer's own review is the only bypass, by their word each time. ${boundary} ${NEVER_WRITES}` + ); + } + if (!inLane) { + // #18536: a cleared `yes` on a card OUTSIDE the two lanes. The `yes` is a + // limb hit, and limb-hit work is the spec lane's whichever seat found it + // -- the remedy is routing, not a review from the lane that cleared it. + const labels = Array.isArray(pair?.cardLabels) ? pair.cardLabels.filter((name) => name.startsWith('domain:')) : []; + return ( + `${read} This is the shape the filing sweep measured five times in one window -- a cleared gate with nothing ` + + `behind it, indistinguishable from never reviewing -- and this pair's card sits OUTSIDE the spec and skills lanes ` + + `(${labels.length ? labels.map((l) => `\`${l}\``).join(', ') : 'no `domain:*` label'}), ` + + 'so a `Clause-②: yes` there is a limb hit: limb-hit work is the spec lane\'s, whichever seat found it, and the ' + + `clear this pair made stands on nothing this lane can produce. ${shape} Remedy -- lane ROUTING, ⛔ not a self-review: ` + + 're-lane the item to the spec lane (the card\'s `domain:*` becomes `domain:spec` through `pm:retriage`, or the ' + + 'contract work is split to a spec-lane card or PR -- 「新 `packages/spec` 工作恒由 `domain:spec` 席收口」) and let ' + + 'that lane\'s review at the contract-review tier produce the record; or, if the `yes` was a false declaration, ' + + 'correct it with a `Clause-②-correction:` comment on the card. ⛔ This lane neither writes a default-tier record nor ' + + `spawns the at-tier subagent. ${boundary} ${NEVER_WRITES}` + ); + } return ( `${read} This is the shape the filing sweep measured five times in one window -- a cleared gate ` + `with nothing behind it, indistinguishable from never reviewing. ${shape} Remedy: the owning seat writes down ` + @@ -4130,16 +4237,24 @@ export function c6NoReviewOfRecord(pair) { export function c6RecordNote(pair) { const v = locateReviewOfRecord(pair); if (v.state !== 'found') return null; + const cleared = gateBindingState(pair).state === 'completed'; + const owed = needsRecordRead(pair); + const inLane = laneOwesReview(pair) === true; return ( `review of record on this head: ${v.where} thread, ${v.id ? `comment ${v.id}` : 'a comment carrying no readable id'} ` + `(${v.at ?? 'undated'}) is a \`## Contract review\` comment naming \`${v.sha}\` and carrying a \`Reviewed-by:\` line -- ` + - (needsRecordRead(pair) + (cleared ? 'cite it in the provenance comment beside the clear (「凡清标同笔留 provenance 评论,引记录 id 与所判 head」). ' - : '⛔ This pair owes no clear, so nothing is prescribed here: the record is reported because it EXISTS on this head, and what it declares is judged wherever it exists. ') + + : owed + ? 'the lane rule owes this record on every round this lane delivers, `Clause-②: no` included, and it exists -- nothing else is prescribed here. ' + : '⛔ This pair owes no clear, so nothing is prescribed here: the record is reported because it EXISTS on this head, and what it declares is judged wherever it exists. ') + + (cleared && !inLane + ? '⚠️ This pair\'s card sits OUTSIDE the spec and skills lanes: under the lane rule a `Clause-②: yes` there is spec-lane work that moves there, so the seat landing this pair answers for which lane produced this record -- it is reported, not endorsed. ' + : '') + (servedTierStands(v.served) ? 'Its `Served-tier:` names the tier constant' + (v.served.stamps ? ` on a stamp control of ${v.served.stamps.atTier}/${v.served.stamps.total}` : '') + - (needsRecordRead(pair) + (cleared ? ', so the strip stands on C7 as well as on this row. ' : ', so it reads at tier on C7 as well as on this row. ') : 'Its `Served-tier:` does NOT stand — C7 says what it reads, and this pair is adverse. ') + @@ -5482,11 +5597,15 @@ async function gather(repo, prFilter = null, reader = NETWORK_READER, { landingR // it in the same `comments` bag keyed by the PR NUMBER and no reader grows a // seventh method. Cached per PR, so a two-card PR (#16304) pays once. // - // Two populations, one pass: + // Three populations, one pass: // · in BOTH modes, the COMPLETED pairs (#17302) -- the narrow window // between a clear and a landing, where a cleared gate with no record // behind it is precisely the board fact the filing sweep measured five // times over; + // · in BOTH modes, the `Clause-②: no` pairs whose card sits in the spec + // or skills lane (#18536, `needsRecordRead`'s second population) -- the + // lane rule owes the record on every round those lanes deliver, and a + // `no` round hangs no carrier that could mark its review pending; // · on the `--pair` path, EVERY pair (#18174) -- because what a record's // `Served-tier:` line declares is a fact about the record, judged on // whatever pair carries one, and the pair that carried the measured @@ -6489,7 +6608,7 @@ export async function selfTest() { const RECORD_SESSION = 'session_01489YWhZEoHT9oXshiyywQy'; // The review of record, in the shape measured on every 2026-09-09 specimen: // the `## Contract review` heading, the head as a code span, the independence - // pair -- the shape #17302 names for the default-tier lanes too. + // pair -- the shape #17302 names, and #18536 keys by lane. // // ⭐ The `Implemented-by:` value carries its token FIRST after the colon, and // that is load-bearing rather than tidy (#17346): this fixture is the pair @@ -7350,6 +7469,69 @@ export async function selfTest() { t('the locator and the gated reader choose ONE comment — same id, same head span, on the pair where both answer', JSON.stringify([locateReviewOfRecord(bothRead).id, locateReviewOfRecord(bothRead).sha]) === JSON.stringify([reviewOfRecord(bothRead).id, reviewOfRecord(bothRead).sha])); t('⛔ and off that population the gated reader still answers `not-owed` — C6\'s scope is unmoved by the split', reviewOfRecord(nonGated([MEASURED_RECORD])).state === 'not-owed' && locateReviewOfRecord(nonGated([MEASURED_RECORD])).state === 'found'); + // -- #18536: the lane-keyed owed population ----------------------------------- + // + // ★ The maintainer's lane rule, restated on #18536: the contract review at + // the contract-review tier is owed in the spec and skills lanes on EVERY + // delivered round, `yes` or `no`, and in no other lane. The measured pair is + // the card's own: PRs #18530 / #18529 (cards #18010 / #18301, `domain:spec`, + // `Clause-②: no`) read 0 here with no record on either head. What is pinned: + // the two-lane constant; the `no` rounds of those lanes now OWE the record + // (a row when absent, the note when found, UNJUDGED when unreadable); a `no` + // anywhere else still owes none; and a cleared `yes` outside the two lanes + // keeps its row and its exit while its remedy becomes lane ROUTING -- never + // a self-review, never an at-tier subagent spawned from that lane. + battery('#18536: the lane-keyed owed population — spec and skills owe the record on EVERY round, other lanes owe none, a `yes` outside them is spec-lane work'); + const SPEC = 'domain:spec'; + const SKILLS = 'domain:skills'; + const CLI = 'domain:cli'; + t('the owing lanes are exactly spec and skills — the maintainer\'s two, frozen', JSON.stringify(LANES_OWING_REVIEW) === JSON.stringify([SPEC, SKILLS]) && Object.isFrozen(LANES_OWING_REVIEW)); + t('a `domain:spec` card owes the review', laneOwesReview(pair({ cardLabels: [SPEC] })) === true); + t('a `domain:skills` card owes it too', laneOwesReview(pair({ cardLabels: [SKILLS, 'priority:p2'] })) === true); + t('⛔ a `domain:cli` card owes none — 「余车道零契约复核」', laneOwesReview(pair({ cardLabels: [CLI] })) === false); + t('⛔ a card with NO `domain:*` label owes none — the existing fixtures\' assumption, pinned', laneOwesReview(pair({ cardLabels: [] })) === false); + t('⛔ unreadable card labels answer null, never a lane — the labels gap is already UNJUDGED', laneOwesReview(pair({ cardLabels: null })) === null && says(pairUnjudged(pair({ cardLabels: null })), 'labels')); + // the `no` rounds of the two lanes: the measured pair, in fixture form + const laneNo = (labels, rows) => pair({ pr: 18530, card: 18010, draft: true, headSha: HEAD_9AF9, cardLabels: labels, cardComments: [CLAIM('Clause-②: no')], prComments: rows }); + t('⭐ THE MEASURED PAIR — a spec-lane `no` round OWES the review-of-record read', needsRecordRead(laneNo([SPEC], [])) === true); + t('…and a skills-lane `no` round owes it too', needsRecordRead(laneNo([SKILLS], [])) === true); + t('⛔ a cli-lane `no` round owes none — the population widened by lane, not to every `no`', needsRecordRead(laneNo([CLI], [])) === false && needsRecordRead(laneNo([], [])) === false); + const specNoRow = c6NoReviewOfRecord(laneNo([SPEC], [])); + t('⭐ a spec-lane `no` round with NO record on the head is a C6 row — where it answered 0', typeof specNoRow === 'string' && pairRows(laneNo([SPEC], [])).map((r) => r.code).join(',') === 'C6'); + t('…that names the declaration, the lane and the head, and says NO review of record', says(specNoRow, 'Clause-②: no') && says(specNoRow, SPEC) && says(specNoRow, HEAD_9AF9) && says(specNoRow, 'NO review of record')); + t('…and carries the lane rule — every round, `yes` or `no`, draft and out of the queue until the record exists', says(specNoRow, 'EVERY round') && says(specNoRow, '`Clause-②: yes` or `no`') && says(specNoRow, 'draft and out of the queue')); + t('…and the remedy is the lane\'s review at tier, in-seat or by the at-tier subagent, with the unavailable-tier state and its one bypass named', says(specNoRow, 'in-seat') && says(specNoRow, 'at-tier review subagent') && says(specNoRow, 'cannot start') && says(specNoRow, 'only bypass')); + t('…and it does NOT describe a clear this round never had', !says(specNoRow, 'bound and cleared') && !says(specNoRow, 'beside the clear')); + t('…while keeping the shape, the verdict-agnostic boundary and the never-writes clause', says(specNoRow, '## Contract review') && says(specNoRow, 'Reviewed-by:') && says(specNoRow, 'PASS half') && says(specNoRow, '自查放行')); + t('a skills-lane `no` round reads the same row', pairRows(laneNo([SKILLS], [])).map((r) => r.code).join(',') === 'C6' && says(c6NoReviewOfRecord(laneNo([SKILLS], [])), SKILLS)); + t('⛔ a cli-lane `no` round with no record is silent on every row and not UNJUDGED — nothing owed, nothing missing', pairRows(laneNo([CLI], [])).length === 0 && pairUnjudged(laneNo([CLI], [])) === null && locatedRecordUnjudged(laneNo([CLI], [])) === null); + // the record, found: the note, and nothing prescribed that a `no` round does not owe + const specNoFound = laneNo([SPEC], [RECORD_ON_9AF9]); + t('a spec-lane `no` round WITH its record is clean — no row, and the landing check answers 0', pairRows(specNoFound).length === 0 && pairUnjudged(specNoFound) === null); + const specNoNote = pairNotes(specNoFound); + t('…and prints the C6-RECORD note naming the comment', specNoNote.map((n) => n.code).join() === 'C6-RECORD' && says(specNoNote[0]?.text, 'comment 3301')); + t('…that says the LANE owes this record, `no` included, and prescribes no clear-citation this round has no clear for', says(specNoNote[0]?.text, 'every round this lane delivers') && says(specNoNote[0]?.text, '`Clause-②: no` included') && !says(specNoNote[0]?.text, '凡清标同笔留') && !says(specNoNote[0]?.text, 'owes no clear')); + t('…and reads at tier on C7 as well', says(specNoNote[0]?.text, 'reads at tier on C7')); + t('an UNSIGNED record on a spec-lane `no` round is C6\'s row, not C7\'s — one fact, one row', pairRows(laneNo([SPEC], [UNSIGNED_OFF_TIER])).map((r) => r.code).join(',') === 'C6'); + t('a below-tier record on a spec-lane `no` round is C7\'s row, not C6\'s — the record was found', pairRows(laneNo([SPEC], [SERVED(BELOW)])).map((r) => r.code).join(',') === 'C7'); + t('⇒ C6 and C7 can never both fire on the lane population either', [laneNo([SPEC], []), laneNo([SPEC], [RECORD_ON_9AF9]), laneNo([SPEC], [UNSIGNED_OFF_TIER]), laneNo([SPEC], [SERVED(BELOW)])].every((x) => pairRows(x).filter((r) => r.code === 'C6' || r.code === 'C7').length <= 1)); + // #4690: unread is never clean, and the gap is owned once + t('a spec-lane `no` round whose PR thread could not be read is UNJUDGED, never clean — and `pairUnjudged` owns that gap', c6NoReviewOfRecord(laneNo([SPEC], null)) === null && says(pairUnjudged(laneNo([SPEC], null)), 'review-of-record read') && locatedRecordUnjudged(laneNo([SPEC], null)) === null); + t('the sweep BUYS the thread for a spec-lane `no` round — the set that owes and the set that gets one read one predicate', needsRecordRead(laneNo([SPEC], [])) === true); + // the cleared `yes`, by lane: the row and its exit are unmoved; the remedy is not + t('a cleared `yes` INSIDE the spec lane is owed and, absent, is the row it always was — write the review down', needsRecordRead(bare({ cardLabels: [SPEC] })) === true && says(c6NoReviewOfRecord(bare({ cardLabels: [SPEC] })), 'writes down') && !says(c6NoReviewOfRecord(bare({ cardLabels: [SPEC] })), 'lane ROUTING')); + t('…and inside the skills lane likewise', says(c6NoReviewOfRecord(bare({ cardLabels: [SKILLS] })), 'writes down')); + const cliYesRow = c6NoReviewOfRecord(bare({ cardLabels: [CLI] })); + t('⭐ a cleared `yes` OUTSIDE the two lanes keeps its row and its exit — the `yes` is a limb hit and limb-hit work is owed', needsRecordRead(bare({ cardLabels: [CLI] })) === true && pairRows(bare({ cardLabels: [CLI] })).map((r) => r.code).join(',') === 'C6'); + t('…but its remedy is lane ROUTING, ⛔ not a self-review — re-lane to spec, or correct a false `yes`', says(cliYesRow, 'lane ROUTING') && says(cliYesRow, 'not a self-review') && says(cliYesRow, '`domain:spec`') && says(cliYesRow, 'Clause-②-correction:') && says(cliYesRow, 'whichever seat found it')); + t('…and it names the card\'s lane, refuses a default-tier record and refuses the at-tier subagent from that lane', says(cliYesRow, CLI) && says(cliYesRow, 'neither writes a default-tier record nor') && says(cliYesRow, 'spawns the at-tier subagent') && !says(cliYesRow, 'writes down the review it already performed')); + t('…and a card with NO `domain:*` label reads the same routing remedy, saying so', says(c6NoReviewOfRecord(bare({ cardLabels: [] })), 'no `domain:*` label') && says(c6NoReviewOfRecord(bare({ cardLabels: [] })), 'lane ROUTING')); + t('a cleared `yes` outside the lanes WITH a record found is clean, and the note reports the record without endorsing the lane', pairRows(bare({ cardLabels: [CLI], prComments: [RECORD_ON_9AF9] })).length === 0 && says(pairNotes(bare({ cardLabels: [CLI], prComments: [RECORD_ON_9AF9] }))[0]?.text, 'reported, not endorsed')); + t('…while the same record inside the spec lane is cited beside the clear with no such warning', says(pairNotes(bare({ cardLabels: [SPEC], prComments: [RECORD_ON_9AF9] }))[0]?.text, '引记录 id 与所判 head') && !says(pairNotes(bare({ cardLabels: [SPEC], prComments: [RECORD_ON_9AF9] }))[0]?.text, 'not endorsed')); + // the populations that did NOT move + t('⛔ a `yes` still carrying the gate in the spec lane owes nothing yet — the review is pending, not missing', needsRecordRead(pair({ prLabels: [L], cardLabels: [L, SPEC], cardComments: [CLAIM('Clause-②: yes')] })) === false); + t('⛔ a never-hung `yes` in the spec lane is C3\'s row, not C6\'s — no row owns a fact twice', needsRecordRead(declaredYes({ cardLabels: [SPEC], cardEvents: [], prEvents: [] })) === false); + battery('the exit register is distinct in every direction it must be'); const codes = [EXIT_OK, EXIT_USAGE, EXIT_INCOMPLETE, EXIT_PREREQUISITE_NOT_MET, EXIT_PAIR_ADVERSE]; t('every exit code is distinct — a verdict can never be read as an environment complaint', new Set(codes).size === codes.length, JSON.stringify(codes)); @@ -8707,7 +8889,9 @@ export async function selfTest() { + 'the sibling\'s one reading — the constant unwidened, and the file\'s two undecoration ' + 'paths pinned as the two jobs they are, the SECOND `Claim:` by one seat named as the state ' + 'the protocol forbids writing rather than ranked as a supersession — per direction, with a ' - + 'non-vacuity control each and the five measured instances replayed — and the exit register).', + + 'non-vacuity control each and the five measured instances replayed — the lane-keyed owed population, ' + + 'spec and skills owing the record on every round, other lanes owing none, a `yes` outside them routed to ' + + 'the spec lane rather than self-reviewed — and the exit register).', ); selfTestReachedVerdict = true;