fix(pm): say the head sha sits in a code span of its own, and name the refused spelling - #18270
Conversation
…he refused spelling `references/contract-review.md` :28 defined the record's shape as a head sha code span and never said the span holds the sha ALONE, so a seat reading it in good faith wrote the key and the sha into ONE span. A span is read as a sha only when it is hex and nothing else, so such a record names no head and C6 reads it exactly as a pair nobody reviewed. The prose now says the head sha 独占码段 (paid inside the line: the file stays at its 60-line ceiling, every touched line under 120 bytes), and `check-clause2-carriers.mjs` names the spelling where the absence is reported: a diagnosis only, read after the locator has already answered `absent`, so the accept set stays exactly one spelling and the locator's choice is unmoved. Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr Co-authored-by: Claude <noreply@anthropic.com>
Both held under an ablation that removed the diagnosis, because a comment count and a thread name survive it. They now read the sentence the branch composes, so the ablation moves them. Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Reviewing seat: ① Derived judgments
② Semver levelNot applicable — nothing published moves; ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
|
Landing provenance — skills seat, session Generated by Claude Code |
Fixes #18141
references/contract-review.md:28 defined the review of record's shape as 「所审 head sha 码段」 andnever said the span holds the sha ALONE. A seat reading it in good faith writes the key and the sha
into ONE span;
H51_SHA_SPANmatches a code span that is hex and nothing else, so such a recordnames no head and C6 reads 「no review of record on that head」 where a complete review exists.
Taken by the file's own 「先删容许出错的构造,再让正确形态成唯一拼写」 order: the prose names the one
correct spelling, and the reader keeps refusing the other while NAMING it. The accept set is
unchanged — a second accepted spelling would be the trap's twin.
What changed
.claude/skills/pm-dispatch/references/contract-review.md:28 — 「所审 head sha 码段」 becomes「所审 head sha 独占码段」, and the line sheds 「判词」 to pay for it. The file is 60 lines at its
60-line ceiling before and after; the touched line is 118 bytes (119 before).
check:pm-skill-ratchet:"contract-review.md is 60 lines (ceiling 60; headroom 0)".
scripts/pm/check-clause2-carriers.mjs—HEAD_KEY_IN_SPAN+headSpanHoldsKey(pair): a DIAGNOSIS, read only AFTER the locator hasalready answered
absent. It chooses no comment, admits none, and returns nothing for a commentthe locator can already read. The newest-of idiom is
latestMarkedComment, the same one thelocator resolves with — never a second one.
it」, and a pair whose heading comment wrote the head inside the key's span gets a row naming the
comment, quoting the span the seat actually wrote, and prescribing the fix (key outside the span,
sha in a span of its OWN,
--templateprints the whole record).a sentence this PR replaced.
The measurements this PR was dispatched to take
P1 — falsified in its live half; the mechanism half stands. The dispatch expected C6 to read
「no review of record」 for comment 5652813288 (PR #17986) today. Measured on the exact bytes (GET,
not edited) against this tree:
Its
Head-sha:span names nothing — the mechanism the card describes is real — but the record isstill FOUND, because its own prose quotes the head in a bare span of its own
("Cross-file staleness, searched at
db55ea6dd"). So the sha C6 reports for that record is read offthe prose and not off the line the seat wrote it on. Replayed end to end through the CLI
(
--pair 17986 --pair-json, verbatim bytes): no C6 row, the C6-RECORD note namingdb55ea6dd; exit 4comes from C4 (
Implemented-by: branch …, half written) and C7 (noServed-tier:line), both factsabout that record that predate this PR. The defect is the SPELLING, not that comment — the same
record trimmed to the spelling alone reads the refusal (below).
P2 — holds.
contractReviewRecordLinesprintsHead-sha:followed by the sha in a span of itsown, and the
--templatenote already says "7 to 40 hex in a span of ITS OWN; a span holding the keyas well is not a sha". The prose now agrees with it, and the self-test derives its refused fixture by
COLLAPSING the template's own line rather than retyping the key — a template that renamed the key
reds this battery instead of drifting past it.
P3 — the distinction was absent; it is the sentence that was added. Before this PR both cases
printed 「a cleared gate with nothing behind it, indistinguishable from never reviewing」. Pinned
three ways now: a bare-sha span record reads
found; a key-in-span record isabsentAND earns therefusal naming the spelling; a comment with no heading is the plain absence with no spelling
sentence.
P4 — holds, pinned.
locateReviewOfRecordchooses the same comment it chose before: a refusedspelling is never chosen over a correct record and never chosen at all (pinned in both arrival
orders, and the pair with a correct record earns no C6 row and no spelling sentence).
Reverse verification
const keyed = headSpanHoldsKey(pair);withconst keyed = null;turns 5 of 677 self-test casesred (
ABLATED EXIT=1). Mutated bloba3d4174bvs HEAD blobaf1a124a; after restore the blob isaf1a124aagain andgit diff HEADis empty. An earlier run of the same ablation moved only 3cases — two pins were reading a comment count and a thread name, which survive the ablation; both
were retied to the sentence the branch composes and are in the 5.
--pair 17986 --pair-json, the record trimmed to comment5652813288's spelling): exit 4, one row, C6, reading
「
… writes this head INSIDE one code span, as
Head-sha: db55ea6dde75d3e9f888d66cbad84c78c9006f0c」with the remedy naming the span of its own and
--template.--pair 18256still exits 0 with the C6-RECORD noteon comment 5674761187 (head
c96b507db288c20bf270c66c6137dc6fa7e79576).Gates
Derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, nopaths, reconciled with
--ran:pnpm --filter @objectstack/lint run check:doc-formula-expressionsfirst exited 3 (PREREQUISITENOT MET —
@objectstack/formulaand@objectstack/lintunbuilt). Built under the shared verify lockand re-run: exit 0.
pnpm check:pm-dispatch-gatesran to completion (exit 0), not cap-killed.pnpm check:pm-clause2-carriers: 677 cases pass.Lint, as a proved narrowing rather than a repo sweep:
pnpm lintiseslint . --no-inline-config;of this diff's two paths only
scripts/pm/check-clause2-carriers.mjsis inside eslint's ownpopulation — the
.mdcomes back "File ignored because no matching configuration was supplied".--format jsonreturns 2 entries, 1 linted, 0 errors, 0 warnings.eslint.config.mjsstates ofitself that it "never enables type-aware linting (no
parserOptions.project, no typed@typescript-eslintrules) for ANY file", so this diff cannot move the verdict of a file it does notcontain. No package typecheck is owed: the diff is one
.mjsunderscripts/and one.md.Union head: the readings above were taken at
c3533346.Deviation from the dispatch
The dispatch said the clause is "paid by density" at 60/60.
.claude/agents/os-dev.mdstates thatthe only legal currency for the line ratchet is DELETED CONTENT and that a re-wrap must never buy a
line for new content, so folding two clauses into one line to free a 61st was not available, and no
clause in this file is redundant enough to delete. The clause therefore lands INSIDE :28: the file
never grows, the ceiling row is untouched, and the payment is 「判词」, whose fact is carried by the
PASS/FAILtoken it stood behind. Flagged here rather than chosen silently.Acceptance notes
contractReviewHeadMatchscans the WHOLE comment, so the head it reports cancome from a span in the prose rather than from the record's own
Head-sha:line — which is howcomment 5652813288 reads
foundtoday despite the refused spelling. H51's declared shape is "thehead sha written as a code span somewhere in the comment", so this is declared behaviour, not a
contract violation; it does mean the trap is survivable for some records and not others. Successor:
whoever next touches H51's recognition shape.
Implemented-by: branch claude/…(C4 half-written) andno
Served-tier:line (C7). Both are already recorded on the card; a merged record is not edited.维护者速读(草稿)
改了什么 —— 契约复核记录的 head sha 从此必须单独占一个码段:
contract-review.md:28 的措辞改成「所审 head sha 独占码段」,并由同一行删去「判词」买单(文件仍是 60 行,不动天花板)。机读一侧,
check-clause2-carriers.mjs在判定「本 head 无复核记录」之后,额外说出为什么:如果有人把Head-sha:和 sha 写进同一个码段,这条 C6 行会点名那条评论、引用他写的码段,并给出一次就能改对的修法。为什么改 —— 旧措辞只说「head sha 码段」,照字面写就会落进读不出的拼写:一份完整的复核记录,机器读
起来和「根本没人复核」完全一样。先让正确形态成为唯一拼写,再让拒收带上理由。
风险与代价(含回滚) —— 受理集合没有变宽:被拒的拼写仍然被拒,定位器选哪条评论一字未动(两个到达
顺序都已钉住)。新增的只是一句诊断文案与 19 条自测。回滚 = revert 本 PR,无数据、无产物、无发布面。
席位意见 ——
你要做的 —— 这是
references/层受管面,按 Prime Directive #14 走席内契约档复核 → ready → 入队,不需要维护者逐条拍板;若对「删掉『判词』来买行」这笔密度支付有异议,请在此处说一句,我按你的说法改。
Generated by Claude Code