Skip to content

summaryLine: H19's clause has no sentence-terminating period unless a cross-repo probe fired, so it runs into H20's clause #13650

Description

@claude

Found while implementing #13629 (scoping check-half-states' per-window summary assertions). Not fixed there — that card's remit is the self-test scaffolding, and its adjudicated default is that the RENDERED summary line must not change.

The shape

Every window's clause on summaryLine ends with . — except H19's. H19's is assembled as:

`Blocker liveness (H19): targets resolved on ${btResolved} of ${btTargets} distinct \`Blocked-by:\` ` +
`target(s) named by open \`pm:blocked\` card(s)` +
`${ btResolved < btTargets ? ` — the ${btTargets - btResolved} unresolved target(s) are named …` : '' }` +
`${ crossRepoProbed > 0 ? ` Cross-repo reachability … ⛔ no re-run resolves them.` : '' } ` +
`Dispatch liveness (H20 + H27): …`

The terminating period exists only inside the cross-repo branch. When a pass has no shortfall AND took no cross-repo probe — the ordinary healthy case — the clause ends at card(s) and a single space joins it straight onto H20's lead-in.

The shortfall branch has the same gap: it ends at …not one rendered row carried an unresolved target), also without a period. So the ONLY rendering that terminates this clause is the one where a cross-repo probe happened.

Measured, not suspected

Live read-only patrol run 2026-08-31 against objectstack-ai/objectstack (from the #13629 worktree at commit 8813cf1, node scripts/pm/check-half-states.mjs, exit 0):

… targets resolved on 27 of 27 distinct `Blocked-by:` target(s) named by open `pm:blocked` card(s) Dispatch liveness (H20 + H27): remote branch read on 9 of 9 distinct claimed branch(es) …

Two sentences run together. Both neighbouring clauses on that same line end . normally.

Why this is more than punctuation

The summary line is the only half a report reader sees. The run-on makes Dispatch liveness (H20 + H27): read as a continuation of H19's population rather than as its own disclosure — the reader has to know the row inventory to find the boundary. It is also the one clause boundary that changes shape depending on whether an unrelated optional probe fired.

No self-test case pins H19's terminator today. The two cases that assert a terminating contract (summary: the report-only contract still ends the sentence) assert endsWith on the whole line, which is about the sentence's END, not about this clause.

Suggested fix: terminate the clause unconditionally, and let the optional branches contribute only their own text.

File surface: scripts/pm/check-half-states.mjs (summaryLine).

Filed unassigned, for triage.

Generated by Claude Code


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