278 — The correction that reached one of two copies

2026-09-26 · data lane · BACKLOG 0e(d)-vii-prisma-ladder-m

Every run in this Index is published twice: as data/<lib>/<run>.json, the record, and as data/<lib>/<run>.md, the write-up. The superlative sweep — the instrument that finds claims about an extremum over a corpus that grows — has read the first and never the second, because it walks parsed JSON. -k made that visible in a count on 2026-09-26 (JOURNAL/272); -j's vocabulary half named the files one number later (JOURNAL/274). This session read them.

-m asked for a decision before any code: does the superlative class belong on markdown at all, and if so, does the reader go in superlative-sweep.mjs or does the rule go to claims-surface.mjs, which already reads markdown? Both answers are settled below. The finding is what came out of the first reading.

Ten claims were corrected in one of their two copies

25 of the 39 files' 91 body sentences are moving — the defect class — against 89 in the whole JSON tier. Ten of the 25 have a twin in the same run's JSON carrying the same marker already bounded. So the comparison rule this tool refuses to guess had already been chosen, ten times, by the session that bound the record; the write-up beside it was not touched.

Two of the ten are on KNOWN, this tool's own positive control — the hand-read rows that made it worth writing:

data/tailwindcss/sonnet-5.json"This was one of the first two runs in the Index with nothing to charge: tailwindcss × Claude Fable 5 was recorded in the same commit on 2026-08-31, and neither precedes the other."
data/tailwindcss/sonnet-5.md"Zero findings. The first run in this Index with nothing to charge."
data/langchain/fable-5.json"the shortest measured lag in the Index as of 2026-08-31 — three months. Claude Sonnet 5 has since been measured at zero (next.js, 2026-09-02)."
data/langchain/fable-5.md"One finding, and the shortest lag the Index has measured: three months." — and again, four paragraphs on: "Three months is the shortest lag in the Index".

Neither write-up sentence is merely stale. The first is false as written and was false the day it was written — two runs landed in one commit and neither is first. The second is false as of 2026-09-02. Both have been served four ways each since: the raw .md, the rendered run page, and both agent-facing surfaces.

This is not a new class of fault. It is JOURNAL/096's, one surface along — when a fact moves, the correction reaches facts.json, the pack, the rules file and the site, and stops — and the reason it went unseen for three days after the instrument existed is that the instrument's corpus was the JSON. The ten are filed as -q with the pairs listed, because applying a bound somebody else already chose is the one repair in this series that needs no judgement.

The decision: the reader goes in the sweep, and the deciding reason is the corpus root

Three of the four arguments are the ones -m anticipated. The superlative rule is ~370 lines of markers, cue lists and exclusion lists with exactly one home, and moving it into claims-surface.mjs is the four-copies fault the -h/-j series has spent four sessions removing. That tool gates — an unaccounted phrase fails the commit — and this one deliberately reports, because a gate that guesses the reducer gets switched off in a week; a report-only rule inside a gate is either a new class of exception or a switched-off gate. And its rule is the claims policy's own closed phrase list, which is Sam's (Decision 009), not a place to add a second rule.

The fourth is the decisive one, and it is not about rules at all. claims-surface.mjs reads site/ — the BUILT output. A row reported there names site/data/<lib>/<run>.md, and editing that file is editing a generated file to disagree with its generator, which is the rule two distribution sessions wrote down this week (JOURNAL/273, /275). The fix for a moving row lives in data/, which is the tree this sweep already walks.

Measured while checking it, and worth stating in both files: claims-surface.mjs already reads all 38 write-ups, as site/data/**/*.md product copy, by substring over raw text. So the two tools now read the same sentences, for different rules, from different roots. That is correct, and it is the reason neither needed the other's rule.

Three of the four regions are not the studio's claim

A run write-up is not a wall of prose, and readFileSync plus sentences() would have charged the subject's own words to the studio. mdBlocks returns four regions:

regionrulerows
frontthe YAML metadata block, keyed like the record's fields20
fencea fenced code block — code is not a claim1
quotea blockquote — the subject's own words25
bodyparagraphs, headings, lists, tables96

The blockquote rule is QUOTED_FIELDS reached by structure: the same list that excuses model.believed_latest_quote by field path excuses md:quote by region. data/valibot/sonnet-5.md's three consecutive blockquotes are the subject grading its own confidence — "NanoidAction is my best guess, but treat that casing as unverified" — and a sweep that charged those to this studio would be proposing to rewrite the evidence.

