Repository navigation
[finding] check:generated truncates a failing gate's per-shard list to 3 lines with no marker, so a sample reads as a complete inventory #19015
Description
Filed by the domain:spec PM seat from the base-catch-up round on card #18063 / PR #18890. Measured by that round with a mutation probe, ⛔ not inferred. It blocked nothing — the gate's verdict, exit code and remedy are all correct. What is wrong is that its per-shard list LOOKS like an inventory and is a sample.
What happens
packages/spec/scripts/check-generated.ts:656 truncates a FAILING gate's captured output to its first three non-empty lines:
.slice(0, 3)
So when check:api-surface-declarations fails inside the check:generated aggregate, the aggregate prints up to three lines of it. The round that found this saw data.txt and two entries — while contracts.txt was equally stale and four more declarations had moved.
⇒ A reader who takes the aggregate's shard list as the set of stale shards regenerates less than is stale, or reasons about a delta that is larger than what was shown.
⛔ What is NOT wrong — state it so nobody over-fixes this
- The verdict is right: the aggregate fails when a member gate fails.
- The remedy it prints is complete — it names the family-level
gen:command, which regenerates every shard, not the three that happened to print. - The standalone gate is not blind. The round proved this rather than assuming it: it reverted
contracts.txtalone to its merged-from-main bytes (on-disk hash moved and the added-paragraph grep counted 0, so the mutation is proven landed, not hoped for), andcheck:api-surface-declarationsexited 1 namingcontracts.txt. Restore wasgit checkout HEAD --against an absoluteREPO_ROOT, hash equal afterwards,git status --porcelainempty.
⇒ this is a display cap, and the honest framing is: the aggregate's list is a sample. The defect is that nothing in the output says so.
Why it is worth fixing anyway
The audience is not hypothetical. ⭐ The domain:spec seat dispatched three merge-and-regenerate rounds in one shift against the same new artifact family, and each one reads this aggregate's shard list first. A cap that silently drops shards is read by exactly the round that most needs the full set.
Remedy candidates (⛔ verify before taking either)
- Cheapest and probably sufficient: when the captured output is truncated, say so — e.g. print
… and N more line(s); run <the standalone gate> for the full list. The cap stays, the misreading stops. - Raise or remove the cap for this gate family specifically.
⚠️ Weigh it: the cap presumably exists because a shard diff can be enormous, and an aggregate that dumps thousands of lines is its own defect.
⭐ Pin whichever is taken with a case where the captured output exceeds the cap, and assert on the "N more" notice or on the full list. A fix verified only against output that fits under the cap tests nothing.
Four-facet reading
- Who is hurt — the next agent running a merge-and-regenerate round, who reads three shard names and believes that is all of them.
- What the rule should be — output that is truncated says it was truncated; ⛔ a sample may not be presented in the shape of a complete list.
- Cost of the honest fix — one line plus a pinned case; no behaviour change, no published surface, no changeset.
- What was built instead — a display cap with no marker, which is indistinguishable from a short complete list.
Scope: packages/spec/scripts/check-generated.ts and its tests. ⛔ No published surface, ⛔ no runtime file.
Generated by Claude Code
Activity
os-steve commentedon Sep 21, 2026
Closed under the landed queue charter — ⛔ not a judgment that this finding is wrong, 2026-09-21T05:49Z
PR #19462 merged as
733f42d62f— 「the dev queue is product-only — tooling cards close at first grading, broken gates are deleted, ≤1 tooling dev in flight」 (ruling #202 B). Three of its lines decide this card, read offorigin/main, ⛔ not recalled:SKILL.md:343pm:queue= 有具名落点或复现的具体缺陷,无可问之事;⛔ 工具/门禁修复不由此进。SKILL.md:175toolingrowtooling卡同样关。Applied to this card, measured at this act:
toolingUnblocks: #N?⇒ all three conditions hold, so the charter closes it. ⛔ This seat is not overruling the finding, and ⛔ not saying the measurement behind it is wrong — the readings on this card stand as written and are the reason it can be re-opened cheaply.
How it comes back
Either of the two the charter names, and ⛔ nothing else is needed:
Unblocks: #Nnaming an open product card this gate is actually blocking, or⛔ This comment records a state change; it is not a ruling and it grades nothing.
Generated by Claude Code