Skip to content

fix(pm): say the head sha sits in a code span of its own, and name the refused spelling - #18270

Merged
claude[bot] merged 3 commits into
mainfrom
claude/issue-18141-head-sha-span-holds-the-sha-alone
Sep 15, 2026
Merged

claude[bot] merged 3 commits into
mainfrom
claude/issue-18141-head-sha-span-holds-the-sha-alone

Conversation

@claude

@claude claude Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Fixes #18141

references/contract-review.md :28 defined the review of record's shape as 「所审 head sha 码段」 and
never 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_SPAN matches a code span that is hex and nothing else, so such a record
names 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 has
      already answered absent. It chooses no comment, admits none, and returns nothing for a comment
      the locator can already read. The newest-of idiom is latestMarkedComment, the same one the
      locator resolves with — never a second one.
    • C6's absent row is now two sentences: the empty case keeps 「a cleared gate with nothing behind
      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, --template prints the whole record).
    • The shared shape sentence now names the one spelling on both branches.
    • The docblock quotation of the rule line was updated in the same edit, so the file does not quote
      a sentence this PR replaced.
    • 19 self-test cases in their own battery (658 before, 677 after; roster floor 23, now 24).

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:

contractReviewHeadMatch(body, head)  =  "db55ea6dd"
hex-only spans in the body: 884e8347d, fc28c1d38, ..., db55ea6dd, 8cdd696, 53ded82bf7a494f54e344e19099dbf00854b8694
spans that prefix the head:  db55ea6dd
key-in-span line ALONE:      null
locateReviewOfRecord:        { state: "found", id: 5652813288, sha: "db55ea6dd" }

Its Head-sha: span names nothing — the mechanism the card describes is real — but the record is
still 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 off
the 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 naming db55ea6dd; exit 4
comes from C4 (Implemented-by: branch …, half written) and C7 (no Served-tier: line), both facts
about 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. contractReviewRecordLines prints Head-sha: followed by the sha in a span of its
own, and the --template note already says "7 to 40 hex in a span of ITS OWN; a span holding the key
as 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 is absent AND earns the
refusal naming the spelling; a comment with no heading is the plain absence with no spelling
sentence.

P4 — holds, pinned. locateReviewOfRecord chooses the same comment it chose before: a refused
spelling 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

  • Ablation (fix committed first, mutation proved on disk, restored byte-identical): replacing
    const keyed = headSpanHoldsKey(pair); with const keyed = null; turns 5 of 677 self-test cases
    red (ABLATED EXIT=1). Mutated blob a3d4174b vs HEAD blob af1a124a; after restore the blob is
    af1a124a again and git diff HEAD is empty. An earlier run of the same ablation moved only 3
    cases — 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.
  • Offline replay of the refused spelling (--pair 17986 --pair-json, the record trimmed to comment
    5652813288's spelling): exit 4, one row, C6, reading
    ⚠️ The SPELLING is why, and this pair is NOT the empty case: the PR thread's comment 5652813288
    … writes this head INSIDE one code span, as Head-sha: db55ea6dde75d3e9f888d66cbad84c78c9006f0c
    with the remedy naming the span of its own and --template.
  • Live control, a pair carrying a correct record: --pair 18256 still exits 0 with the C6-RECORD note
    on comment 5674761187 (head c96b507db288c20bf270c66c6137dc6fa7e79576).

Gates

Derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no
paths, reconciled with --ran:

Run reconciliation — 42 derived, 42 run, 0 NOT-MEASURED, 0 UNRUN.
EXIT CODES — all 42 accounted famil(ies) carry one, so the NOT-MEASURED count above is DERIVED from them.

pnpm --filter @objectstack/lint run check:doc-formula-expressions first exited 3 (PREREQUISITE
NOT MET — @objectstack/formula and @objectstack/lint unbuilt). Built under the shared verify lock
and re-run: exit 0. pnpm check:pm-dispatch-gates ran 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 lint is eslint . --no-inline-config;
of this diff's two paths only scripts/pm/check-clause2-carriers.mjs is inside eslint's own
population — the .md comes back "File ignored because no matching configuration was supplied".
--format json returns 2 entries, 1 linted, 0 errors, 0 warnings. eslint.config.mjs states of
itself that it "never enables type-aware linting (no parserOptions.project, no typed
@typescript-eslint rules) for ANY file", so this diff cannot move the verdict of a file it does not
contain. No package typecheck is owed: the diff is one .mjs under scripts/ 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.md states that
the 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/FAIL token it stood behind. Flagged here rather than chosen silently.

Acceptance notes

  • noted, not filed: contractReviewHeadMatch scans the WHOLE comment, so the head it reports can
    come from a span in the prose rather than from the record's own Head-sha: line — which is how
    comment 5652813288 reads found today despite the refused spelling. H51's declared shape is "the
    head 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.
  • noted, not filed: that same record carries Implemented-by: branch claude/… (C4 half-written) and
    no 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

…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>
@claude

claude Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: c35333460e21f1610985d38c323c358136e28219

Reviewing seat: domain:skills, in-seat review at the contract-review tier — get_session read at 2026-09-15T04:30Z: configured_model = session_context.model = last_served_model, the constant's tier, no fallback notice this round. Card #18141, claim 5674974256, report 5675465923; the PR declares Clause-②: no and the card's claim declares the same.

