fix(pm): H44 stops reading a session id as a dateless tree tip - #18437
Conversation
`H44_READING_FRAGMENTS`'s `tree` shape is 7-40 hex characters carrying both a letter and a digit, and a session identifier satisfies it: on one live board 6 of 9 H44 rows in a sweep were 「PM session c5c0ce54」/「PM 会话 c5c0ce54」 or the LAST SEGMENT of a `session_<uuid>` line, where the hyphen is a word boundary. The row's remedy — add the time the reading was taken — applied to an identifier asks a seat to stamp a reading nobody took, so the row taught the wrong discipline rather than merely being noisy. The `tree` shape itself is unchanged (pinned by its regex source). What is added is narrowing 4: a per-shape `exclude` predicate, declared on the `tree` entry alone, that drops a CANDIDATE which is lexically part of an identifier — the tail of a longer token behind a flush `-`/`_`, or one introduced immediately by `session` / `会话` / `session_`. The introduction leg reads ADJACENCY rather than 「the sentence mentions a session」 because the loose spelling silenced a real dateless tip reading measured on this board (「this session's checkout HEAD `588475c3`」), which is pinned as CONTROL D. The paragraph is rescanned past an excluded candidate for a shape that declares an exclusion, so a comment that fired can change which fragment it names but a quiet one cannot start firing. Self-test: 4270 -> 4297 cases, H44 105 -> 132. CONTROL A (a dateless real tip) still fires and CONTROL B (the same tip stamped) stays quiet. Claude-Session: https://claude.ai/code/session_01HPfcjvF23QBoBj7P47DDxs Co-authored-by: Claude <noreply@anthropic.com>
… the verdict A case that dereferences a null match throws, and the throw takes the whole self-test down before its verdict line — every sibling reading in the run is hidden with it. Measured while ablating the introduction leg: the run died on one case instead of reporting the rows that had gone red. Claude-Session: https://claude.ai/code/session_01HPfcjvF23QBoBj7P47DDxs Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Skills seat, ① Derived judgments
② Semver levelNone owed: ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
|
Landing provenance — skills seat, Generated by Claude Code |
Fixes #18385
H44_READING_FRAGMENTS'streeshape reads "7-40 hex characters carrying at least one letter and at least one digit". A session identifier satisfies that, and the row's remedy — add the time the reading was taken — applied to an identifier asks a seat to stamp a reading nobody took. On the board the card measured, 6 of 9 H44 rows in one sweep were exactly this. The failure direction is "a patrol row teaches the wrong discipline", not "a patrol row is noisy".Before / after, measured on this branch
h44UntimestampedReading(body, false)fed claim-shaped strings. BEFORE is the module at the merge base (90b23ab1), AFTER is this branch's HEAD; both were imported into one process so the two readings are taken on the same inputs.Claim: …)Claim: PM session c5c0ce54 — dispatching this cardtree·c5c0ce54Claim: PM 会话 c5c0ce54 派发本卡(席位 F)。tree·c5c0ce54Session:line carrying a backtickedsession_71836b57-5db6-459d-ae4d-c6d9d7dd2cc6tree·c6d9d7dd2cc6(the UUID's last segment)reviewed head+ a backticked480080c7a0tree·480080c7a0at 2026-09-16T06:48Zsession_01TAUTP6Yky8QWoHUAPDKNJQSix of six agree with the card's table before the change, and the two controls hold after it.
⭐ CONTROL D was found while measuring, and it moved the design. Over a corpus of 251 real comments from 30 recently-updated cards in this repo, the first spelling of the introduction leg ("the candidate's SENTENCE mentions a session") silenced exactly one comment —
5695539587, 「every harness-loaded path onorigin/mainis in this session's checkout HEAD588475c3」 — which is a genuine dateless tip reading this row exists to file. A possessive three words away introduces nothing, so the leg was tightened to adjacency: only separators and decoration may stand between the word and the candidate. Re-measured on the same corpus afterwards: 251 comments, 12 fired before, 12 fired after, 0 changed — the narrowing takes the false positives and no live reading with them.What changed
treeshape itself is untouched and pinned as its regex source in the self-test, so a later widening of the token cannot ride in under this row. The change is an exclusion on the candidate, added as a per-shapeexclude(paragraph, index, matched)seam declared on thetreeentry alone, so the self-test drives it by name.session/会话/session_immediately before it, decoration only in between).Session:line by template, so a paragraph-scoped test would silence H44 across the whole claim population, which is CONTROL A's habitat. ASession:line one line above a dateless tip therefore leaves the tip firing.session id c5c0ce54) is not excluded — one measurement away, not a guess. It is pinned as a case in that direction.Self-test
H44casesnode scripts/pm/check-half-states.mjs --self-test→✓ check-half-states self-test: 4297 cases pass.Ablation (two legs, each restored, each proven on disk before the run):
exclude:wiring line (occurrences 1 → 0 verified on disk): 9 of 4297 cases fail, including all three firing inputs and the whole rescan block.Both legs restored from
HEADunder a trap; after each,git status --porcelainis empty andgit hash-objecton the file equals theHEADblob hash.Gates
node scripts/pm/dispatch-gates.mjs --commands(no paths) derived 40 commands; all 40 ran in the foreground with exit codes captured before any pipe, and all 40 exited 0. Reconciled:✓ dispatch-gates --ran: 40 derived famil(ies) accounted for — 40 run, 0 NOT-MEASURED (a DERIVED zero — all 40 recorded an exit code and none of them is 3). Heavy runs went throughscripts/pm/os-verify-lock.sh(VERDICT command-exit 0 · held the lock 841s).Named among them:
pnpm check:pm-half-states(the self-test, 4297 pass),pnpm check:nul-bytes(OK (scanned 8721 text file(s) … no raw ASCII control bytes)),pnpm check:pm-dispatch-gates,node scripts/check-self-test-wired.mjs(and its--self-test),node scripts/check-scripts-symbol-anchors.mjsandpnpm check:commit-card-trailers.Lint, as a declared narrowing (the repo-wide
pnpm lintis CI's run): ① the population is read from eslint's own config —ESLint#isPathIgnoredover the tracked JS/TS set says 6786 of 6786 files are in scope; ② the targeted runnpx eslint scripts/pm/check-half-states.mjs --no-inline-config --format jsonreports 1 file linted, 0 errors, 0 warnings (count read from the JSON); ③ invariance:eslint.config.mjsstates in its own text that this repo "runs oneeslint.config.mjs, which never enables type-aware linting (noparserOptions.project, no typed@typescript-eslintrules) for ANY file", so a one-file diff cannot move the verdict on any file it did not touch.Changeset
No changeset. AGENTS.md, Post-Task Checklist step 3, the line acted on: 「⛔ never
skip-changeset: that label is for a diff that publishes nothing from any released package」 — this diff is one file underscripts/pm/**, which no package'sfiles[]ships, so theskip-changesetlabel is the declaration and a changeset would be the wrong one.Clause-②: no.Acceptance notes
H44_READING_FRAGMENTS'streeentry,h44UntimestampedReadingand the new helpers beside them are touched, plus H44 self-test cases appended after the existing H44 block. The H38 region and its cases, the file's tail entry/argv parser and the H64 region are untouched — those are other cards in flight on this same file, and the hunks are kept tight so the later lander merges cleanly.h44UntimestampedReadingRow) is unchanged: it is now only ever rendered for a reading, so it stays truthful without an edit. The card asked for the predicate, not a new message.H44_READING_TIMESTAMPparagraph leg means a claim whoseSession:line and tip share one paragraph WITH a stamp elsewhere in that paragraph is clean for a reason unrelated to this change. Carrier for that reading: none — no open card and no PR touches that leg, and it is the row's declared design, not a defect.session, 会话). A board that writes 「席位」 or another coinage beside a shorthand id would fire again. Carrier: the next H44 patrol row that shows one — a spelling nobody has measured is not a defect to file today.Generated by Claude Code