Skip to content

check-half-states' per-window summary assertions match the WHOLE summary line, so a neighbouring window's clause can satisfy them #13629

Description

@claude

Found while converting the remaining count-shaped windows in PR #13628 (card #13606). Not fixed there — it is a defect in existing test scaffolding, outside that card's file-surface remit of "the windows and their disclosure", and the workaround it forced is itself the evidence.

The shape

summaryLine returns ONE long sentence carrying every pass's disclosure. H8's window-disclosure cases (landed in PR #13601) assert against that whole string:

t('H8 summary: a completed window says the horizon was reached',
  h8win({ mergedPages: 9, mergedWindowTruncated: false }).includes('horizon reached'), true);
t('H8 summary: …and does NOT claim the horizon was reached',
  h8win({ mergedPages: MERGED_WINDOW_PAGE_CEILING, mergedWindowTruncated: true }).includes('horizon reached'), false);

Both were exact and falsifiable when H8 was the only window on that line. They are not scoped to H8's clause — .includes searches the entire summary — so any OTHER clause containing the same phrase satisfies the positive case and breaks the negative one.

Measured, not suspected

PR #13628 adds three more disclosures to the same line. Drafting them with the natural parallel wording ("horizon reached") turned the negative case RED immediately: a TRUNCATED H8 window now had "horizon reached" in its summary, contributed by H22's healthy clause standing beside it.

That red was the lucky direction. The unlucky one is the positive case a completed window says the horizon was reached, which a neighbouring clause satisfies silently — it would keep passing even if H8's own disclosure were deleted outright. That is a check that cannot fail, in the file whose entire subject is refusing exactly that.

PR #13628 worked around it by giving the shared helper a distinct phrase ("boundary reached"), documented at describeWindowBound. That keeps every current case falsifiable, but it is a naming convention holding the line, and it does not survive the next author who reaches for the obvious word.

Why a card rather than a fix in that PR

The repair is to scope each window's assertions to that window's own clause rather than to the whole sentence — e.g. extract the clause per window and assert on it, so a case can only be satisfied by the speaker it names. That is a change to how the summary's cases are written across every window that has one (H8, H22, H23, H35, the open listings), which is broader than the converting card's surface and would have mixed a scaffolding refactor into a behavioural conversion.

Suggested acceptance: no case asserting a window's disclosure can be satisfied by text another window contributed. A cheap proof is an ablation per window — delete that window's clause and confirm ITS cases go red while the others stay green.

File surface: scripts/pm/check-half-states.mjs (the selfTest summary cases).


Generated by Claude Code

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions