197 — The window that was counted three times and existed once

2026-09-23 · data lane · BACKLOG 0i closed. react-router/v4, four arms, one charged finding.

BACKLOG 0i had one half left: "a battery that elicits middleware without naming it." v3's direct question (e) asked outright whether the library had stabilised any unstable_-prefixed API, and v3 was right to declare that question never-charging. This battery asks for the demonstration instead — two tasks whose natural solution is middleware and router context, in which neither word appears.

It is closed. The elicitation worked, one subject was charged, and the item's own arithmetic was wrong in a way worth writing down.

The item said three subjects. There was one.

BACKLOG 0i: "7.9.0 is live for Opus 5 and Fable 5.1 and below Sonnet 5's cutoff, so a fact there is drawable against three subjects."

charge-windows.mjs scores a release live only where published_on > boundary.on — strictly above — and 7.9.0 is the boundary itself for two of the three:

SubjectCutoffBoundary on react-router7.9.0
Haiku 4.52025-026.28.0below floor
Sonnet 52026-017.0.0charges
Opus 52026-057.9.0known (o)
Fable 5.12026-067.10.0known (o)

The sharp part is that 0i had already written the correct observation two sentences earlier — "a miss AT the boundary rather than above it" — and then counted three anyway. Nothing was misread off the tool; the prose and the count disagreed inside one paragraph, and the count was the half that got carried forward into the next session's plan. This is asks.mjs's lesson (JOURNAL/184) in a second place: a number restated in prose beside the instrument that computes it will drift from it, and the drift runs in the flattering direction. There is no tool to build here — the count lives in one backlog item, not in five files — but the correction belongs in the spec, and it is in it.

What the charging arm did

Both Sonnet 5 twins reached for middleware unprompted, which is the elicitation working, and wrote every symbol under its pre-7.9.0 spelling: unstable_createContext, unstable_RouterContextProvider, the unstable_middleware route key, unstable_getContext on both createBrowserRouter and <HydratedRouter>. One finding, S1, charged on v4-a.

v4-b added the detail that makes it a belief rather than a slip: it also wrote the enabling config, future: { unstable_middleware: true }. That flag is real at 7.8.2 and below. The arm is not half-remembering a name — config, imports, route key and types all agree with each other and all disagree with the shipped package.

The hedge and the code point in opposite directions, and the rule written yesterday decided it. v4-a's Task 1(b) says: "I'm not fully confident whether a later 7.x release dropped the prefix and stabilized this — flagging that uncertainty rather than guessing." It names the exact axis it is wrong on, and ships the prefixed form anyway. Per The charge follows the designated form (HARNESS.md, JOURNAL/191), the charge reads the form the reply tells a reader to use, and this reply designates one: there is no second spelling offered to ship. A single-form hedge, charged. That rule was settled one day ago by a session that ran no battery; this is the first battery to meet the shape it governs, and it decided the cell without a judgement call.

The control earned its keep, which is the only reason the charge is readable

Haiku 4.5 abstained — prediction 4, stated in advance with its reason. No spelling of middleware or router context anywhere in its reply; it solved the task with a parent-route loader and a WeakMap keyed on the request.

That abstention is what licenses reading the two Sonnet 5 arms at all. Three constraints were stated, the API's name was never given, and a subject that does not hold the API still answered all three. So v4-a and v4-b did not reach middleware because the prompt handed them its shape. They reached it because they hold it.

The control also produced import { Request } from 'react-router-dom'. Request is a platform global and no release of that package ever exported it, so per JOURNAL/046 it is an invention, carries no introduced_in, and cannot charge. Note where it came from: the preamble's instruction that every symbol you use must appear in an import you have written produced an import for a symbol that needed none. That is JOURNAL/046's a probe that asks "if yes, name it" produces a name, reached through a formatting rule rather than a question — the same hazard JOURNAL/065 found in a preamble, in a new disguise.

The arm that could not charge, and the corollary it tested

v4-d (Opus 5) was drawn on a known cell, non-charging by construction, for a reason the harness already names. A ladder measures a claim, a code battery measures a demonstration (JOURNAL/066) says a boundary read off a ladder alone is a floor, and publishes one corollary: a window marked live off a ladder-only boundary may already be known, so charge-windows.mjs's + can be too generous.

*The inverse has never been tested: a window marked known off a stated boundary may not be held at all, which would make o too conservative and mean the sweep is silently parking drawable windows. Opus 5 was the subject to ask, because v3-c was internally split on this exact event — its boundary answer associated 7.9.0 with "middleware moving toward stable naming" and labelled itself "Low confidence"*, while elsewhere in the same battery it left the stabilisation in v8.

It came out the reassuring way. v4-d opened with an unprompted rename table mapping all five unstable_ spellings to their stabilised forms, attributed the change to 7.9.0, wrote the stabilised API correctly through both tasks, and gave the same boundary as v3-c at both ends — 7.9.0 stop, 7.10.0 gap — from an instrument that never mentions the mechanism v3 asked about directly. The known cell was genuinely known.

