217 — The three releases nobody had ever run

2026-09-23 · data lane · BACKLOG 0e(c)

react-router was the last ladder the reach check called GAPPED: releases.json published 6.25.0, 6.30.0 and 8.3.0 as tracked stable minors and the probe file's hand-typed ladder skipped all three. Three rungs installed, ladder 52 → 55, REACHES, full bisect 54/54 confirmed, 0 to review. Every ladder the Index has now contains every release it publishes for that library.

What the gap was worth: nothing, and that is the result

Zero of 162 new cells differ from the rung below them (54 rows × 3 rungs), computed off the grid rather than eyeballed. No boundary was hiding in the gap; nothing published moves. This is the same shape as better-auth 1.7.0 (JOURNAL/185) and react-router 8.4.0 (JOURNAL/181) — the question had never been asked, and the answer is that the three releases changed nothing these fourteen facts claim.

8.3.0 is the one worth naming, because it is the case --reach's rule 2 was written for (JOURNAL/183): the ladder already carried 8.3.1, 8.3.0's own patch tail, and a minor sampled by its patch tail is not sampled. Every top-of-ladder check reads that as clean. The two 6.x rungs are the other shape — the 6.x line is deliberately sampled rather than exhaustive, so they were a judgement rather than an oversight; but releases.json publishes them, and the unit of the reach check is the tracked release, never the ladder's ceiling.

The second finding, and it is the one that was already published wrong

Re-running the whole ladder made every measured_range in data/react-router/facts.json stale, so they were recomputed from this run's cells rather than from the ladder's length — which is what caught the thing a careful copy gets wrong.

Nine facts were understating their coverage and had been since 2026-09-22. They read 6.4.0..8.3.1, 51 rungs. 8.4.0 was added to the ladder on 09-22 (JOURNAL/181) and a full bisect ran over it; nobody updated the field. JOURNAL/215's twenty-six false negatives, one order of magnitude smaller and by the same mechanism: the coverage a fact claims and the coverage a fact has are two different things, and only one of them is joined to anything.

One fact was overstating it, and that is new. LF14's range said 6.4.0..8.4.0, 52 rungs. Its four rows do not agree about how far down they can see: three read every rung, and LF14c is E on all sixteen 6.x rungs — that line ships no root declarations export list, so the instrument is blind there, which is not the same as the type being unexported (identifiers.mjs's rule, in the bisector's own vocabulary). The range over which LF14's whole statement was executed is 7.0.0..8.4.0, 39 rungs.

That is tailwindcss LF28's rule — the range is a property of the arm, not of the harness (JOURNAL/215) — reaching a fact whose rows disagree with each other, which LF28 could not test because it had one arm. Applied here the reading is the intersection: a range claiming 6.4.0 publishes a measurement at 6.4.0 that one of the fact's four clauses never had. The alternative — the union, "some row read down to here" — is the sentence JOURNAL/215 refused in the tailwindcss case in exactly these words: applied to all four it would have published a measurement at 3.4.17 that never ran.

The published pack now reads "boundary measured on 39 releases, react-router 7.0.0 through 8.4.0" where it read 52 and 6.4.0. That is the only fact in the corpus whose coverage got narrower on a re-measurement, and the reason is in its note rather than only here.

What did not move

No statement, date, severity, boundary or change_kind. verified_on deliberately not moved on any fact — coverage metadata was recomputed and nothing was re-checked against a primary source. data/index.json is byte-identical to HEAD (measured_range is not projected into it), so runs stay 178, findings 172, facts 231. In hf/facts.jsonl exactly 13 of 231 rows changed and measured_range is the only field that moved in any of them — differentialled row by row against HEAD, not asserted; bisected and measured_by are unchanged because all thirteen already named the bisector.

fact-citation-sweep.mjs per the standing rule after a fact file moves: 488 api joins, 8 allowlisted, 0 stale. Full pre-commit chain green; site 458 pages.

Found on the way

build-site --check fails if build-rules runs after it — rules/README.md is written by build-rules and copied by build-site, so the chain has an order and running the six builds in the order they are listed in CLAUDE.md is not it. Cost a minute and no data; noted because the next session that rebuilds everything by hand will hit it too. The check caught it, which is the pre-commit chain doing its job.

Registry check

2026-09-23 22:02Z: 7 of 8 current; next.js BEHIND on the patch pointer only (16.3.5 → 16.3.6, patches 148 → 150). Fifteenth consecutive identical reading. Not refreshed: no tracked minor or major has moved and releases.json lists no patches, so a refresh would move fetched_on stamps and nothing else. This session worked react-router against releases releases.json already tracks — the three new rungs are all in it, which is why they are rungs — and needed no refresh to do it. Re-read at the end rather than quoted from the opening, per JOURNAL/215.

Gates

18 open asks (node tools/asks.mjs, not counted by hand), unchanged, none answerable by this lane. No account, no spend, no publish, no outbound, no new surface. The deploy is the standing routine-data-deploy approval (Decision 007).