fix(pm): H44's timestamp leg accepts an ISO instant whose hour follows a T — the ruled minute spelling no longer reads as untimestamped - #18326
Conversation
…s a T `H44_READING_TIMESTAMP` anchored the hour with a bare word boundary, which needs a NON-word character in front of it. The `T` of an ISO instant is a word character, so `2026-09-15T14:51Z` read false — and so did `2026-03T00:21Z`, the spelling the 2026-09-02 ruling itself gives. A reading that DID carry its 取数时刻 in the ruled minute form was reported as untimestamped: a false positive on the row's own subject. A seconds stamp passed only by accident, the boundary holding before its `mm:ssZ` tail so the match began at the minutes. The left anchor now names one further predecessor — the ISO `T`, looked BEHIND rather than consumed, so a match is still exactly the stamp. Nothing else is admitted: the boundary is kept (a clock inside a longer digit run is still not a stamp), no other letter opens one, and only the uppercase `T` the ruling spells. Strictly more paragraphs read clean, so the row can only get quieter. Self-test 4235 -> 4243 cases: the two ISO spellings that read false, a pin on where the seconds match STARTS (the fix, not the accident), three declared negatives, and the H44 marker case re-pinned to MINUTES with the seconds spelling kept beside it — the comment saying that limit existed is rewritten, because the limit is gone. 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 |
Takes in PR #18326 (the H44_READING_TIMESTAMP region and its cases), which landed on main while this branch was in flight. Different regions of the same file; no conflict. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr
Fixes #18323
H44_READING_TIMESTAMPis the leg that decides a paragraph already carries its 取数时刻. It anchored the hour with a bare word boundary, which needs a NON-word character in front of it — and theTof an ISO instant is a word character. So the leg read false on the very spelling the 2026-09-02 ruling gives, and H44 reported readings that DO carry their time as untimestamped: a false positive on the row's own subject. A seconds stamp passed only by accident, the boundary holding before itsmm:ssZtail, so the match began at the MINUTES.Reverse verification — probes on the module's own export
A
file://import of the script (a pure export; the module runs nothing on import and makes no request), against the unpatched file ata46cd8c4and against this branch:2026-09-15T14:51Z— the live R+236 marker's fire stamp2026-03T00:21Z— the spelling the ruling itself gives2026-09-15T14:51:42Z14:51Z— a bare clock19:38— a bare clock with no zone12314:51Z— a clock inside a longer digit runThe seconds probe is the one that shows the difference between the fix and the accident it replaces:
'2026-09-15T14:51:42Z'.match(...)[0]was51:42Zbefore and is14:51:42Znow — the match starts at the HOUR, and that is pinned as a case rather than the baretruethat held either way.The one design choice, on the four axes
The choice is between naming the left anchor (start / whitespace / punctuation, which the word boundary already spells, plus the ISO
T) and dropping the left boundary altogether. This PR names it, and looks behind rather than consuming, so a match is still exactly the stamp.T, in the R+236 round-open marker (fire 2026-09-15T14:51Z) and in the ruling's own2026-03T00:21Z. No artefact was measured writing a stamp behind any other letter. Dropping the boundary would serve a case nobody has:12314:51Zis a digit run that happens to contain a clock, never a reading's time.HH:MM[:SS]Zis clean — this makes the regex true to a statement the file has been making all along, rather than rewriting the statement down to the implementation.tis legal and absent from this corpus; it is pinned as NOT admitted, so taking it later is a measurement rather than a guess.Self-test
node scripts/pm/check-half-states.mjs --self-test: 4235 → 4243 cases pass, exit 0. Eight cases added, one rewritten:2026-09-15T14:51Z, and the ruling's own2026-03T00:21Z);t;2026-09-15T14:51) still reads false, exactly as a bare clock does;Firing control (ablation): with the one regex line reverted and every case kept, the self-test goes red on exactly four cases by name — the two ISO spellings, the match-start pin, and the marker case, which reports
{shape: 'a round-open marker', kind: 'tree', fragment: '827cacbf'}wherenullis wanted. That row IS the false positive this PR removes. Restoring reproduced the committed blob hash exactly, andgit diff HEADandgit status --porcelainare both empty.Scope
scripts/pm/check-half-states.mjsonly, and inside it only the constant at the H44 grammar, its doc comment, and its self-test cases. H44's population, its seat gate, its marker shapes (h44RoundOpenShapes/h44IsRoundOpenMarker), the fragment grammar and every other H row are untouched.:9791is the constant's only consumer (grepcount: one declaration, one consumer, the self-test cases) and it calls.test, so nothing reads the match text today.The two sibling cards dispatched on this same file — #18324 and #18325 — work at other regions (
h44NeedsSeatComments, theseatMarkerscapture,latestSeatMarker) and also add self-test cases at the tail; whichever lands second mergesmainand re-runs the self-test. PR #18322 is the predecessor that landed the marker spelling this card's measurement came from.Acceptance notes
PROTOCOL_STAMP_RE(H56's stamp shape) carries the same\bopener and is NOT affected: its boundary sits in front of the four-digit YEAR, where a non-word character really does precede it. Checked, not assumed.1234-56:78Zreads as a stamp. It read that way before this change and still does; the direction is toward MORE paragraphs clean, so it can only make the row quieter, and no artefact on the board writes it.skip-changeset: nothing published moves. The diff is one file underscripts/pm/**, which no package'sfiles[]ships.Generated by Claude Code
Generated by Claude Code