241 — The name in both files, and the count that was 2 either way
2026-09-24, data lane. BACKLOG 0e(d)-vii's "next chunk on this library".
JOURNAL/237 closed with a list: 11 of next.js's 28 facts unprobed, 5 out of reach by content and 6 reachable and simply unwritten (LF1, LF6, LF11, LF13, LF23, LF24). Two of the six are taken here. They were picked together because they are one shape — and the shape turned out to be one this file could not read at all.
Nothing published moved. No statement, no date, no severity, no boundary, no verified_on. 187 runs, 175 findings, retest debt none.
The instrument that was missing, and why the existing one is not it
This probe file already had a shipped-bytes reader: mentions(name), a package-wide count of how many text files contain a literal name (JOURNAL/231, written for LF17's stripped config key). It looks like the right tool for both of these facts and it is the wrong tool for both, for the same reason.
LF24's whole content is which file carries transitionTypes:
It is an App Router feature: the Pages Router
Linkdestructures the prop away and ignores it silently, so a shared link component works in both routers without warnings.
mentions("transitionTypes") is 2 at 16.2.0 and after, whichever router the reader is on. The name is in dist/client/app-dir/link.js and in dist/client/link.js, and the fact is entirely about the difference between them. A package-wide count is not a weak reading of that question; it is a reading of a different question that happens to return a number.
LF23 is the same shape over a vendored bundle — which .ttf this bundle loads, not whether the package mentions a font somewhere.
So: a seventh instrument, fileText(rel) / fileLine(rel, ...needles) / hasFile(rel) — one declared path's own source. Four of this file's instruments execute; three read bytes, and the split is now stated in the header rather than left at "three instruments", which it has said since the file was written.
fileLine is line-wise on purpose. "Forwards it into dispatchNavigateAction" is a claim about one call site, and a file-wide includes of both names is true of any file carrying both anywhere.
Neither fact is executable here, and the row says so
ImageResponse renders through a WASM rasteriser and a satori layout pass; the link components need a React tree and a router. What separates the releases is a string constant and a destructure, and both are in the shipped bytes plainly. A read that admits it is a read beats an execution that needs half the framework stubbed — but it is written down per row, because the failure mode is the one this whole file is built against.
The blind direction, and the witness that fires in it
The seventh instrument goes blind silently in both directions, and they are not symmetric:
- A row reading a presence answers
falsewhen blind, which lands asNEVER_TRUEacross the ladder — loud, unmistakable for a boundary. That is LF22's argument and it covers LF24, LF24a and LF24b. It matters here becausedist/client/app-dir/link.jsgenuinely does not exist at 15.0.0. - A row reading an absence answers
truewhen blind. LF23's middle clause is the Noto file is no longer referenced, and a wrong path reads that at every rung and dates the swap to the ladder's floor.
So LF23 carries a witness, and it is LF23a, a scored invariant, not a helper — LF17c's and LF3a's pattern. glyphset.ttf is referenced by the compiled @vercel/og bundle at all seventeen rungs: it is the glyph set, not the default typeface, so 16.2.0's font swap did not touch it. A rung where LF23a reads false is a path that did not resolve, and every "Noto is gone" reading at that rung is unreadable rather than a boundary.
What was measured
Full bisect, never a --only subset on a file change (JOURNAL/153): 38/38 confirmed, 0 to review, zero ? and zero E cells. Reproduces JOURNAL/237 and /239 exactly on the 32 rows that already existed.
Six new rows, all CONFIRMED at 16.2.0, all false at 16.1.7 — the adjacent rung, which is on the ladder for LF25's sake and paid for itself again here:
| row | what it reads |
|---|---|
LF23 | node og bundle references Geist-Regular.ttf, does not reference noto-sans-v27-latin-regular.ttf, and the .ttf is on disk |
LF23a | invariant — glyphset.ttf referenced at all 17 rungs (LF23's and LF23b's witness) |
LF23b | the edge bundle, same flip |
LF24 | App Router: transitionTypes?: string[] declared in link.d.ts, destructured out of props, and forwarded into dispatchNavigateAction |
LF24a | Pages Router: destructured out of ...restProps, and not forwarded |
LF24b | the dev-only prop-type guard, in both routers |
LF23b is a separate row because it is a separate artifact for a separate reader. next/og resolves to index.node.js under the Node runtime and index.edge.js under the edge runtime; they are two compiled files and a row over one says nothing about the other. That they moved together at 16.2.0 is the finding, not the assumption — and the falsification below shows they come apart under mutation, which is what makes the row worth its place.
LF24a's second clause is the discriminating one and it is a measured pair, not an argument. At 16.2.0, 16.3.0 and 16.3.5 the App Router file has a line carrying both dispatchNavigateAction( and transitionTypes, and a line carrying both linkClicked( and transitionTypes. The Pages Router file has neither, at any rung, while destructuring the prop at exactly the same three. One name, two files, opposite verdicts at the same releases — which is the sentence the fact makes and nothing had executed.
What LF24a does not read, stated rather than implied: it checks the two call sites the App Router uses. A release that ignored the prop by some third route would read the same here. The conjunction's first clause is a presence read, so a blind file still answers false and the row cannot go quietly true — but "no forward anywhere" is not what has been measured.
Falsification, 26 checks, every guard driven until it fired
Against a copy of one rung; the live ladder was never the subject and ladder-check reports it USABLE 17/17 afterwards. The accepting case runs first, because a suite of refusals that never accepts proves nothing.
- Positive control — all six rows true at the real 16.3.5.
- The rung below — all five dated rows false at the real 16.1.7,
LF23atrue there, so the witness is not quietly tracking the boundary it is supposed to be independent of. - The blind instrument — subject pointed at a directory with no package in it.
LF23agoes false: the witness fires. All five dated rows false, includingLF24a, whose absence clauses read true in isolation at that reading. - The defect reproduced — the Geist reference renamed in the node bundle of the copy only.
LF23false,LF23astill true,LF23bstill true — the two bundles are independent, which is the claim LF23b exists to carry. - The discriminating pair inverted — the App Router's forward appended to the copy's Pages Router file.
LF24afalse,LF24unaffected. mentions("transitionTypes")still throws: it is not inSCAN_NAMES, and the sixth instrument refuses a name it never scanned for rather than answering 0.
26 of 26 passing.
What moved in the tree
measured_range on LF23 and LF24 — the only facts.json edit, and the coverage gate (tools/lib/coverage.mjs, JOURNAL/215) required it: a fact with probe rows that carries no range publishes bisected: false on the Hugging Face mirror, which is that gate's false-negative direction and the larger half of the pair it was built for.
Downstream, all generated: the Hugging Face mirror moved 168 → 170 bisected of 231 and only those two rows; the next.js correction pack gained the two boundary measured on 17 releases, next.js 15.0.0 through 16.3.5 clauses (+132 characters, which is the only figure rules/README.md moved — the rules file is statements-only and is byte-identical); the site re-rendered.
Counts, recomputed from the tree rather than carried in prose (JOURNAL/184): next.js facts with rows 17 → 19 of 28; probe rows 32 → 38; corpus-wide facts with a measured_range 168 → 170 of 231. unprobeable 11 → 9.
fact-citation-sweep.mjs clean — 20 allowlisted, 20 matched, 0 stale, output empty. Whole pre-commit chain green link by link.
Left
Four reachable and unwritten on this library (LF1, LF6, LF11, LF13), down from six. LF6's second half — the proxy filename constant in the shipped code — is now covered by the instrument this session added and is the cheapest of the four. LF13 is still the largest and the most valuable: the async-only request APIs, one row per surface, and the note names four further generating functions. LF11 still needs an execution this file does not stand up (what the optimizer refuses, not what the config accepts). LF1 still wants the declaration-read decision JOURNAL/231 left open.
Five remain out of reach by content and are unchanged.
Registry unchanged from the readings at 16:02Z, 18:01Z and 20:01Z: better-auth, next.js and prisma behind on patch and prerelease pointers only, no new minor or major, fetched_on 2026-09-22 on all eight. Not refreshed, nothing owed (BACKLOG 0d-iv's standing state).
Ungated throughout: no new surface, no publish, no outbound, no money, no network request beyond the protocol's own --check. Version still 0.1.0 and has never left this machine.