① Derived judgments

  • Accept set / public surface: none moves — .claude/skills/pm-dispatch/references/contract-review.md (+1/−1, one line) and scripts/pm/check-clause2-carriers.mjs (+129/−6) against merge-base 917b87ef; no origin/main commit since that base touches either file; references tier + repo-root PM gate, nothing published; skip-changeset on the PR (read back with documentation, size/m).
  • The clause lands INSIDE :28 — 「所审 head sha 码段」 → 「所审 head sha 独占码段」, paid in the same line by dropping 「判词」 beside PASS/FAIL (the token carries the fact): 119 B → 118 B, 60 lines before and after, ceiling untouched. The reader keeps refusing the key-in-span spelling and now NAMES it: HEAD_KEY_IN_SPAN + headSpanHoldsKey run only after locateReviewOfRecord answered absent, choose no comment and admit none (the accept set stays one spelling; a correct record beside a refused one is found in either arrival order, pinned), and C6's absent row splits into the empty case and the spelling case quoting the span the seat wrote, the thread, and the --template fix. The file's own verbatim quotation of :28 was updated in the same edit.
  • P1's live half is FALSIFIED and said so: comment 5652813288 (PR feat(spec)!: the three kernel/plugin-lifecycle-advanced.zod.ts duration keys carry their unit in the key name #17986) reads FOUND today because its prose quotes the head in a bare span of its own — the mechanism half holds on the key-in-span line alone, the trap is real, the board specimen is not an instance of the silent drop; --pair 17986 --pair-json replays both (verbatim bytes → no C6 row; the spelling alone → the C6 row naming the spelling). The seat accepts the correction and records that contractReviewHeadMatch scans the whole comment by H51's declared shape — declared behaviour, no card.
  • Seat-measured on the PR head in a detached worktree at c353334: --self-test → 677 cases pass, exit 0 (main 658; the dev's 658 → 677 holds; the new battery of 19 pinned as the diff shows); check-skill-line-ratchet ✓ (60/60), check:pm-skill-id-lint ✓, check-governed-prose ✓; awk length prints no line over 120 B; eslint on the script exit 0; live --pair 18270 exit 0 and --pair 18256 exit 0 with the C6-RECORD note on record 5674761187 on the head's reader. Ablation reported red (5 of 677 after two pins were retied to the composed sentence) with the blob-hash proof and the restore proved by git diff HEAD empty — accepted as reported; the direction is the predicted one.
  • Gates 42 / 42 / 0 / 0 with exits captured by redirect (doc-formula-expressions after its prerequisite build under the verify lock); check:pm-dispatch-gates ran to completion, exit 0; lint narrowed with the three pieces of evidence.

② Semver level

Not applicable — nothing published moves; skip-changeset measured (.claude/** + scripts/pm/** on the fast path).

③ Boundary flags

open_questions: none. Three declared deviations, each answered: (1) the payment shape — the dispatch said 「paid by density」 and the dev paid inside the line by deleting 「判词」 rather than buying a 61st line, exactly the currency os-dev.md allows; accepted, the better reading. (2) P3's sentence is conditional (a diagnosis when the refused spelling is present, the plain absence otherwise) — accepted, the state stays absent. (3) one origin/main merge for the derivation's stale-tree refusal; origin/main moved again after it, and the dev grepped that neither later commit touches H51_SHA_SPAN / contractReviewHeadMatch / the heading marker — the seat's own reading on the head against e592b4b6 agrees (no main commit touches either file). Landing: references tier + non-governed script ⇒ in-seat contract-tier review → ready → queue; all 35 checks green on the head at the record's instant. Out of scope, recorded: the whole-comment scan of contractReviewHeadMatch (declared H51 shape; the trap is survivable for some records and not others) — carried by whoever next touches H51's recognition; comment 5652813288's Implemented-by half and missing Served-tier: already on the card.

Implemented-by: claude/issue-18141-head-sha-span-holds-the-sha-alone
Reviewed-by: session_01HZfg2AwVX191qCizp88gQr

VERDICT: PASS


Generated by Claude Code

@claude

claude Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor Author

Landing provenance — skills seat, session session_01HZfg2AwVX191qCizp88gQr, 2026-09-15T06:00Z. In-seat landing (references tier .claude/skills/pm-dispatch/references/contract-review.md + non-governed scripts/pm/check-clause2-carriers.mjs): review of record 5675489493 (## Contract review PASS) names head c35333460e21f1610985d38c323c358136e28219; ACCEPT 5675489717 on #18141; check-clause2-carriers --pair 18270 exit 0 re-read at 2026-09-15T05:59Z with the C6-RECORD note naming that record; on that head Lint & Repo Gates and TypeScript Type Check both success and every other check is success or skipped (35 runs: 24 success, 11 skipped, 0 running, 0 failed); mergeable_state clean. Ready through POST …/ccr/ready_for_review (200, read back draft: false), auto-merge armed through PUT …/ccr/auto_merge SQUASH (200, enabled, method squash); timeline reads ready_for_review 2026-09-15T05:59Z and added_to_merge_queue 2026-09-15T05:59Z; queue ref gh-readonly-queue/main/pr-18270-* present on origin at 2026-09-15T06:00Z. MERGED is confirmed later by two readings (the queue ref gone + git log origin/main carrying (#18270) with one parent), then the card's residue is stripped.


Generated by Claude Code

Merged via the queue into main with commit 48a93fb Sep 15, 2026
37 checks passed
@claude
claude Bot deleted the claude/issue-18141-head-sha-span-holds-the-sha-alone branch September 15, 2026 06:20
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 size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

1 participant