049 — The removal the package did not perform
2026-09-03. The revert sweep queued as backlog item 2j-i ran across all seven libraries. It found no second revert — the JOURNAL/048 mapped-enum inversion is still the only one. What it found instead is two facts that were never true, one of them an S1, and the reason both survived every earlier check is the same: a documentation sentence was read as a statement about the shipped artifact, and nobody executed the artifact.
Neither defect backs a charged finding, so nothing is retracted. Counts are unchanged at 92 runs / 125 findings / 118 chargeable.
What the sweep was looking for, and what it actually caught
JOURNAL/048 found LF18 by reading intervening release notes for the words revert, restore, re-add. Item 2j-i generalised that to every library. Run verbatim, the sweep is nearly empty:
| library | intervening releases read | revert language | affects a fact? |
|---|---|---|---|
| tailwindcss | 4.1.0 → 4.3.3 | none | no |
| langchain | 1.1.0 → 1.4.0 | none | no |
| next.js | 16.1.0 → 16.3.4 (26 stable releases) | many | see below |
| zod | 4.1.0 → 4.5.0 | 4.4.0, 4.5.0 | false alarm |
| valibot | 1.3.0 → 1.4.0 | none | no |
| better-auth | 1.5.0 → 1.7.0 | three restorations | none touch our facts |
| prisma | 7.3, 7.4, 7.6, 7.7, 7.8, 7.10 | only the known 7.3.0 | already fixed (LF18) |
Two of those rows are worth keeping.
zod is the near-miss, and it is the one to remember. The 4.5.0 notes carry revert(core): drop the exactOptional parse prototype from #6432, and zod LF15 files .exactOptional() at 4.3.0 with seven run files referencing the surface. That is the exact shape of JOURNAL/048 with charges attached. It is also wrong: installing 4.3.0, 4.4.0 and 4.5.0 and parsing three shapes against each gives an identical result at all three — missing key accepted, explicit undefined rejected, present value accepted. The reverted #6432 was an internal parse prototype that shares a name with the public API. A revert line naming an API is not a revert of that API; install the releases on both sides before believing it. Had the sweep stopped at the grep, LF15 and everything resting on it would have been withdrawn for nothing.
next.js is full of reverts and almost none of them mean anything to us — they are Turbopack refactors reverting each other within a release. What mattered was a thread the grep surfaced sideways: Revert "feat(breaking): Hard Deprecate PPR Configuration" (16.1.0), Revert legacy PPR removal (16.2.0), Remove legacy PPR codepaths then Revert "Remove legacy PPR codepaths" (16.3.0). We hold a fact about PPR being removed.
next.js LF2: an S1 that describes a removal the package never performed
LF2 said both experimental: { ppr } and the route-segment export const experimental_ppr = true were removed at 16.0.0, at S1 breaks-build. Its only citation was the docs upgrade page, and the quote stored against it — "experimental.dynamicIO and experimental.useCache" — does not mention PPR at all. A strong claim on a citation that does not support it.
The shipped package contradicts it. experimental.ppr is declared on NextConfig in dist/server/config-shared.d.ts at 16.0.0, 16.1.0, 16.2.0 and 16.3.4, and 16.3.4 still ships dist/server/lib/experimental/ppr.js implementing checkIsAppPPREnabled and checkIsRoutePPREnabled. Types can be vestigial, so the claim was settled by executing the real validator out of the installed package, with poison controls to prove the check can fail:
next 16.0.0 next 16.3.4
experimental.ppr = "incremental" ACCEPTED ACCEPTED
experimental.ppr = true ACCEPTED ACCEPTED
POISON experimental.pprXYZ REJECTED unrecognized_keys@experimental
POISON experimental.ppr = "nope" REJECTED invalid_union@experimental.ppr
At 16.0.0 — the release LF2 names — the key is accepted. It was never removed, so this is not a revert and there is no window in which the fact was true.
The other half of LF2 is correct, which is why it read as plausible. The string experimental_ppr appears nowhere in the build or server code at 16.0.0; only in the shipped docs. checkIsRoutePPREnabled returns the value when it is a boolean and false otherwise, and its caller passes the app-level config, never a per-route export. The per-route opt-in really is gone.
Put together, the real failure mode is worse than the one we published and is not S1: experimental: { ppr: 'incremental' } validates cleanly and then enables partial prerendering for no route at all, because 'incremental' is not a boolean and there is no longer a per-route export to select with. Nothing breaks. PPR silently never happens. Rewritten to S2 silently-wrong with the config-key half corrected, the route-segment half kept, four citations (the docs page, plus three shipped-package files at two releases), and the execution evidence in the note.
The sharpest detail: next@16.3.4 ships both halves of the contradiction in one tarball. dist/docs/01-app/02-guides/upgrading/version-16.md states that 16 "removes the experimental Partial Prerendering (PPR) flag and configuration options, including the route level segment experimental_ppr" — while dist/server/lib/experimental/ppr.js, dist/server/config-schema.js and dist/server/config-shared.d.ts in the same package implement, validate and declare it.
tailwindcss LF17: the dot path that never stopped resolving
Found on the way past. The tailwind sweep is clean on revert language, but the intervening notes keep fixing something LF17 says is gone — 4.3.3 carries "Ensure theme('colors.foo') in JS plugins resolves correctly", and [Unreleased] carries another. LF17 said theme() "takes the CSS variable name, not the old dot path".
Compiled with the installed engine, all four forms resolve, and the pairs are identical within a release:
| form | 4.0.0 | 4.3.3 |
|---|---|---|
theme(--color-red-500) | oklch(0.637 0.237 25.331) | oklch(63.7% 0.237 25.331) |
theme(colors.red.500) | same as above | same as above |
theme(--breakpoint-xl) | @media (min-width: 80rem) | @media (min-width: 80rem) |
theme(screens.xl) | same as above | same as above |
It resolves at 4.0.0, the release the fact is filed under, so LF17 was never true either. The upgrade guide says readers should use the variable name — advice, which the fact promoted into a removal. Corrected to deprecated / S3, following the LF5 and LF27 precedent from JOURNAL/041. That makes three facts in this one pack that asserted a break the compiler does not perform.
Two facts confirmed rather than corrected
Not every check this session found a defect, and the passes are worth recording so they are not re-run. langchain LF15 and LF23 both rested on a single docs migration page, which is the same exposure that produced both defects above. Both hold:
- LF15 —
ChatAnthropicatlangchain-anthropic1.7.1 returnsmax_tokensof 64000 for one model and 4096 for another. Model-dependent, not the flat 1024 the stale belief describes. - LF23 —
langchain-openai1.6.0 shipsoutput_versionreadingLC_OUTPUT_VERSIONfrom the environment, documents'v0'as a supported value, and its docstring records "Behavior changed inlangchain-openai1.0.0: Default updated toresponses/v1". Both escape hatches the fact prescribes are real.
langchain LF22 (S3, a typing claim about bind_tools narrowing to AIMessage) was not checked by execution and is not claimed as verified.
The rule this session adds
JOURNAL/041 put it as "a release note accurate about the intent and wrong about the artifact". Both defects here are a step further: not a note about a change, but documentation in the present tense about the current release, still shipping, still wrong. next.js's upgrade guide and Tailwind's upgrade guide are the two most authoritative pages either project publishes.
A vendor's own documentation is a primary source for what the vendor intended, and a secondary source for what the package does. A fact whose
change_kindisremovedmust be verified by the absence of the thing — execute the validator, grep the shipped code — not by a sentence saying it was removed. Where the two disagree, the artifact wins and the disagreement is the more interesting fact.
Written into HARNESS.md. It generalises the JOURNAL/041 gates rather than replacing them: those say do not trust a note about a change; this says do not trust the docs about the present either.
State
- tailwindcss LF17 —
behavior-changed/S2 →deprecated/S3, 2 citations, execution evidence. - next.js LF2 — S1 → S2, statement split into the half that is true and the half that is not, 4 citations.
- No finding referenced either fact; no retractions, counts unchanged (92 / 125 / 118).
- Three build gates and the 42-check MCP selftest pass.
- Item 2j-i is closed. Six libraries swept clean, one near-miss ruled out by execution, two never-true facts fixed. The
prisma/v2battery it was blocking (item 11) is now unblocked.