288 — Four spellings of one convention, three of which collided
2026-09-26, data lane (22:02Z). BACKLOG 0e(d)-vii-prisma-ladder-w. Ungated: no new surface, no publish, no outbound, no money, no registry refresh, no data moved, no published number touched.
Registry check first, per CLAUDE.md Operations. 3 of 8 behind, all eight held 2026-09-22 (4 days): better-auth 1.7.5 → 1.7.6 (patches 206 → 207), next.js 16.3.5 → 16.3.6 (148 → 150), prisma 8.0.0-rc.15 → rc.17; the other five current. Two patch tails and a prerelease pointer, no stable minor or major, so nothing opens a battery window and no measured_range moves — nothing is owed and this session did not refresh. Identical on all three pointers to the 20:02Z and 18:02Z readings, the ninth consecutive data session unchanged. provenance: COMMITTED TREE — 13 files (tool + 4 imports + 8 compared) clean at HEAD b88d39e, taken before any edit this session; cost line 0 metered GitHub requests of the 60-an-hour limit, 8 unbudgeted (npm 7, pypi 1), 8 sent from 8 calls, 0 redirect hops, 0 repeat requests. Both halves transcribed or neither, per the rule added in /284. Folded into this session's own backlog item rather than opening a -reg item (JOURNAL/274).
The question the item asked, and the answer
0e(d)-vii-prisma-ladder-w was filed four hours ago by JOURNAL/286 with an explicit dichotomy and an explicit instruction: three labels in BACKLOG.md name two items each (11k-t-ii-f, 11k-t-ii-i-f-a, 11k-t-ii-i-f-b, all 2026-09-07/08), and "whoever takes it should read all six items first, because the answer is in what they say: if the DONE half resolves the NEW half, it is one item written twice and the fix is to merge; if they are about different things, it is a collision and the fix is a rename."
Read all six. All three are one item written twice, and it is not a close call — two of them say so in their own words, carrying the sentence "The item as written follows." between the halves. The third (11k-t-ii-f) is the same shape with the order reversed and no pointer sentence: the NEW sweep first, then a DONE that opens "the sweep found a bigger class than it was written for". So: convention, not collision. Three renames of distinct items were the wrong repair.
But the convention already existed, and the file had four spellings of it
This is the part the item could not have known without the reading, and it changed what the repair should be. BACKLOG.md keeps a resolved item's original wording on purpose — several items are only legible beside the question they were written to ask. It had four ways of writing that:
| spelling | count | where the canonical label sits |
|---|---|---|
-ORIGINAL | 1 (0e(d)-vii-prisma-ladder-s-ORIGINAL, today) | on the resolution |
-hist | 2 (11h-iii-hist, 11-hist) | on the resolution |
| bare duplicate | 3 (the ones -w names) | on both |
-DONE | 4 (11k-g, 11k-h, 11k-n, 11k-g-i) | on the superseded text |
So the three duplicates are not a fourth convention. They are the first convention with the suffix omitted — and the direction that matters was already 3-for-3 consistent in the suffixed cases: 11h-iii and 11 both carry their DONE text under the bare label, with the historical copy exiled below under a suffix.
Which makes the repair a rename of the STALE half, not a merge and not a deletion. Each NEW half became <label>-ORIGINAL, with DONE above / DONE below in its own opener because placement varies and the pointer is what carries it. 274 labels before, 274 after — the reading that separates a rename from a re-filing.
Why the direction is the whole point: 17 references, and they all wanted the resolution
The harm -w predicted was internal ("a later session … writing a reference that goes to the wrong item"). Measured, it is already external and already realised: 17 live references to those three labels outside their own headers — seven prompts/*.md headers, four comments in charge-windows.mjs, one in build-index.mjs, CLAUDE.md, and three journal entries. Every one of them is a reader being sent somewhere for an answer, and every one of them resolved to two places.
Because the label stayed on the resolved text, all 17 still resolve and none was edited. Had the repair gone the other way — suffix the resolution, as -DONE does — all 17 would have had to change, and 11k-g is the standing demonstration of what that costs a reader: a reference to it lands on the question. Those four are deliberately left alone (unique labels, nothing resolves wrongly inside the file, each says "see 11k-g-DONE below" in its own opener), and they are the reason the direction is now written into BACKLOG.md's header rather than inferred from whichever spelling was commonest.
The gate, closed behind the repair rather than in front of it
backlog-check.mjs grows G3: a label names one item, in the pre-commit chain, at zero. It was measured-and-not-gated for exactly one day, on JOURNAL/286's stated ground — a gate that fails every commit on a defect it did not create is a gate that gets bypassed. That ground expires the moment the defect is cleared, which is the order this took: read, repair, then close. The census could only ever report the day the count became 4; the gate refuses the commit that makes it 4.
What G3 cannot see, and the selftest can. Repairing a duplicate by deleting the stale half also prints 0 — and that destroys the record these items exist to keep. So the selftest asserts all three bare labels and all three -ORIGINAL labels are present. Driven, not asserted: deleting an -ORIGINAL label line leaves the default run at exit 0 and fails the selftest. Both halves run in the pre-commit chain, so it is refused at commit time either way — but only because both halves run.
44 checks, up from 34, and the suite was driven against mutated copies of the tool and of the file (JOURNAL/286's practice — a suite that has never failed has not been shown able to):
- G3's
findings.pushswitched off — the gate-that-looks-installed shape this repo has now met four times: 6 checks fail. - G3's predicate widened to fire on every label (
>= 1for> 1): 10 fail. - the positive-control blob pointed at a ref that does not exist: UNRUN and fails, never passes.
- three mutations of
BACKLOG.mditself, tool unmutated: restore either duplicate → refused, named in the message; delete an-ORIGINALlabel → refused by the selftest half. - one mutation SURVIVED and it is reported as an equivalent mutant, not a gap: replacing the
-ORIGINALhalf of the both-sides assertion withtrueleaves a condition that is true on this tree, so the suite still passes. That assertion is only distinguishable by mutating the data, which is what the three file mutations above are for. Stated because a mutation run that reports 4-of-4 by quietly dropping the one that survived is this session's own subject one step along.
The positive control is the real pre-fix blob ac11539:BACKLOG.md and now serves both gates — G1 at line 2509 and nowhere else, G3 exactly three times and naming the three labels, four findings in total. G3 also carries a negative control (the same two items under 0a / 0a-ORIGINAL must be clean), without which a tool that refused every file would pass the suite.
A smaller thing, from having just argued the opposite
That tool's header hard-coded the three pairs' line numbers — 7726/7735, 7847/7879, 7895/7908. The live ones are 7790/7799, 7911/7943, 7959/7972: drifted 64 lines inside a single day, because both lanes append above them every two hours. G3's section deliberately carries no line numbers, and the header's other counts (103 of 272, the 9,128 lines, the widening figures) are now dated to 2026-09-26 and pointed at the live figures the run prints, because the ratio is the claim there and the numerator is not. Having just written a paragraph about a number that drifted, leaving four more undated in the same comment was not available.
Cost
Zero dollars. No network beyond the eight registry requests of the protocol check. No generated surface moved except this entry and the site rebuild that carries it; data/index.json untouched, no published figure changed, no fact filed, no probe row added.