From 0c27f2c2f7e06286a406502c6efa35c3324c32ae Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 05:13:42 +0000 Subject: [PATCH 1/2] fix(pm): say the head sha's code span holds the sha alone, and name the refused spelling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `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 --- .../pm-dispatch/references/contract-review.md | 2 +- scripts/pm/check-clause2-carriers.mjs | 135 +++++++++++++++++- 2 files changed, 130 insertions(+), 7 deletions(-) diff --git a/.claude/skills/pm-dispatch/references/contract-review.md b/.claude/skills/pm-dispatch/references/contract-review.md index e2a8eb2e8e7..63419ee5c2e 100644 --- a/.claude/skills/pm-dispatch/references/contract-review.md +++ b/.claude/skills/pm-dispatch/references/contract-review.md @@ -25,7 +25,7 @@ - 归属该卡派发席,交付后收集复核当轮席内完成;借复核不移卡,新 spec 工作恒归 spec 席。 - 逐车道:spec 席达档审契约增量;余席默认档自审加门禁、挂标;豁免仅独立性件与保险丝。 - 复核记录 = 一条评论落 PR 或卡,达档与默认档同形;散文、dev 自评、`os-dev-report` 恒不算。 -- 同形 = `## Contract review` 题头、所审 head sha 码段、①②③ 逐项、独立性对、PASS/FAIL 判词。 +- 同形 = `## Contract review` 题头、所审 head sha 独占码段、①②③ 逐项、独立性对、PASS/FAIL。 - 同形含首行 `Served-tier:`:值写常量名 `CONTRACT_REVIEW_TIER`;无此行不成裁决,模板见 `--template`。 - ① derived judgments 逐项:diff 引出的接受集与公开面变化逐条点名判对错。 - ② semver 定级与 changeset 声明一致;③ 边界旗:dev 挂旗与 `open_questions` 逐旗答复或升级。 diff --git a/scripts/pm/check-clause2-carriers.mjs b/scripts/pm/check-clause2-carriers.mjs index 5a79776bd70..fdf870864a3 100644 --- a/scripts/pm/check-clause2-carriers.mjs +++ b/scripts/pm/check-clause2-carriers.mjs @@ -310,7 +310,7 @@ * `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 - * review` 题头、所审 head sha 码段、①②③ 逐项、独立性对、PASS/FAIL 判词」 — and + * 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 @@ -713,6 +713,7 @@ const SELF_TEST_BATTERIES = Object.freeze({ '#17098: a key-INITIAL line that DESCRIBES the spelling — the half the fixture did not cover': 48, '#17959: POSITION is the LINE, not the body — the merged #17819 specimen in both its shapes': 10, '#18042: the copyable record TEMPLATE — the one machine-read artefact with nothing to copy': 24, + '#18141: the head sha sits in a span of ITS OWN — the key-in-span spelling, refused and NAMED': 19, }); // DELETING an entry silences that battery's floor exactly as effectively as @@ -722,8 +723,8 @@ const SELF_TEST_BATTERIES = Object.freeze({ // existing slack is preserved rather than tightened or loosened as a side // effect, and once more by the one #17149 adds, by the one #17098 adds, by the // one #17915 adds, by the one #17959 adds, by the one #18042 adds, and by the -// one #18174 adds. -const SELF_TEST_BATTERY_FLOOR = 23; +// one #18174 adds, and by the one #18141 adds. +const SELF_TEST_BATTERY_FLOOR = 24; // 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 @@ -2908,6 +2909,64 @@ export function reviewOfRecord(pair) { return locateReviewOfRecord(pair); } +/** + * The key-and-sha-in-ONE-span spelling -- the shape `H51_SHA_SPAN` cannot read. + * + * The key is the one `contractReviewRecordLines` prints, and the self-test + * derives its fixture by collapsing THAT line rather than retyping the key, so + * a template that renamed it reds here instead of drifting silently. + */ +export const HEAD_KEY_IN_SPAN = /`\s*Head-sha\s*:\s*([0-9a-fA-F]{7,40})\s*`/; + +/** + * The refused spelling, NAMED where the absence is reported (#18141). + * + * ⛔ A DIAGNOSIS, never a second accepted spelling. `H51_SHA_SPAN` matches a + * span that is hex and nothing else, so a record writing its head as + * `Head-sha: …` inside ONE span names no head, and a complete review written + * that way reads exactly like a pair that was never reviewed at all. That was + * the trap: `references/contract-review.md` :28 said 「head sha 码段」 and never + * that the span holds the sha ALONE, so a seat reading it in good faith wrote + * the refused spelling. The prose now says 「独占码段」 and this function is its + * machine half -- read only AFTER the locator has answered `absent`, choosing + * no comment and admitting none, so the accept set stays exactly one spelling. + * What it buys is the seat's next edit: 「no record at all」 and 「a record whose + * span carries the key」 stop printing the same sentence. + * + * ⛔ A comment the locator can already read is never this finding, whichever + * span carried the head -- measured on the live corpus specimen (PR #17986's + * comment 5652813288), whose `Head-sha:` span names nothing but which is still + * FOUND today, because its prose happens to quote the head in a bare span of + * its own. The defect is the spelling, not that comment. + * + * @returns {{ where: 'PR'|'card', id: number|null, sha: string, at: string|null } | null} + */ +export function headSpanHoldsKey(pair) { + const head = String(pair?.headSha ?? '').toLowerCase(); + if (head.length < H51_SHA_MIN_HEX) return null; + const tagged = [ + ...(Array.isArray(pair?.prComments) ? pair.prComments.map((row) => ({ row, where: 'PR' })) : []), + ...(Array.isArray(pair?.cardComments) ? pair.cardComments.map((row) => ({ row, where: 'card' })) : []), + ]; + const keyed = tagged.filter(({ row }) => { + const body = String(row?.body ?? ''); + if (!CONTRACT_REVIEW_HEADING_MARKER.test(body)) return false; + if (contractReviewHeadMatch(body, head) !== null) return false; + const m = HEAD_KEY_IN_SPAN.exec(body); + return m !== null && head.startsWith(m[1].toLowerCase()); + }); + // The same newest-of idiom the locator resolves with, never a second one. + const newest = latestMarkedComment(keyed.map(({ row }) => row), CONTRACT_REVIEW_HEADING_MARKER); + if (!newest) return null; + const { row, where } = keyed[newest.index]; + return { + where, + id: row?.id ?? null, + sha: HEAD_KEY_IN_SPAN.exec(String(row?.body ?? ''))[1], + at: row?.created_at ?? null, + }; +} + /** * C6 -- a gate cleared on both carriers with no review of record on the head. * @@ -2936,7 +2995,8 @@ export function c6NoReviewOfRecord(pair) { const shape = '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, and a `Reviewed-by:` line naming the reviewer. Existing tier verdicts already carry all three; a ' + + '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 ' + 'dev\'s own report, or an ACCEPT paragraph with the head and the line but no heading, is not one -- and ' + '「清标缺引记录即半态」.'; const boundary = @@ -2953,10 +3013,29 @@ export function c6NoReviewOfRecord(pair) { `and cites it in the provenance comment beside the clear. ${boundary} ${NEVER_WRITES}` ); } - return ( + const read = `${head} -- and NO review of record exists on this head: ${v.read.pr} comment(s) on the PR thread and ` + `${v.read.card} on the card were read, and none is a \`## Contract review\` comment naming \`${short}\` with a ` + - '`Reviewed-by:` line. This is the shape the filing sweep measured five times in one window -- a cleared gate ' + + '`Reviewed-by:` line.'; + + // The two ways a pair reaches this row print two sentences, because they ask + // two different things of the seat: writing a review down, or respelling one + // that was already written. ⛔ The spelling is still refused either way. + const keyed = headSpanHoldsKey(pair); + if (keyed) { + return ( + `${read} ⚠️ The SPELLING is why, and this pair is NOT the empty case: the ${keyed.where} thread's ` + + `${keyed.id ? `comment ${keyed.id}` : 'comment carrying no readable id'} (${keyed.at ?? 'undated'}) carries ` + + `the heading and writes this head INSIDE one code span, as \`Head-sha: ${keyed.sha}\`. A span is read as a ` + + 'sha only when it is hex and nothing else, so a span carrying the key as well names no head, and a complete ' + + `review written that way reads here exactly like no review at all. ${shape} Remedy: the reviewing seat ` + + 'reposts the record with the key OUTSIDE the span and the sha in a span of its OWN -- `--template` prints ' + + 'the whole record -- and cites it in the provenance comment beside the clear. ' + + `${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 ` + 'the review it already performed, in that shape, on the PR or the card, and cites it in the provenance comment ' + `beside the clear. ${boundary} ${NEVER_WRITES}` @@ -4969,6 +5048,50 @@ export function selfTest() { t('the offline document serves the PR thread from the same `comments` bag, keyed by the PR number', Array.isArray(pairJsonReader({ pulls: DOC.pulls, comments: { 13910: [] } }).readCardComments('owner/name', 13910))); t('…and one it omits reads null — UNJUDGED, ⛔ never a missing record', pairJsonReader({ pulls: DOC.pulls }).readCardComments('owner/name', 13910) === null); + // -- #18141: the head sha's span holds the sha ALONE ----------------------- + // + // ★ The trap, both halves. `references/contract-review.md` :28 said only + // 「head sha 码段」, so a seat reading it in good faith wrote the key and the + // sha into ONE span -- the live corpus spelling -- and a span is read as a + // sha only when it is hex and nothing else, so that record names no head and + // a complete review reads exactly like a pair nobody ever reviewed. The prose + // now says 「独占码段」. Here the reader pins that the refused spelling stays + // REFUSED -- ⛔ a second accepted spelling would be the trap's twin -- and + // that the row NAMES it, so the seat's next act is one respell, not a hunt. + battery('#18141: the head sha sits in a span of ITS OWN — the key-in-span spelling, refused and NAMED'); + // ⛔ Derived by collapsing the TEMPLATE's own line, never retyped: the key the + // diagnosis matches is the key `--template` prints, so a template that + // renamed it reds here instead of leaving this battery green about nothing. + const OWN_SPAN = contractReviewRecordLines({ headSha: HEAD_9AF9, implementedBy: 'claude/issue-13657-x', reviewedBy: RECORD_SESSION }).join('\n'); + const IN_SPAN = OWN_SPAN.replace(/^([A-Za-z-]+): `([0-9a-fA-F]{7,40})`$/m, '`$1: $2`'); + const KEYED_ROW = { id: 3401, created_at: '2026-09-01T08:50:00Z', body: IN_SPAN }; + const NEWER_RECORD = RECORD(HEAD_9AF9, undefined, '2026-09-01T08:55:00Z', 3403); + const keyedPair = bare({ prComments: [KEYED_ROW] }); + const keyedRow = c6NoReviewOfRecord(keyedPair); + t('⭐ the template writes the key OUTSIDE the span, and that record names the head', IN_SPAN !== OWN_SPAN && contractReviewHeadMatch(OWN_SPAN, HEAD_9AF9) === HEAD_9AF9); + t('⛔ …and the SAME record with the key folded INTO the span names no head — the defect isolated to the fold', contractReviewHeadMatch(IN_SPAN, HEAD_9AF9) === null); + t('⛔ so it is not a review of record: the accept set is still exactly one spelling', reviewOfRecord(keyedPair).state === 'absent'); + t('…and the pair is a C6 row, exactly as if nothing had been written', typeof keyedRow === 'string'); + t('⭐ but the row NAMES the spelling, quoting the span the seat actually wrote', says(keyedRow, `\`Head-sha: ${HEAD_9AF9}\``) && says(keyedRow, 'comment 3401')); + t('…and says WHERE it read it, so the seat opens the right thread', says(keyedRow, 'PR thread')); + t('…and prescribes the fix in the rule\'s own words — key outside, sha in a span of its OWN', says(keyedRow, 'in a span of its OWN') && says(keyedRow, '所审 head sha 独占码段')); + t('…pointing at the template as the thing to COPY, never a shape to compose', says(keyedRow, '`--template`')); + t('⛔ and it is a DIFFERENT sentence from the empty case — the two stopped printing alike', keyedRow !== absentRow && says(absentRow, 'indistinguishable from never reviewing') && !says(absentRow, 'The SPELLING is why')); + t('⛔ verdict-agnostic and never writes, exactly like the sentence it stands beside', says(keyedRow, 'PASS half') && says(keyedRow, '自查放行')); + t('⛔ a heading-less comment carrying the head is the plain absence, not this diagnosis', headSpanHoldsKey(bare({ cardComments: [CLAIM('Clause-②: yes'), SEAT_ACCEPT] })) === null); + t('⛔ a keyed span naming an OLDER head is the plain absence too — this row speaks about THIS head', headSpanHoldsKey(bare({ prComments: [{ ...KEYED_ROW, body: IN_SPAN.replace(HEAD_9AF9, 'facefeed') }] })) === null); + t('⛔ and a head too short to match is refused before any of it — unreadable is not a spelling verdict', headSpanHoldsKey(bare({ headSha: 'abc', prComments: [KEYED_ROW] })) === null); + t('the NEWEST refused spelling is the one named, when a thread carries two', headSpanHoldsKey(bare({ prComments: [KEYED_ROW, { ...KEYED_ROW, id: 3405, created_at: '2026-09-01T09:10:00Z' }] }))?.id === 3405); + // ⭐ The live corpus specimen's own shape: the refused line, and the head + // quoted in a bare span somewhere in the prose. It reads FOUND today -- the + // spelling is the defect, not that comment -- and this diagnosis stays silent. + const RESCUED = { id: 3402, created_at: '2026-09-01T08:51:00Z', body: `${IN_SPAN}\n\nCross-file staleness, searched at \`${HEAD_9AF9}\`.` }; + t('⭐ the refused line BESIDE a bare sha span elsewhere in the prose reads FOUND — and is not this finding', reviewOfRecord(bare({ prComments: [RESCUED] })).state === 'found' && headSpanHoldsKey(bare({ prComments: [RESCUED] })) === null); + t('⭐ a correct record beside a refused one is FOUND, in either arrival order', reviewOfRecord(bare({ prComments: [KEYED_ROW, NEWER_RECORD] })).state === 'found' && reviewOfRecord(bare({ prComments: [RECORD(HEAD_9AF9, undefined, '2026-09-01T08:45:00Z', 3404), KEYED_ROW] })).state === 'found'); + t('…and the locator chooses the CORRECT one — a refused spelling is never chosen over it, and never chosen at all', locateReviewOfRecord(bare({ prComments: [KEYED_ROW, NEWER_RECORD] })).id === 3403 && locateReviewOfRecord(bare({ prComments: [RECORD(HEAD_9AF9, undefined, '2026-09-01T08:45:00Z', 3404), KEYED_ROW] })).id === 3404); + t('…so no C6 row and no spelling sentence on a pair that has a real record', c6NoReviewOfRecord(bare({ prComments: [KEYED_ROW, NEWER_RECORD] })) === null); + t('the PROSE, the template and the reader name ONE spelling — and the template still round-trips', says(keyedRow, '独占码段') && contractReviewHeadMatch(contractReviewTemplateLines({ headSha: HEAD_9AF9 }).join('\n'), HEAD_9AF9) === HEAD_9AF9); + // -- C7: the tier that SERVED the verdict the strip stands on (#17915) ----- // From c35333460e21f1610985d38c323c358136e28219 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 15 Sep 2026 05:33:34 +0000 Subject: [PATCH 2/2] test(pm): tie the two weakest new pins to the diagnosis itself 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 --- scripts/pm/check-clause2-carriers.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/pm/check-clause2-carriers.mjs b/scripts/pm/check-clause2-carriers.mjs index fdf870864a3..af1a124a285 100644 --- a/scripts/pm/check-clause2-carriers.mjs +++ b/scripts/pm/check-clause2-carriers.mjs @@ -5073,10 +5073,10 @@ export function selfTest() { t('⛔ so it is not a review of record: the accept set is still exactly one spelling', reviewOfRecord(keyedPair).state === 'absent'); t('…and the pair is a C6 row, exactly as if nothing had been written', typeof keyedRow === 'string'); t('⭐ but the row NAMES the spelling, quoting the span the seat actually wrote', says(keyedRow, `\`Head-sha: ${HEAD_9AF9}\``) && says(keyedRow, 'comment 3401')); - t('…and says WHERE it read it, so the seat opens the right thread', says(keyedRow, 'PR thread')); + t('…and says WHERE it read it, so the seat opens the right thread', says(keyedRow, "the PR thread's comment 3401")); t('…and prescribes the fix in the rule\'s own words — key outside, sha in a span of its OWN', says(keyedRow, 'in a span of its OWN') && says(keyedRow, '所审 head sha 独占码段')); t('…pointing at the template as the thing to COPY, never a shape to compose', says(keyedRow, '`--template`')); - t('⛔ and it is a DIFFERENT sentence from the empty case — the two stopped printing alike', keyedRow !== absentRow && says(absentRow, 'indistinguishable from never reviewing') && !says(absentRow, 'The SPELLING is why')); + t('⛔ and it is a DIFFERENT sentence from the empty case — the two stopped printing alike', says(keyedRow, 'The SPELLING is why') && !says(keyedRow, 'indistinguishable from never reviewing') && says(absentRow, 'indistinguishable from never reviewing') && !says(absentRow, 'The SPELLING is why')); t('⛔ verdict-agnostic and never writes, exactly like the sentence it stands beside', says(keyedRow, 'PASS half') && says(keyedRow, '自查放行')); t('⛔ a heading-less comment carrying the head is the plain absence, not this diagnosis', headSpanHoldsKey(bare({ cardComments: [CLAIM('Clause-②: yes'), SEAT_ACCEPT] })) === null); t('⛔ a keyed span naming an OLDER head is the plain absence too — this row speaks about THIS head', headSpanHoldsKey(bare({ prComments: [{ ...KEYED_ROW, body: IN_SPAN.replace(HEAD_9AF9, 'facefeed') }] })) === null);