Skip to content

Commit d114d4c

Browse files
os-steveclaude
andauthored
fix(pm): C5 reports a widening tell instead of refusing on it (#19495)
Fixes #19490 ## What this changes `scripts/pm/check-clause2-carriers.mjs`'s **C5** limb turned a widening **tell** into a hard refusal: a card declaring `Clause-②: no` whose diff carried tells made `--pair N` exit 4, and PD #14 makes `--pair` at 0 a conjunct of the landing predicate. C5 is now **report-only** — the row still prints, with its `file:line` evidence and its remedy text, and it no longer contributes to a non-zero exit. **⛔ C5 and nothing else.** C6 stays a hard refusal, as do C2, C3, C8, C9 and the UNJUDGED exit-2 path. ## The ruling this stands on Maintainer ruling of 2026-09-21, recorded at #18917 (comment). Quoted verbatim, untranslated, because paraphrasing a ruling rewrites it: > 阻碍我的pr落地,导致 agent 开发满就是负面因素,哪怕挡住几个bug,但是出现bug也是可以重新修改的。 The operative distinction that record draws, and which the code now carries in its own words (`pairReportRows`'s docblock): > A limb that judges 「is this diff widening a contract」 — which `check-widening-tells` itself says it cannot prove (its header: 「a tell, never a proof」, 「cannot tell an array element from a call argument」) — does not hold a hard gate. A limb that asks 「does a review of record exist」 does. ## The mechanism - `pairReportRows(pair, repo)` is new and is **where the demotion is**: the C5 row is built there instead of being pushed into `rows`, and `rows.length === 0` is the exit-0 condition. A row that is not in that list cannot refuse. - `renderPair` is split into the pure **`pairRendering`** (every line, its stream, and the exit, computed before a byte is printed) and a printer. That split is what lets the self-test pin what a run **prints** beside what it **exits** — "the row still prints" and "the exit is 0" are two claims, and a case pinning only the second stays green over a row that has gone silent. - The C5 row's text gains `C5_REPORT_ONLY_DISPOSITION`: it says the row is report-only, that the at-tier contract review is what rules on the tell, and ⛔ that report-only is **not** a clearance and **not** a verdict that the tell is false. `REFUSAL_SENTENCE`'s remedy is carried verbatim, unchanged. - The report row prints under `⚑`, never `✗` — a refusal marker beside an exit of 0 is the exit register's banned "0-with-a-message", inverted. - `greenPairLine` gains a `wideningReported` branch, so an exit-0 line on a pair that carries tells says so instead of going quiet. Without it a 0 would read as "narrow", which is the silence this file exists against. - The report and its `file:line` list print on **every** exit this path can answer — including the exit-2 gap path, where the tell would otherwise be lost. ## Measured, before and after Exit codes captured BEFORE any pipe. | run | before | after | | --- | --- | --- | | `--pair 19314` | **exit 4**, sole adverse row `✗ C5`, 7 tells | **exit 0**, row `⚑ C5`, the same 7 tells | | `--pair 19438` | **exit 4**, row `✗ C6` | **exit 4**, row `✗ C6` — untouched | Both halves of requirement 1 verified: 19314 reaches 0 **because C5 no longer refuses**, not because any tell disappeared. `grep -c 'T2 packages/spec/src/stack.zod.ts'` reads **7** on the before log and **7** on the after log — `stack.zod.ts:3412` through `:3418`, each with its `T2` explanation and its `+` source line, in both. The after run's exit-0 line says so itself, rather than reading clean: > ⚠️ Its diff DOES carry widening tell(s), printed in full above with their file:line evidence: since the maintainer ruling of 2026-09-21 row C5 is REPORT-ONLY and moves no exit code, so this 0 says the clause-② limbs are LEGIBLE and ⛔ does NOT say the diff is narrow. The at-tier contract review is what rules on those tells. ## Pins, and the ablation for each A new self-test battery, `⭐ the 2026-09-21 ruling: C5 REPORTS its tell, C6 still REFUSES`, 24 cases, declared in `SELF_TEST_BATTERIES` at its measured floor. Self-test: **1075 → 1099 cases, exit 0**. Six ablations, each through `scripts/ablation-replace.mjs` so the mutation's landing is the tool's own verdict (anchor count 1 to 0, blob hash before and after) and the restore is proved by `blob == HEAD` plus an empty `git diff HEAD`: | # | ablation | red cases | what it proves is not vacuous | | --- | --- | --- | --- | | 1 | put C5 back into `rows` | 6 | the exit-0 half: "C5 present reaches 0" | | 2 | delete the `printReports` body | 9 | the printed half: row, `file:line`, evidence list, remedy, disposition, marker | | 3 | delete `greenPairLine`'s `wideningReported` branch | 1 | the exit-0 line says the diff carries tells | | 4 | delete the `C6` row push in `pairRows` | 14 | C6 still refuses, and the mixed case's 4 is C6's | | 5 | make `pairReportRows` return `[]` | 8 | the report exists at all, including the structural case | | 6 | make `wideningUnjudged` return `null` | 4 | the UNJUDGED exit-2 path is untouched | Every ablation restored byte-identically before the next; `git diff HEAD` empty and `git status --porcelain` clean after each. The two `⛔ CONTROL` cases on the clean-diff pair stay green under all six by design — they are the non-vacuity bracket for the reported/clean pair of readings, not pins on code. ## Gates `node scripts/pm/check-governed-merges.mjs --test scripts/pm/check-clause2-carriers.mjs` → **exit 0, NOT governed** — ordinary queue landing applies to a PR with exactly this file list. Size: 292 changed lines (+260 / -32), under the 5000-line human-merge threshold. Every command's exit code captured BEFORE any pipe: - `node scripts/pm/check-clause2-carriers.mjs --self-test` → 0 (1099 cases) - `node --check scripts/pm/check-clause2-carriers.mjs` → 0 - `pnpm exec eslint scripts/pm/check-clause2-carriers.mjs` → 0 - `node scripts/check-self-test-wired.mjs` → 0 - `node scripts/check-scripts-symbol-anchors.mjs` → 0 - `node scripts/pm/check-governed-merges.mjs --test` → 0 - plus the full family list derived by `node scripts/pm/dispatch-gates.mjs --commands` (35 commands, derived from the merge base, three-dot) — all 0. ## 维护者速读(草稿) **改了什么** — 把全仓落地谓词里的 C5 一肢从「拒绝」降为「只报告」。一张卡声明 `Clause-②: no`、而 diff 带了扩面迹象时,这条行照旧打印,连同它的 `file:line` 证据和补救文字;但它不再让 `--pair` 返回非零。C6(本轮是否留下达档复核记录)以及 C2/C3/C8/C9、UNJUDGED 的 exit 2 一律原样不动。 **为什么改** — 2026-09-21 的裁决:挡住 PR 落地、让开发 agent 排满,本身就是负面因素,哪怕代价是漏几个 bug,因为 bug 还能再改。裁决给出的分界是问题的**种类**而非严重程度:判断「这个 diff 是不是在扩接口」的肢,其工具自己写着「只是迹象,不是证明」「分不清数组元素和调用实参」,就不该持硬闸;问「有没有一条复核记录」的肢可以。现场证据:`check-widening-tells.mjs` 14 天改了 18 次,挂着 5 张缺陷卡且**全部是误报**;PR #19314 全绿、达档复核 PASS 已判定它那 7 条迹象**全部为假**,仍被这 7 条卡了 12 小时。 **风险与代价(含回滚)** — 代价是真实的:一个确实扩了接口却声明 `no` 的 PR,机器不再拦它,改由达档复核去判——这正是裁决接受的那笔交易。风险被三处收窄:行照打不误、证据照列、exit-0 那行自己写明「本 0 不代表 diff 是窄的」。回滚成本一行:把 `pairRendering` 里的 `const reports = pairReportRows(pair, repo)` 改回推进 `rows`,6 条用例会立刻转红提示。本 PR 保持 draft,不合并、不入队、不动标签,等维护者看过。 **席位意见** — **你要做的** — 读一眼上面的分界是否就是你的本意(C5 报告、C6 仍拒);同意就把这个 PR 标 ready 并走队列。合并后 `--pair 19314` 立刻读 0,那张被挡 12 小时的 PR 就能合法落地,不需要任何人自查放行。 ## Acceptance notes - **No card existed for this when the work started; this session created #19490 itself.** The brief that dispatched it predicted issue creation would be refused. It was not: `POST /repos/objectstack-ai/objectstack/issues` returned 201. The branch therefore carries a real `issue-NNNNN` segment and `CLAIM_BRANCH_SHAPE` is satisfied — the predicted exit-2 UNJUDGED consequence does not apply. - **`--pair` on THIS PR is adverse on C2, and deliberately so.** Card #19490 carries no `Claim:` comment, because writing one is the owning seat's act and not a dispatched executor's. A seat that wants that reading to clear posts the claim naming this branch. `scripts/pm/**` is not a governed surface, so PD #14's `--pair`-at-0 conjunct does not gate this PR's landing either way. - No labels were added or removed, per the brief. `scripts/pm/**` is on the changeset fast track (not published), so `skip-changeset` applies on the merits; this PR does not hang that label. - The demotion broke **no existing self-test case**: the full suite was green on the edited file before a single new case was added. The old C5-refuses behaviour was pinned nowhere at the rendering level, which is itself worth knowing about this file. - `check-widening-tells.mjs`, `check-half-states.mjs`, `check-governed-merges.mjs`, `AGENTS.md` and all skill text are untouched. The tell is not the defect being fixed here — its force is. --- _Generated by [Claude Code](https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 9dd9319 commit d114d4c

1 file changed

Lines changed: 260 additions & 32 deletions

File tree

0 commit comments

Comments
 (0)