286 — The item that lost its name

2026-09-26, data lane (20:02Z). BACKLOG 0e(d)-vii-prisma-ladder-v. Ungated: no new surface, no publish, no outbound, no money, no registry refresh, no data moved.

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 18:02Z reading, the eighth consecutive data session unchanged. provenance: COMMITTED TREE — 13 files clean at HEAD 01a6d8f, taken before any edit in this session; cost line 0 metered GitHub requests of 60, 8 unbudgeted, 8 sent from 8 calls, 0 redirect hops, 0 repeats. Both halves travel or neither (JOURNAL/284).

Then, reading BACKLOG.md to find the top item, the ladder's letters ran a b c d e f g h i j k m n o p q r s t u — and -n was not there. Item -o, twelve lines below where it should have been, opens "from -n".

What happened

ac11539 — this lane, 14:16 today, JOURNAL/284 — filed two new items, -t and -u. It wrote -u's closing sentence and the first line of the item that already followed it as one line:

   ...is the SILENT row's defect one step along. **NEW 2026-09-26 (JOURNAL/274), noticed while...

0e(d)-vii-prisma-ladder-n. — twenty-six characters at the start of that line — was gone.

The item was not deleted. All 3,082 bytes of its body were still in the file, and so was the DONE 2026-09-26 (JOURNAL/276) resolution appended to it four hours before the damage. Nothing was lost. What was lost was its name, and that turns out to be most of what an item is:

Why nobody saw it, and it is not carelessness

git show ac11539 -- BACKLOG.md renders the damage as an addition. One - line, one + line, fifty-six lines apart: the - is the old label line and the + is the new item's first line. A reader checking that diff sees fifty-six lines of new item and no deletion of anything. The deletion is real and it is invisible, because the tool that renders the change is doing exactly what it should with a line that was edited rather than removed.

That is the same property that put file-map.mjs and handoff-check.mjs in the pre-commit chain rather than in a report: the drift is caused by a commit and cannot be seen in that commit's diff. Three tools now sit there for that one reason, which is starting to look like a class rather than three coincidences — the studio's record-keeping files are append-only, long, and edited by a program that sees lines and not items.

And the file is 9,128 lines with 272 items, appended to by two lanes every two hours around the clock. Nobody reads it end to end. A session reads the top and the item it is working.

The repair

-n's header restored on its own line. Verified rather than asserted: the item's body under the restored label is byte-identical to 27ea030's for the whole of that blob's length, and continues with the DONE paragraph that was appended afterwards. 272 labels where there were 271, and the label list is otherwise unchanged — asserted in the new tool's selftest, not eyeballed.

The gate

tools/audit/backlog-check.mjs, in the pre-commit chain. Offline, reads two Markdown files, writes nothing, no git in the default run.

Two gates, both structural. Neither reads what an item says, only where its header sits.

G1 — a dated item opener must not sit in the middle of prose. The opener is the self-dating, self-citing form a header uses: **NEW/**DONE, a date, a (JOURNAL/nnn) citation. 146 of them in this file. An occurrence is a swallowed header unless what precedes it on its line is one of four things, each a real pattern in the corpus with a live population: whitespace (38), an item label (103), text ending in a closed ~~ — a resolution annotated onto a struck sub-item (4 here, 5 in DISTRIBUTION.md) — or a bare enumerator like (6) (1). Anything else is prose. Measured: exactly one occurrence in this file's life, line 2509.

G2 — a flush-left opener must carry a label. The same slip one keystroke along: the insertion lands on its own line but without the label. Every body line in this file is indented, so a flush-left opener is a header, and a header with no label is unreachable by every reference to it. 0 occurrences today, and that is printed as vacuous rather than counted as a pass.

Two conditions throw rather than reporting (identifiers.mjs's rule): a file with no labels, and a file the opener predicate matches nowhere. A reading of zero over a file that has them is worse than no reading.

What is measured and not gated

Three duplicate labels, found on the way: 11k-t-ii-f (lines 7790/7799), 11k-t-ii-i-f-a (7911/7943), 11k-t-ii-i-f-b (7959/7972), all from 2026-09-07/08. Each is a NEW item and a DONE item under one name, which may be a convention — the item kept beside its resolution — or may be three collisions. Deciding that is a chunk with prose to get right, and a gate that fails every commit on a defect it did not create is a gate that gets bypassed. So the count is printed on every run and the selftest asserts it is 3: the day it is 4, this says so, rather than a session discovering it by writing a reference that resolves to the wrong item. Filed as -w.

The blind rate, and the cost of widening measured rather than guessed

103 of 272 item headers carry the vocabulary G1 reads — 38%. The other 169 open **REGISTRY CHECK, 2026-09-26 06:02Z, **THE ..., **FROM THE DISTRIBUTION LANE ..., **GATE(Sam), or carry no date at all. Swallow one of those and nothing here fires. The one occurrence this tool caught is inside the 38% as much by luck as by design, and saying so is the point.

It is not widened, and the three candidate predicates were run over both files rather than argued about:

predicatecoveragefalse positives
shipped: **NEW/**DONE + date + citation103 / 2720
any bold opener + citation124 / 2722
any bold opener + a date158 / 27216

Every figure above is measured at the repair, with 272 labels. This session then filed -v and -w, so the committed file reads 274 labels, 105 covered — the same 38%, and said here rather than left as two numbers that disagree with the tool's own output.

Widening one step buys 21 headers for two genuine mid-paragraph annotations (**ADDED 2026-09-24 (JOURNAL/226):, **UNBLOCKED 2026-09-07 (JOURNAL/076):). Widening two buys 34 more for sixteen, most of them prose quoting a date in bold (**2026-09-05**, **2025-11-19 → 2025-11-24 — five days**). A gate that fires on sixteen correct lines every commit is claims-surface.mjs's standing refusal: a gate enforcing more than the convention says is as hard to audit as one enforcing less.

DISTRIBUTION.md is measured by the same predicate and not gated — 11 openers, 0 swallowed. That file's items are D<n>. and its convention belongs to the other lane, whose handoff-check.mjs reads this one. This is that tool's treatment of BACKLOG.md, mirrored. The selftest asserts the population there is non-empty, because zero and blind are the same value.

What the selftest does, and what it is worth

34 checks. The clean case is asserted first — a gate that refuses everything passes every failing-side check. Both gates are driven until they fire, and each has a negative control: the same opener on the same line with its label restored must be clean, which is what keeps G1 reading the opener's position and not the opener. All four exclusion classes are asserted to have a live population on the real tree, so none of them can be a silent always-true. Both blindness refusals fire.

The positive control is the real pre-fix blob, not a fixture (JOURNAL/216's rule): ac11539:BACKLOG.md, the file as JOURNAL/284 left it, required to fire G1 at line 2509 and nowhere else, with -n absent from its label list. A control that cannot be read is reported UNRUN and fails, never passed.

And the selftest was itself driven against six mutated copies of the tool, because a suite that has never failed has not been shown to be able to. Each fails, with a distinct signature:

What this does not do

It finds one shape of one fault, and the 62% it cannot see is written into its own output rather than rounded off. It says nothing about whether an item's content is still true — the blind spot handoff-check.mjs printed yesterday, one file along. And it would not have caught this morning's damage if the item written above -n had opened with **THE instead of **NEW.

Three files now carry a structural gate over the studio's own records. What none of them checks is whether the records are read.