STATUS, 2026-09-14 — R2, R3 and R4 were ACCEPTED IN WRITING; this issue now rests on R6 alone.
The decision and its reasoning are in a comment below. The 09-13 note follows unchanged.
STATUS, 2026-09-13 — read this before the list below. Two of these are
CLOSED and two more residuals were found while closing them. The per-residual
headings below were written when all four were open and are annotated in place
rather than rewritten, so the original framing stays readable.
| residual |
state |
R1 gatePreSanitised resolves a name |
✅ CLOSED — #578 (3457c5dc): the state was deleted rather than made relational |
| R2 laundering past four hops |
✅ CLOSED — accepted in writing 2026-09-14 by @ZacxDev (comment below): bound measured 4/5, live corpus max 2 hops, GREW/SHRANK/MISLABELLED unaffected |
| R3 a renderer with no server text has no honest row |
✅ CLOSED — accepted 2026-09-14 (comment below). 🔴 Its "points at gatePreSanitised" clause is STALE: #578 deleted that state |
| R4 the same hazard one line outside a cell |
✅ CLOSED — accepted 2026-09-14 (comment below); was already partly narrowed by #578 |
R5 one-letter bareIdentArgs keys (comment below) |
✅ CLOSED — #582 (095f4acf): re-keyed enclosingFunction::argument |
R6 a (function, name) key cannot express two callers with two origins (comment below) |
🟡 open — surfaced by R5's audit |
R5 and R6 are recorded as comments on this issue, not in this body.
Successor to #552, whose closing condition was met by #573 (6f0a8d8). These four were recorded in the code as open — each is stated in internal/cmd/tabwriter_ledger_test.go's residual list or const block rather than implied — and none is covered by #552's condition. Filed together because they share one root: a structural scan over tabwriter cells cannot see any of them.
Closing condition
Each residual below is either fixed, or re-stated with a decision recorded by a named reader. R1 is the only one that is plainly a defect; R2–R4 are trade-offs that may legitimately be accepted in writing.
Checked by: for a fix, the merged PR plus a mutation showing the relevant guard reddens; for an accepted trade-off, a comment on this issue from a maintainer naming which residual and why, after which this issue closes.
✅ R1 — gatePreSanitised resolves a NAME, never a relationship — CLOSED by #578
Closed 2026-09-13 by #578 (3457c5dc). Not by making the resolution relational,
which is what the text below proposes: matching an upstream's output to the
renderer's own cell narrows the hole to a field name and still leaves one. The state
was deleted instead, and its single user (printGenerateQuote) now gates at the
cell, where safeTermSingle is an idempotent no-op and the scan can see it. Watched:
the row that used to pass now fails three ways — unknown gate, MISLABELLED, and
GREW — where all three were green before.
The original framing follows unchanged.
internal/cmd/tabwriter_ledger_test.go. The gate arm checks that upstream names a function that exists and calls safeTermSingle somewhere. It never checks the named function feeds this renderer's cells.
Measured: a renderer writing a raw server string into a cell, ledgered as {…, gatePreSanitised, "printTagList", …} — printTagList being an unrelated renderer that merely happens to sanitise — passes the test and the entire internal/cmd package.
So the ledger's set is closed at two states, but one of them is a hole any row can be moved into. Pre-existing — the same row is green before that file existed — and three sentences claiming otherwise were retracted in 34f0257.
Closing it means resolving upstream against the renderer's own cell expressions. That is hard precisely for the struct-field case the state exists to cover, which is why it is filed rather than fixed.
Today exactly one row uses it (describeVersion) and that use is independently true. That bounds the damage; it is not a defence.
🟡 R2 — laundering past four hops
sanitizerReach stops at depth 4. A bare safeTerm passed through five successive local assignments reaches a cell uncounted. Measured at both points: 4 hops → reported, 5 hops → sanitizers=[], missed.
The renderer is still seen, so GREW/SHRANK/MISLABELLED still apply — only the BARE-SAFETERM half is lost. No value in the package is currently passed through more than two hops.
🟡 R3 — a renderer with no server text has no honest row
An all-CLI-owned renderer (integers and literals only) is still registered as a renderer, so GREW demands a row — but gateSingle fails MISLABELLED with "the gate was deleted — which is the #552 defect happening", which is untrue of it, and gatePreSanitised would be a lie.
The honest options are a no-op safeTermSingle on an integer, or restoring a third state. None exists today, so the choice is deferred, not made — and the GREW message currently points the next author at gatePreSanitised, i.e. straight into R1.
🟡 R4 — the same hazard one line outside a cell — NARROWED, still open
#578 closed the money-path instances: confirmGenerate's Checkpoint: and
LoRA: label lines, and printImageDisclosure's Image: line, all of which sat
above Generate? [y/N]: and could forge a fake Cost: line before an irreversible
spend. The ~60 other single-line read-path sites below are untouched.
printModelDetail's header, printCollectionDetail, printAppDetail print label: value with plain Fprintf; a \n still lands at column zero. ~60 such single-line read-path sites remain.
printSubmissionDetail and printListingStatus were in this class and are fixed (#573) — a rejection reason of "\x1b[1A\x1b[2KOVERWRITTEN" previously put a raw ESC on stdout.
Telling a single-line label from legitimately multi-line free text is a per-field judgement, not a structural one. The README says this to users rather than promising the wider claim.
Not included
Soft wrap — collapsing \n makes lines longer, so a long value can still reach column zero via the terminal's own wrap with no control character involved. It is the one item #552 was being held open for; it is a different root cause (no column budget) and belongs in its own issue if anyone takes it up. U+2028/U+2029 likewise: a documented internal/saferune residual with no known terminal that breaks on them.
Provenance
R1 came from a delta re-audit of #573; R2–R4 from the blind correctness round and the requirements round. The original forgery class is @xsvm's (#544, #545, #554).
Successor to #552, whose closing condition was met by #573 (
6f0a8d8). These four were recorded in the code as open — each is stated ininternal/cmd/tabwriter_ledger_test.go's residual list or const block rather than implied — and none is covered by #552's condition. Filed together because they share one root: a structural scan over tabwriter cells cannot see any of them.Closing condition
Each residual below is either fixed, or re-stated with a decision recorded by a named reader. R1 is the only one that is plainly a defect; R2–R4 are trade-offs that may legitimately be accepted in writing.
Checked by: for a fix, the merged PR plus a mutation showing the relevant guard reddens; for an accepted trade-off, a comment on this issue from a maintainer naming which residual and why, after which this issue closes.
✅ R1 —
gatePreSanitisedresolves a NAME, never a relationship — CLOSED by #578Closed 2026-09-13 by #578 (
3457c5dc). Not by making the resolution relational,which is what the text below proposes: matching an upstream's output to the
renderer's own cell narrows the hole to a field name and still leaves one. The state
was deleted instead, and its single user (
printGenerateQuote) now gates at thecell, where
safeTermSingleis an idempotent no-op and the scan can see it. Watched:the row that used to pass now fails three ways —
unknown gate,MISLABELLED, andGREW— where all three were green before.The original framing follows unchanged.
internal/cmd/tabwriter_ledger_test.go. The gate arm checks thatupstreamnames a function that exists and callssafeTermSinglesomewhere. It never checks the named function feeds this renderer's cells.Measured: a renderer writing a raw server string into a cell, ledgered as
{…, gatePreSanitised, "printTagList", …}—printTagListbeing an unrelated renderer that merely happens to sanitise — passes the test and the entireinternal/cmdpackage.So the ledger's set is closed at two states, but one of them is a hole any row can be moved into. Pre-existing — the same row is green before that file existed — and three sentences claiming otherwise were retracted in
34f0257.Closing it means resolving
upstreamagainst the renderer's own cell expressions. That is hard precisely for the struct-field case the state exists to cover, which is why it is filed rather than fixed.Today exactly one row uses it (
describeVersion) and that use is independently true. That bounds the damage; it is not a defence.🟡 R2 — laundering past four hops
sanitizerReachstops at depth 4. A baresafeTermpassed through five successive local assignments reaches a cell uncounted. Measured at both points: 4 hops → reported, 5 hops →sanitizers=[], missed.The renderer is still seen, so GREW/SHRANK/MISLABELLED still apply — only the BARE-SAFETERM half is lost. No value in the package is currently passed through more than two hops.
🟡 R3 — a renderer with no server text has no honest row
An all-CLI-owned renderer (integers and literals only) is still registered as a renderer, so GREW demands a row — but
gateSinglefails MISLABELLED with "the gate was deleted — which is the #552 defect happening", which is untrue of it, andgatePreSanitisedwould be a lie.The honest options are a no-op
safeTermSingleon an integer, or restoring a third state. None exists today, so the choice is deferred, not made — and the GREW message currently points the next author atgatePreSanitised, i.e. straight into R1.🟡 R4 — the same hazard one line outside a cell — NARROWED, still open
#578 closed the money-path instances:
confirmGenerate'sCheckpoint:andLoRA:label lines, andprintImageDisclosure'sImage:line, all of which satabove
Generate? [y/N]:and could forge a fakeCost:line before an irreversiblespend. The ~60 other single-line read-path sites below are untouched.
printModelDetail's header,printCollectionDetail,printAppDetailprintlabel: valuewith plainFprintf; a\nstill lands at column zero. ~60 such single-line read-path sites remain.printSubmissionDetailandprintListingStatuswere in this class and are fixed (#573) — a rejection reason of"\x1b[1A\x1b[2KOVERWRITTEN"previously put a raw ESC on stdout.Telling a single-line label from legitimately multi-line free text is a per-field judgement, not a structural one. The README says this to users rather than promising the wider claim.
Not included
Soft wrap — collapsing
\nmakes lines longer, so a long value can still reach column zero via the terminal's own wrap with no control character involved. It is the one item #552 was being held open for; it is a different root cause (no column budget) and belongs in its own issue if anyone takes it up. U+2028/U+2029 likewise: a documentedinternal/saferuneresidual with no known terminal that breaks on them.Provenance
R1 came from a delta re-audit of #573; R2–R4 from the blind correctness round and the requirements round. The original forgery class is @xsvm's (#544, #545, #554).