fix(pm): the half-state patrol reads a seat post's NEWEST comment page, and H44 knows the current marker spelling - #18322
Conversation
…e, and H44 knows the current marker spelling `commentRowsFor` asks the comments endpoint for `?per_page=100` with no `page`, and GitHub serves issue comments OLDEST-FIRST (`direction=desc` / `sort=created` are ignored there). That is the right window for a card and the wrong one for a seat post: on the triage seat post (816 comments) it returns 2026-08-06 → 2026-08-10, five weeks of archive holding none of the round then running. H44, H56 and H64 were all reporting on that page; H65 had to buy its own. The seat-post window is now `seatPostRowsFor` — the last page, located from the carrier's own `comments` count through H65's two helpers, memoised, ONE request per seat post per run. H44's seat leg lands it in the comment cache before the judging loop, so H56 and H64 inherit it by construction, and H65 consumes the same memo instead of a second purchase. An ordinary card keeps its first-page window; a single-page seat post costs no new request; a post whose count cannot be read falls back to page 1 and is counted apart from newest-page coverage. A seat post's cached thread is a page of the tail rather than a prefix, so the walk memo records it incomplete and H52 keeps treating those posts as unjudged. H44's round-open leg also matched nothing live: its regex expects `R+<n> open` and the triage seat writes `**Round-open marker** · … · **R+236** · fire …`. It now reads the round-open entries of `H65_ROUND_ARTEFACT_SHAPES` — the file's one declaration of those spellings — against the comment's headline, H65's measured false-positive control. `H44_ROUND_OPEN_MARKER` is unchanged and still matched body-wide, so no carrier this row already reports falls out. Self-test 4196 → 4235 cases. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr
…4-seat-leg-newest-page
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 #18312
The defect, measured
commentRowsForasks/issues/{number}/comments?per_page=100with nopage, and theper-issue comments endpoint serves oldest-first (
direction=desc/sort=createdaresilently ignored there). That is the right window for a card — a claim is early in the thread,
and H50's walk completes a full first page — and the wrong one for a seat post, which is an
append-only log running to hundreds of comments.
On the triage seat post (#6015, 818 comments) the page-less request returns
2026-08-06T16:01Z → 2026-08-10T17:29Z: five weeks of archive, holding none of the current
round's artefacts. H44, H56 and H64 all read that page; H65 (landed earlier, PR #18311) had to
buy its own newest page for exactly this reason.
Second half: H44's round-open leg matched nothing live.
H44_ROUND_OPEN_MARKERexpectsR+N open; the triage seat writes**Round-open marker** · triage seat · ... · **R+236** · fire 2026-09-15T14:51Z. Probe on thebase tree:
H44_ROUND_OPEN_MARKER.test(body of 5682407231)readsfalse.What this changes
One shared seat-post window.
seatPostRowsForis the file's single declaration of whichpage is a seat post's window: the last page,
ceil(comments / H50_COMMENTS_PAGE_SIZE)locatedfrom the carrier's own count through H65's two exported helpers, memoised — one request per
seat post per run, whichever row asks first. H44's seat leg lands it in
commentCachebeforethe judging loop, so H56 and H64 inherit it by construction; H65 consumes the same memo instead
of buying a second copy.
file and it is the card one (pinned by a source audit).
rows are reused unfetched.
commentscount cannot have its newest page located, so thewindow falls back to page 1 and is counted apart from newest-page coverage.
records it incomplete and H52 keeps treating those posts as UNJUDGED rather than clean.
One declaration of the marker spellings.
h44RoundOpenShapes()reads the round-open entriesback out of
H65_ROUND_ARTEFACT_SHAPESand tests them against the comment's headline(H65's measured false-positive control: a comment that merely quotes a marker deeper down is not
one).
H44_ROUND_OPEN_MARKERis unchanged and still matched body-wide, so no carrier this rowalready reports falls out. Neither row carries a private copy of the other's spelling.
Design choice (b) of the two the card offered — the shared bought page — rather than (a), a
seat-aware cache window: (a) leaves two rows deciding the same question in two places, which is
the dialect the file spends its length refusing.
Live before → after (report-only run on this board, 2026-09-15T16:51Z → 17:00Z)
Rows that moved — H44 on the three multi-page held seat posts, each now naming an artefact
from the current page instead of an August one:
5249069333—12 cards5622000371—551 commits5224786202—a36db285593116616—4013 PRs5239794336—33 PR5537619920—97bcd99e#6026 (48) and #7623 (63) fit in one page and are byte-identical before and after, which is the
single-page leg working. Row counts are unchanged: H44 26, H56 6, H64 10, H65 1.
Coverage clauses:
1184 comment(s) across 185 thread(s)→958 across 185, seat leg5 of 5both times,and the new sentence reads
5 of those post(s) had that page LOCATED. The corpus shrinksbecause a last page is shorter than a full first page — that is the trade this card bought:
fewer comments read, and the ones read are the live ones.
1184judged →958; ambiguous held-out lines14→18.1702→1476, signed872→748; its census (102/22/80) and itsfiled rows are unchanged.
11 round artefact(s) ... 18 comment(s) ... 1 carrier(s) filed— identical. Its counterskeep their meaning; only the clause's prose changes, to say the page is shared rather than
never cached.
Not measurable on this board today, and stated rather than implied: #6015 is
🔴 空缺, andH44's seat leg gate is
pm:seat+seatIsHeld, which excludes a vacant or🟢 Routineseat byname — so H44/H56/H64 read nothing on the triage post before or after. That gate is out of this
card's surface; it is written up in the report.
Reverse verification
Three ablation legs from the committed state, each mutated on disk, proved on disk, read, and
restored to the HEAD blob (
git diff HEADempty,git hash-objectback tob42680717dff2cd6aada4440b978e3905dcf87b4):seat window: exactly ONE page-less comment read exists in this file (got 2, want 1);seat window: ...taken through the memo by more than one row (got 1, want 2);H44 marker: ...under the marker's own name rather than the carrier's (got "a seat-post section", want "a round-open marker")— which is precisely what the base tree reported.Gates
All 41 commands derived by
node scripts/pm/dispatch-gates.mjs --commands scripts/pm/check-half-states.mjswere run and reconciled through--ran: every one exit 0.The battery
pnpm check:pm-dispatch-gatestook 453.5s (1730 self-test cases). The file's own--self-testgoes 4196 → 4235 cases, all passing. ESLint on the file: exit 0.node scripts/check-self-test-wired.mjs: exit 0.skip-changeset: nothing published moves —scripts/pm/**ships in no package'sfiles[].Generated by Claude Code