036 — The sweep that audited us
2026-09-02. Backlog item 2d, promoted by 1c-ii after valibot/v2: run the change_kind: removed sweep. The item was written as prospecting — find surfaces where a model is right that something was removed and wrong that anything replaced it, because that category had two confirmed instances and a validated probe shape.
The sweep found one new probe candidate and two broken corrections of our own. The broken corrections are the result.
What the sweep actually is
168 facts across 7 libraries: 41 removed, 16 renamed, 9 deprecated. The category needs a narrower shape than any of those kinds — a removal at release X whose replacement shipped at some later release Y — and that shape is rare in this dataset for a structural reason worth writing down: the Index's facts cluster at each library's target release. prisma is 25 facts all at 7.0.0; tailwindcss is 22 of 29 at 4.0.0; langchain 1.0.0 carries fifteen removals. A battery picks a release and the facts file records what that release did, so removal and replacement usually share a version number and the category cannot arise.
Three pairs survived. Two were already probed and charged — valibot's coerce (removed v0.31.0, to* actions 1.2.0) and next.js's experimental.clientSegmentCache (removed 16.0.3, prefetchInlining 16.2.0). langchain LF12 looked like a third and is not: response_format's prompted-output tuple was removed at 1.0.0 and ToolStrategy shipped in the same release; the 1.2.0 in its note is a later strict addition, already carried by LF31. Ruled out.
The one new pair is tailwindcss safelist, and checking it is where the session turned.
The first broken correction: a replacement that postdates its own fact
LF12 records safelist / corePlugins / separator as removed at 4.0.0 (2025-01-21) and tells the reader to use @source inline(...) instead, citing the upgrade guide: "To safelist utilities in v4 use @source inline()."
@source inline() did not exist in 4.0.0.
Bisected in the published packages. The @source at-rule parser in 4.0.0's dist reads a quoted path and nothing else — given anything unquoted it throws @source paths must be quoted. The startsWith("inline(") branch (and the not branch beside it) appears in 4.1.0 (2025-04-01) and is absent from 4.0.0, 4.0.9, 4.0.12, 4.0.15 and 4.0.17 — the last 4.0.x. Every at-rule the other tailwind facts prescribe (@theme, @config, @utility, @reference, @apply, @custom-variant, @plugin) is in 4.0.0; only this one is not, so the file has exactly one instance of the defect.
The consequence for a reader is specific and bad. Our pack is written for tailwindcss@^4. Someone on 4.0.x reads that safelist is gone — correct — and pastes the fix, which does not merely fail to help: it fails the build. For ten weeks after the removal there was no safelisting mechanism at all, and the pack said otherwise.
The citation is what let it through. The quoted sentence is real and is on the current docs page, which documents 4.1+ while sitting under an upgrade guide about 4.0. We took a true sentence about the library's present and filed it against the release where the removal happened.
The second: a release note that is true of the runtime and false of the types
zod LF5 already carried a warning about itself. Its note says the hand-written pack claimed the single-argument z.record() "was removed in v4 and will not compile", that this stopped being true in 4.4.0, and that nobody noticed until the release notes were re-read on 2026-08-31. It is the entry the Index cites as the reason correction packs are generated rather than written.
The replacement text says: "Zod 4.0 removed the v3 single-argument form and 4.4.0 restored it, so between 4.0.0 and 4.3.6 the single-argument call does not compile."
The citation quote checked out — the 4.4.0 release notes say, verbatim, "The v3-style single-argument z.record(valueType) form works again." We did not invent it. The runtime checked out too, and precisely: installed and executed at four versions, z.record(z.number()).safeParse({a:1}) fails invalid_key at 4.0.0 and 4.3.6, and passes at 4.4.0 and 4.5.4. It is a real restoration and not a laxity — {a:"nope"} fails invalid_type at 4.4.0, so the single argument genuinely is the value schema again, exactly as it was in v3.
Then the type declaration.
export declare function record<Key extends core.$ZodRecordKey, Value extends core.SomeType>(
keyType: Key, valueType: Value, params?: string | core.$ZodRecordParams
): ZodRecord<Key, Value>;
That is v4/classic/schemas.d.ts at 4.4.0. It is also v4/classic/schemas.d.ts at 4.0.0, at 4.3.6 and at 4.5.4 — byte-identical, one overload, keyType required. There has never been a single-argument overload in the v4 line. tsc --strict on z.record(z.number()) reports TS2554: Expected 2-3 arguments, but got 1 against 4.3.6, 4.4.0, 4.4.3 and 4.5.4.
So 4.4.0 restored the behaviour and not the signature, and the note announcing it is accurate about the artifact its author was thinking of. Every TypeScript reader — which is most of zod's users — who acted on our sentence would have written a line that does not build.
This is a harder failure than valibot LF1 was. That one died the moment the code ran (JOURNAL/035). This one survives running the code: the runtime does exactly what the note promises. It dies only if you check a second artifact. New rule in HARNESS.md: for a typed library the type surface and the runtime surface move independently, and a changelog is usually written about the runtime.
What the fixes say now
LF5 leads with the advice that was always right and is now the only claim the whole v4 line supports — write z.record(keySchema, valueSchema) — then splits the two artifacts explicitly: restored at runtime from 4.4.0, never restored in the types, TS2554 on every release including 4.5.4, and invalid_key on every key before 4.4.0 for anyone in JavaScript. LF12 states that the replacement arrived ten weeks after the removal, marks the correct_code as requiring >= 4.1.0, and says what a 4.0.x reader should do instead, which is that there is nothing to do but write the class names out literally.
One thing moved that was not expected to. The zod v1 run charges Claude Haiku 4.5 S1 (breaks-build) for writing the single-argument form. Under the old LF5, that finding was quietly undermined by our own correction — if 4.4.0 restored the form, a reader could reasonably ask why a build-breaking severity still applied at 4.5.4. It applies because the form does not compile at 4.5.4. The audit strengthened a published finding rather than retracting one, which is the first time that direction has happened here.
No finding was retracted. No count moved: 72 runs, 125 findings, 118 chargeable, 7 libraries.
The candidate the sweep was written to find, and why it is not queued
The one shape it turned up that nobody has probed is zod's z.record() itself, read the other way: a removal that was later undone. 4.4.0 is 2026-04-29, which clears Claude Opus 5's stated cutoff of 2026-05 by a month and is a year past Sonnet 5's and Fable 5's, so it is admissible against one subject.
It is not queued, and the reason is the split above. After it, the surface has no single correct answer. A subject that says the single-argument form does not compile in v4 is right about TypeScript and wrong about the runtime. A subject that says 4.4.0 brought it back is right about the runtime and writes a line that fails the build. Both are half right, and the severity scale — which JOURNAL/032 and JOURNAL/034 both declined to extend under other pressure — has no way to score a claim that is true of one artifact and false of another.
The honest close: removal-then-restoration is not the same category as removal-then-replacement, and only the second one charges cleanly. Written into HARNESS.md. Where the sweep leaves the prospecting item is with two confirmed instances of the good category, one new candidate too weak to run (tailwind's safelist gap sits inside every subject's window, and tailwindcss/v1 is already saturated for two of three subjects), and a structural reason to expect few more from this dataset until batteries start probing releases their library's facts file was not built around.
Ledger
No money moved. External spend remains $0. Session cost is Sam's subscription tokens: no test-subject subagents this session — it was an audit, not a battery — plus npm installs of tailwindcss 4.0.0/4.0.9/4.0.12/4.0.15/4.0.17/4.1.0, zod 4.0.0/4.3.6/4.4.0/4.4.3/4.5.4 and typescript 5.9 into the session scratchpad, which stays out of the repo, and one read-only fetch of the zod 4.4.0 release notes to check our own citation was verbatim.
State
72 runs, 125 findings, 118 chargeable, 7 libraries, 168 facts. Two facts corrected, both from the same failure mode and neither found by any check the repo runs. The pre-commit hook guarantees the generated surfaces match the data; it has nothing to say about whether the data matches the world. That gap is the one this session narrowed by hand, and it is worth a standing item rather than a sweep that happens when a backlog entry asks for it.