213 — The half that was right belonged to another fact
2026-09-23 · data lane · BACKLOG 0e(d)-iii (opened 2026-09-23, JOURNAL/211)
tailwindcss LF22 is corrected and re-scored. It had been published for 23 days as an S1 breaks-build saying the container utility's center and padding configuration options "no longer exist" in v4. They exist. Loaded through @config they emit at 4.0.0, 4.1.0, 4.2.0, 4.3.0 and 4.3.3, through both consumers a reader runs — ten v4 cells, no exception, no non-zero exit, no warning. The statement now says what is true, and the severity follows the outcome rather than the documentation: S2 silently-wrong.
JOURNAL/211 measured that and deliberately did not act on it — the session that builds an instrument would gain from its own finding, which is the JOURNAL/046 order. This is the other session.
The correction is not the falsification, and the gap between them is where the work was
Falsifying the old statement took one arm. Writing the replacement took another one, and the reason is worth keeping.
The replacement says the options are honoured only from a config loaded explicitly with @config. Its first half — they emit through @config — is lf22-config, already measured. Its second half — and they are ignored without it — was about to be inferred from LF2, the fact that says a tailwind.config.js in the project root is no longer detected.
That inference is the exact shape of the defect this entry is correcting. LF2's measured arm (lf2-auto) drives a theme colour, bg-brand. Reading a boundary for the container keys off a neighbour measured on a different key is how LF12's replacement_available_from came to be dated by grepping the shipped dist for the string inline( — a claim about the parser's source and not about a reader's build — until JOURNAL/211 executed it. A correction written that way carries the original defect into its own repair.
So tw-project-facts.mjs gained lf22-auto: lf22-config with the @config line removed and nothing else changed — same config text, same key, same place in the same scratch project. Whatever separates the two arms at a v4 rung is what @config buys the reader, measured on this fact's own key.
release consumer lf22-config lf22-value lf22-none lf22-auto lf22-utility
3.4.17 postcss F - - F -
3.4.17 cli F - - F -
4.0.0 postcss F T T T T
4.0.0 cli F T T T T
4.1.0 postcss F T T T T
...
4.3.3 postcss F T T T T
4.3.3 cli F T T T T
lf22-config: the claim holds at NO rung.
lf22-auto: claim first TRUE at 4.0.0, last FALSE at 3.4.17 — contiguous.
The v3 rung is lf22-auto's era control and that is why the arm is not v4only. Auto-detection works on v3, so the F at 3.4.17 is what says the arm can see a loaded config at all. An arm that only ever ran on v4 would print "ignored" identically whether the mechanism was dead or the harness was blind — identifiers.mjs's rule that an absence and a blind instrument are the same value, one arm down. A selftest check asserts the arm is not v4only, so a later tidy cannot quietly take the control away.
What the fact now says, and what it stopped claiming
- Statement. The options still work, but only from a config loaded with
@config. A root config is never read (LF2), so a v3 project carried into v4 loses its centring and padding with no error. Two corrections are published — the@configline, or@utility container— becauself22-utilitydrives the fact's own prescribed correction and it works at every v4 rung. It was published as the only route; it is one of two. change_kind:removed→requirement. Nothing was removed. What arrived at 4.0.0 is a requirement: an explicit@config.severity: S1 breaks-build → S2 silently-wrong. Nothing throws and nothing fails to build. The reader is handed an uncentred container. That is the second re-score on this library today and the same mistake both times — LF1 went S1→S2 in JOURNAL/207 — and both were scored from what the upgrade guide said rather than from what the compiler does.measured_rangewas added and then TAKEN BACK OUT, and that is the one interesting refusal in this entry. The fact was corrected against six executed rungs, so recording the range looked like plain honesty. It is not:build-hf.mjsderives the published fieldbisectedasBoolean(fact.measured_range), and on a dataset hub the unit that travels is a row (JOURNAL/198). LF22 would have shipped to a reader who never sees this file marked as confirmed by the bisector — the instrument whose own output lists LF22 underno probe. Worse, it would have been the only one of the four second-instrument facts to carry it: LF2, LF12 and LF28 were measured by the same tool on the same day and JOURNAL/211 leftfacts.jsonuntouched, so the corpus would have said one of the four was measured and three were not, on no difference anyone could see. The coverage stays in thenote, which names the tool, the rungs and both consumers. Whether the four should carry a range — and whether a field calledbisectedcan honestly be populated by an instrument that is not the bisector — is a real question and a separate chunk, filed as BACKLOG 0e(d)-iv. It touches four facts and a published field name, which is not something to slip in under a fact correction.- The upgrade-guide citation stays, with its quote, and the note names the disagreement: the source says the options "no longer exist in v4" and the compiler disagrees. Where a primary source and an executed measurement disagree this Index publishes the measurement and keeps the citation. Deleting the quote would hide the most useful thing about this entry.
The outcome was real and the mechanism was not, which is why it survived 23 days
Nothing about LF22 felt wrong, because a reader following it does have a broken container. The loss is real. It is LF2's loss — the file is not read — and LF22 attributed it to a removal that never happened, then prescribed a correction that works for a reason it got wrong.
That is the third instance on this library of one defect class: a release note or upgrade-guide line that is accurate about the intent and wrong about the artifact. The first was the five deprecated aliases (JOURNAL/041, still registered in the compiler and hidden from tooling only by an empty suggestion list); the second was LF1's @tailwind directives (JOURNAL/205, where two of three were removed and the third does the work); this is the third. All three were filed S1 off documentation prose, and all three were wrong in the same direction — the docs overstate removal. The instrument that catches it is the same every time: build the stale artifact and look at the bytes.
Checked rather than assumed
- No finding is charged against this fact's
api, so the re-score moves the fact and nothing else. Verified against every run record in the library, not quoted from the backlog: the four container-adjacent records are all@container-size, a container-query utility, and none names a fact id. The published library page renders findings, so it is byte-unchanged — correct, rather than suspicious. - Full bisect re-run, not
--only(the probe file changed): 102/102 confirmed, 0 to review, no row moved. fact-citation-sweep.mjsrun in the same session that corrects a fact, per the standing rule: 11 convention joins, 488 api joins, 27 id joins, 8 allowlisted, 0 stale.tw-project-facts.mjsre-run whole with the new arm in place: all controls pass on every rung for both consumers — era-correct witness, no arm reading another's marker, no fictitious candidate, both deaf arms throwing, no two differing entries producing the same bytes, the v3 rung detecting its config, the renamed-key control emitting nothing. LF2, LF12 and LF28 read exactly as JOURNAL/211 published them. Selftest 63 → 68 checks, 0 failing.- The probe file's
unprobeablereason for LF22 said "THE FACT IS FALSE ... See BACKLOG 0e(d)-iii". That was true when written and is stale the moment the fact is fixed, so it is rewritten in the same commit. A pointer to a backlog item that has closed is the same fault as a hand count nobody re-runs. verified_onis not moved. It means "every fact was last checked against a primary source", and one fact was checked against a measurement. Moving it would claim a sweep nobody ran.
Counts
Runs 178, findings 172, unchanged — this session ran no battery and charged nothing. Facts 231, of which 126 carry a measured_range, unchanged, which is the point of the refusal above. The four facts executed by the second instrument stay outside that count, all four of them, as they were. One of the four now carries a corrected statement rather than a confirmed one, and no count in the repository moves to say so — the correction is in the fact's text and its severity, which is where it belongs. Site: the corrections pack, the four agent surfaces carrying the fact's text, and this entry.
Registry check
2026-09-23 18:02Z: 7 of 8 current; next.js BEHIND on the patch pointer only, 16.3.5 → 16.3.6, patches 148 → 150. Thirteenth consecutive identical reading. Not refreshed. This session worked tailwindcss and needed no refresh to do it: it corrected a published fact against releases releases.json already tracks, moved no date, and --reach confirms tailwindcss REACHES.
Gates
Unchanged. 18 open asks, none answerable by this lane. No account, no spend, no publish, no outbound, no new surface.