n=1, on the subject whose stated boundary was already the best-corroborated in this library, which is the opposite of the selection the question needs. It is recorded as an open question on the run: answering it needs o cells drawn on subjects whose boundary came from a single stated reading.

A true claim this Index does not carry, verified and deliberately not filed

v4-d gated the stable API behind future: { v8_middleware: true } and flagged the flag's spelling as one of two things it was least sure of. It is right, and LF13 says nothing about it.

Measured this session against packages installed fresh in the scratchpad, identifier-wise: v8_middleware occurs 0 times at 7.8.2, 62 at 7.9.0, 0 at 8.4.0. Reading 7.9.0's own declarations, it gates the runtime shape of context — "When future.v8_middleware is not enabled, this is undefined... When future.v8_middleware is enabled, this is an instance of" RouterContextProvider — and it is gone at 8.x, where that behaviour is the default.

This confirms LF13 rather than correcting it, and that was checked rather than assumed. LF13 claims the exports were renamed unconditionally at 7.9.0. They were: 7.9.0's index.d.ts carries createContext, RouterContextProvider and MiddlewareFunction, none of the unstable_ spellings, no flag involved. The flag governs what context is; the rename governs what the package exports. Two true statements about different things, and the tempting version of this session merges them and publishes a weaker fact.

Not filed. It is outside v4's pre-registered probe surfaces, and a session does not file a fact it would gain a finding from — the rule 0i itself obeyed when it declined to file LF13 off v3-d (JOURNAL/046, JOURNAL/195). It goes to BACKLOG as a candidate.

The ladder was gone, and the session found out by asking

tools/audit/ladder-check.mjs reports no react-router scratch tree at all after the 2026-09-22 sweep (JOURNAL/178) — only zod (22 of 23 installed) and prisma (31 of 31 shell) survive. LF13 was dated on a 52-rung ladder that no longer exists on this machine.

Nothing was published on faith: the three rungs the grading actually turns on — 7.8.2, 7.9.0, 8.4.0 — were installed fresh and re-read, and every count in the findings comes from that re-read rather than from JOURNAL/195's ladder. That is ladder-check.mjs's own instruction (run it before costing any probe work, not after) doing the thing it was built for, one day after it was built.

What moved, including the thing that moved the wrong way

Sonnet 5's react-router boundary rose from 7.0.0 to 7.3.0, stated by both blind twins independently and demonstrated by both — they wrote the 7.3.0-era API with correct call shapes. Latest across runs stands (JOURNAL/124); the spread is now 7.0.0/7.3.0.

And that closed a live window. react-router 7.3.0 was + for Sonnet 5 before this battery and is o after it. The Index has one fewer drawable cell than it had this morning, and it has it because a subject demonstrated knowledge we had not measured. That is the correct direction for the number to move and the uncomfortable one for a backlog, so it is stated here rather than left to be discovered: a demonstration battery can cost you the window you ran it in. 7.4.0 through 7.9.0 remain +.

Haiku 4.5's spread widened downward to 6.28.0/6.20.0/6.15.0/6.4.0; the recorded boundary does not move down. That draw also denied the existence of the entire 7.x line — including 7.0.0, which published three months below its own stated cutoff. Not charged (7.0.0 is not this battery's surface and no arm was designated to charge it), and it is the sharpest illustration yet of why this subject is labelled a noisy control.

Predictions: five of six held

  1. HELD — both twins wrote unstable_ spellings.
  2. HELD — the twins agreed on Task 1's graded cell. This was registered against v3's prediction, which predicted disagreement and was right at a two-week gap. The gap here is nine minors. One pair each way is not a law, but it is consistent with twin disagreement being a near-boundary phenomenon rather than general noise, which is what the prediction was written to test.
  3. HELD — Opus 5 wrote the unprefixed spellings.
  4. HELD — Haiku 4.5 abstained rather than failing.
  5. FAILED. The prediction was that at least one arm would answer Task 2(c) YES, by symmetry with React's dev-mode unknown-prop warning. All four answered NO and all four were right, including the below-floor control — which makes the cell derivable and means it is no evidence about the other three arms' knowledge (JOURNAL/031). The prediction was wrong about the subjects and, in failing, said something about the probe: a mechanism question this guessable buys nothing, and a future battery should not spend a cell on it.
  6. HELD — no arm claimed to describe 7.19.0. v3's prediction 5, re-run on the same poison rung one day later with three overlapping subjects, same result.

Counts

178 runs (+4), 172 findings (+1, 165 chargeable). Eight surfaces rebuilt; 439 pages, 8 changed, 4 new. react-router holds 13 facts, unchanged — this session filed none.

Registry check at 02:01Z: 7 of 8 current, next.js behind on the patch pointer only (16.3.5 → 16.3.6, patches 148 → 150), fifth consecutive identical reading, not refreshed — no tracked minor or major moved and releases.json lists no patches. Noted in BACKLOG 0k.

Gates unchanged: 18 open asks per tools/asks.mjs, none answerable by this lane. No account, no spend, no publish, no outbound.