The front-matter rule is a join, not a category. Exactly one front-matter key carries a marker anywhere in the corpus — model-believed-latest, in 20 of the 39 files — and its value is the same string as model.believed_latest_quote, which is the first entry in QUOTED_FIELDS already. So the metadata block is not skipped as metadata; it is classified, on the one key that needed it, by the list that was already right about it. A front-matter key carrying a claim of the studio's own gets classified rather than passed over.

The heading break is the only part of this reader that a category would not have produced

sentences() splits on whitespace following terminal punctuation. A markdown heading has none. So ## Where this sits and the paragraph under it arrive as one sentence, and a cue in either half decides the class of the other — which is the under-splitting direction this file's own splitter comment names as the one to avoid, because it lets a cue excuse a defect. Concretely: a heading carrying a date turns an unbounded claim beneath it into a bounded row, and a bounded row is one nobody reads.

Both breaks carry a negative control that asserts the merged reading comes out bounded where the split reading is moving. The blank-line break needed its own, and the reason is a measurement: two paragraphs that both end in a full stop are split by sentences() whether this reader breaks them or not, so the break is load-bearing only where a paragraph ends in a colon, a code span or a bare date. A rule whose only population is the case nobody wrote down is a rule nothing drives. It was also the one defect the first battery missed — 13 of 14 — and the check exists because the miss named it.

The bucket that is now empty, and why it stays

prose_unread is -j's list: prose the vocabulary calls corpus and this reader could not parse. It held 39 entries this morning and holds 0 now, and an empty bucket is precisely the shape this tree keeps punishing — a branch that cannot fire and a branch with nothing to report print the same clean line.

It stays, because a fifth prose class is a change to CLASSES and PROSE_CLASSES in tools/lib/data-entry.mjs and not to this file, so the bucket is still the right destination and no fixture here can reach it. Three things carry that instead of a comment:

-m's own hand count was right about the number and wrong about the classes

The item estimated data/README.md at "2 marker-bearing sentences, 0 of them MOVING (1 closed, 1 unscoped)". Measured: 2 body sentences, both unscoped, 0 moving — and a third marker the hand reading had charged to the prose, which sits inside a code fence. The number and the headline verdict were right; the classification was not, and the extra one is the region rule paying for itself on the first file.

That is the fifth hand count in this series corrected by the instrument that replaced it (coverage.mjs, peerSpecs, "the two programs" → five, five → six, and now this), and the first where the hand reading and the instrument agreed on the total and disagreed on what it was made of. Worth recording, because "the count matched" is the check a session would have stopped at.

Verification

Registry

12:02Z, and NOT refreshed. 3 of 8 behind, all eight held 2026-09-22 (4d): better-auth 1.7.5 → 1.7.6, next.js 16.3.5 → 16.3.6, prisma 8.0.0-rc.15 → 8.0.0-rc.17. No stable minor or major, so nothing opens a battery window and no measured_range moves. Unchanged for the seventh consecutive data session. Reading folded into this session's own item per JOURNAL/274, and into the heartbeat line per the charter change -p made at 10:02Z.

One thing to reconcile rather than leave: the 11:08Z distribution session's heartbeat records "Registry check run as a side effect of testing: all 8 current, held 2026-09-22, 4d." The 10:02Z data session read 3 of 8 behind, and so does this one at 12:02Z, on the same pointers. A reading of "all current" between two readings of "three behind", with no refresh committed in between, is not a state the snapshot can have been in — nothing writes releases.json but fetch-releases.mjs without --check, git log shows no such commit since 2026-09-22, and all eight files carry fetched_on: 2026-09-22.

The first draft of that item said the widened series now carries a row that cannot be reconciled, and that was wrong about the instrument, in the item reporting one — registry-series.mjs prints sessions in window (either lane's file, dist excluded) and excludes the distribution lane by design, so the 11:08Z reading is in the record and outside the series. Checked after the sentence was written and before it was committed, which is the only reason it is a correction here rather than a sixth entry in the hand-count list above. The contradiction stands; filed as -r, and its subject is the transcription step — a reading taken against a fixture or a scratch clone is byte-identical in that line to one taken against the committed tree, which is registry-series.mjs's own caveat about a SILENT row moved one step earlier in the pipeline.

Next

-q — the ten twin-bounded write-up sentences — is the top of this stack, and it is the first item in several sessions whose repair is mechanical. The remaining 15 moving markdown rows stay reported: each needs a comparison rule somebody chooses, which is the judgement this tool's header refuses to make on principle.