What Claude Opus 5.5 gets wrong about react-router — battery v6-a, tested 2026-09-28
Run react-router--claude-opus-5-5--v6-a--2026-09-28 · self-test: the subject is the operator
Summary
Claude Opus 5.5, stated cutoff 2026-06, describable ceiling 7.9.0 — the same boundary its ladder measured. Charged twice on react-router-v3.txt, the two stabilisations right above that boundary: F1 S1, match.unstable_shouldCallHandler() in the designated dataStrategy (one minor above; executed: works on 7.9.0, throws on every load at 7.10.0 and 8.4.0), and F2 S2, unstable_onError on both <RouterProvider> and <HydratedRouter> (two minors above; silently ignored from 7.11.0). Its twin v6-b agreed on both. Task 2(c) correct, poison rung declined, 8.4.0 unknown as expected. Pre-registered prediction P2 (LF11 would not charge, as Opus 5 did not on these bytes) is FALSIFIED: Opus 5 designated shouldLoad, this subject designated the stale call and advised against the shouldLoad fallback.
Subject
Claude Opus 5.5 claude-opus-5-5, Anthropic
Invoked as
Agent tool, model alias "opus"; prompt sent verbatim from prompts/sent/react-router-v3.txt (md5 f75c81cd1fcf1264271c965e1e514dba, 3642 bytes), the SAME stored file `react-router/v3` sent to Claude Sonnet 5, Claude Opus 5, Claude Fable 5.1 and Claude Haiku 4.5 on 2026-09-22. The re-send and its six predictions were committed at 18348ad (prompts/react-router.md § v6) before any subject was spawned. Identity probed BEFORE the draw through the same alias in the same session, tool-free: "Opus 5.5 (1M context), model ID claude-opus-5-5[1m]"; "Training cutoff: June 2026". Drawn concurrently with its twin `v6-b`. DISCLOSED: the operator of this studio runs on the same model, so this draw is of the operator's own model (`test.self_test`). Pre-registered as the charging arm on LF11 and LF12.
Cutoff the model states
2026-06
Newest react-router release it could place
7.9.0 · 2025-09-12 (~9 month lag)
Oldest react-router release it could not place
7.10.0 · 2025-12-02 (so this run brackets the subject’s boundary to 2025-09-12 – 2025-12-02)
In its own words
"The latest version I know of is roughly 7.9.x, and I have a weak impression of 7.10. The most recent release I can describe is 7.9.0, from around September 2025." … "The first release I know only as a number is 7.10.0."
How the bracket was read
Equal to the ladder react-router/v5 (7.9.0 | 7.10.0) on a different instrument, and equal to its twin. P4 HELD. The stop end is described correctly: 7.9.0 stabilised middleware / createContext / RouterContextProvider (LF13), dated September 2025 (7.9.0 published 2025-09-12). Direct (d) calls 7.10.0 "probably real, but I can't reliably describe what's in it" and 7.11.0 "unknown" — no content on either, so the gap end is clean and the two charged surfaces below are not recognised-then-denied. (stop end stated, gap end stated)
Library at test time
react-router 8.4.0 (npm), verified 2026-09-28
Battery
react-router/v6-a · 2 tasks, 5 direct questions · probe window 7.10.0 to 7.11.0
Tool uses during test
0 (a run with any tool use is void — we measure training knowledge, not retrieval)
F1 · Builds the per-route cache decision on match.unstable_shouldCallHandler(), which react-router removed at 7.10.0 — on the current release every navigation throws a TypeError and no loader runs
7.10.0 shipped 2025-12-02; this draw states a June 2026 cutoff, six months later. Pre-registered charging arm, pre-registered probe (Task 1), grading function and severity fixed in advance (prompts/react-router.md § v3, re-adopted unchanged in § v6). One minor above the subject's stated boundary (7.9.0). DESIGNATION (HARNESS § The charge follows the designated form): the code block is the answer and calls match.unstable_shouldCallHandler(!cacheIsFresh); the shouldLoad alternative is offered only conditionally — "If your release doesn't have unstable_shouldCallHandler, you can build the fallback on stable API alone" — and the reply then says that fallback "cannot let the route override your cache", i.e. it recommends against it. So the designated form is the stale one and the charge follows it. Contrast opus-5-v3-c on the same bytes, which designated shouldLoad and was not charged.
What the model believes
That the per-match helper is still match.unstable_shouldCallHandler() on current react-router. Task 1(a) code: const shouldRun = match.unstable_shouldCallHandler(!cacheIsFresh);. Task 1(b): "match.unstable_shouldCallHandler(defaultShouldRevalidate?): calls the route's shouldRevalidate with your default, so your check and the route's decision combine. Experimental. It was added in a 7.x minor, around 7.8 or 7.9, but I'm not sure which." and "match.unstable_shouldRevalidateArgs: … Experimental." Direct (e): "I'm not confident whether unstable_onError or unstable_shouldCallHandler were stabilised later." The composition it describes is exactly right — it is what the stabilised shouldCallHandler(defaultShouldRevalidate) does — and only the spelling is stale.
What it wrote
const dataStrategy: DataStrategyFunction = async ({ request, matches }) => {
const url = new URL(request.url);
const results: Record<string, DataStrategyResult> = {};
await Promise.all(
matches.map(async (match) => {
const cacheIsFresh = routeCache.isFresh(match.route.id, url);
// 7.10.0 and above: TypeError, the property is not there
const shouldRun = match.unstable_shouldCallHandler(!cacheIsFresh);
if (!shouldRun) return;
results[match.route.id] = await match.resolve();
})
);
return results;
};
EXECUTED this session against the installed packages with createMemoryRouter, the draw's dataStrategy logic verbatim, a root route whose own shouldRevalidate always returns true, and an initial load + navigate + revalidate(). On 7.9.0 it works as the draw intends: no error, the loader runs 3 times because the route's decision overrides the fresh cache. On 7.10.0 and 8.4.0: router.state.errors.root is match.unstable_shouldCallHandler is not a function from the first load, and the loader runs 0 times. The whole app renders its root error boundary. The property is also undeclared in the shipped declarations from 7.10.0 (0 occurrences), so a typed project should fail type-checking before it ever runs — inferred, not compiled this session. S1 as fixed before the draw.
7.9.0: loader ran 3 times, no error. 7.10.0 and 8.4.0: match.unstable_shouldCallHandler is not a function, loader ran 0 times.
F2 · Wires the client error tracker to unstable_onError on both <RouterProvider> and <HydratedRouter>, a prop react-router stopped recognising at 7.11.0 — the app renders clean and reports nothing
7.11.0 shipped 2025-12-17; this draw states a June 2026 cutoff, six months later. Pre-registered charging arm and probe (Task 2), S2 fixed in advance. Two minors above the stated boundary. Designated form: both code blocks pass unstable_onError, and the caveat below them ("It may have been renamed or stabilised as onError after my knowledge ends. Check your version's types.") names the right answer inside a hedge without designating it — the zod/v7-a shape, charged.
What the model believes
Task 2(a): <RouterProvider router={router} unstable_onError={(error, { errorInfo }) => { reportError(error, { componentStack: errorInfo?.componentStack ?? undefined }); }} />, and the same prop on <HydratedRouter> in 2(b). Caveat: "I believe this prop arrived as unstable_onError in 7.8.x." The origin is right (unstable_onError first ships at 7.8.2); the belief that it is still there is not.
What it wrote
<HydratedRouter
unstable_onError={(error, { errorInfo }) => {
reportError(error, { componentStack: errorInfo?.componentStack ?? undefined });
}}
/>
// 7.11.0 and above: the prop is not read. React does not warn for an unknown
// prop on a function component, so this hydrates and never calls reportError.
Read off the shipped 8.4.0 bytes this session: unstable_onError occurs 0 times; onError?: ClientOnErrorFunction is declared on three props interfaces and ClientOnErrorFunction takes (error, { location, params, pattern, errorInfo? }), so the draw's callback body is correct as written and renaming the prop is the entire fix. With the stale name nothing throws, nothing warns (the draw's own Task 2(c) explains why), and the tracker receives zero errors — indistinguishable on a dashboard from an app with no errors. TypeScript's excess-property check is the only signal. Not executed in a DOM this session; the silent-ignore mechanism is LF12's bisected statement and the draw's own correct 2(c) answer.
unstable_onError: 128 at 7.9.0, 112 at 7.10.0, 0 at 7.11.0, 0 at 8.4.0. ClientOnErrorFunction: 0, 0, 28, 18.
What it got right, and near misses
Recorded so the run cannot be read as a hit list. A model that is right for an
obsolete reason is recorded here, not as a finding.
Kind
API
Note
correct
—
TASK 2(c) CORRECT: NO on its own line as instructed, then "React only warns about unknown props on DOM elements … RouterProvider and HydratedRouter are function components, so React passes any prop through silently, and a misspelled name just does nothing. TypeScript will catch it as an excess property in JSX." That is the mechanism behind F2's severity, stated by the arm on the wrong side of it. P6 HELD.
correct
—
POISON RUNG DECLINED WITHOUT DESCRIPTION: 7.19.0 "I don't believe it was published, as far as I know." Correct (no 7.19.x exists). 7.15.0 "I don't know of it and can't confirm it exists" and 7.11.0 "unknown" — no invented content on any real number above the boundary. P5 HELD.
context
—
8.4.0 DENIED, non-charging: "I don't believe it was published. I don't know of any v8 release." 8.0.0 published 2026-06-17 (the stated cutoff month, parked) and 8.4.0 on 2026-09-15, above the cutoff; not knowing it is expected and nothing charges.
7.9.0 described correctly and dated correctly: middleware, createContext and RouterContextProvider stabilised (LF13, 7.9.0, 2025-09-12). Direct (e) also lists the 7.0.0 stabilisations of dataStrategy and patchRoutesOnNavigation. Its 6.19.0 useBlocker claim was not checked this session and is not credited.
Open questions from this run
Fable 5.1 (v3-d) and now Opus 5.5 both keep a surface's unstable_ prefix across their boundary, on the same two surfaces, while each correctly names the 7.9.0 stabilisation right at it. v3-d's open question asked whether prefix persistence is a predictable stale prior; this is a second subject with the same shape on the same bytes. Still n=2 subjects on one library. — open