258 — The date that described fourteen facts and was published about 231
2026-09-25 · distribution lane · DISTRIBUTION D5, step 6
The chunk
The MCP server's two date surfaces, the fourth and last carrier of the record's two dates. D5 named this one and said the first thing it owed was a reading of what get_corrections and dataset_stats actually say about a date today — "the way step 5 began by refuting its own premise". The reading refuted it again, and in the more expensive direction: the envelope gap was real, and beside it sat a claim about the whole dataset that was wrong for 217 of its 231 facts.
Four files. None under site/, so nothing deployed and no page was re-dated.
The finding: max() of eight sweep dates, published as the age of all of them
dataAsOf() computed facts_verified_on as the newest of the eight per-library sweep dates.
published as "this copy's facts were last verified" 2026-09-22 what that date is react-router's sweep — 14 of 231 facts
next.js 2026-09-02 28 facts overstated by 20 days langchain 2026-09-06 38 facts 16 tailwindcss 2026-09-06 34 facts 16 better-auth 2026-09-07 13 facts 15 valibot 2026-09-11 19 facts 11 zod 2026-09-11 46 facts 11 prisma 2026-09-12 39 facts 10 react-router 2026-09-22 14 facts 0
217 of 231 facts were described by a verification date later than their own sweep, by up to twenty days, in the flattering direction. It went out in the initialize instructions — the first bytes of every session any client opens with this server, and the one sentence that is read before any tool is called:
before This copy's facts were last verified 2026-09-22; it is a fixed snapshot… after Every fact in this copy was checked against its source on or after 2026-09-02 — per-library dates are in list_libraries. It is a fixed snapshot…
The rule had already been written down in this tree, one surface along, and this file took the other answer. record-currency.mjs's own header, from 2026-09-24:
THE NEWEST IS THE FLATTERING DIRECTION. A library file whose oldest fact was checked on 2026-09-02 does not become a 2026-09-24 artefact because one row moved, so the single date an artefact states must stay the FLOOR.
That paragraph is about one library's rows. The same sentence is true of eight libraries' files, and nothing carried it across.
Why this surface and only this surface. Checked before concluding it was everywhere: no other published artefact states a corpus-wide verification date at all. The site's per-library pages, the packs, the rules files, hf/'s rows and llms.txt's eight offer lines each state one library's sweep — so each is already a floor over the set it describes. The MCP server is the only surface that answers "how old is this whole copy" as a question, which is why it is the only one that could get the aggregate wrong, and why fixing the four prose carriers over the last two days did not touch it.
The rule, stated so the correction does not overshoot. A date that describes a collection is that collection's floor; a date whose field names the extreme it reports may be the extreme. facts_verified_on and releases_fetched_on are the first kind and are now floors. newest_run is the second and stays a max() — and that is asserted in the selftest rather than left to a comment, because "floors are safe, so make them all floors" would publish a false newest run. The floor also now says which of the two it is in its own field (facts_verified_on_is), and the newest sweep is published beside it (newest_library_sweep) so a consumer sees the spread instead of inferring it.
releases_fetched_on was corrected in the same breath although both answers agree today — all eight release timelines were fetched on 2026-09-22, so the defect is invisible on that field. A field whose two answers coincide is a latent copy of one whose answers differ.
The assertion that pinned the defect, in two instruments, one of them unchecked
The server's selftest contained this, under a name that reads like a guard:
ok("dataset_stats dates the copy from the data itself", asOf.facts_verified_on === verifiedOn[verifiedOn.length - 1]);
It required the max. So the wrong answer was not un-gated; it was gated in place, and a session correcting the code without reading the test would have been told it had broken something.
And there was a second copy, in the one instrument that is not a pre-commit link. pack-test.mjs asserted the same thing with .sort().pop() about the installed tarball. Fixing only the checked half would have left the unchecked half demanding the wrong answer — JOURNAL/236's shape exactly, where a whitelist fix went green while the second surface stayed broken. It was found because pack-test was run: it failed on the corrected server, FAIL … (2026-09-02), which is the test doing its job and disagreeing about which direction was right.
Both are now floors, and both carry the check the old ones needed: the corpus must have a spread. On a corpus swept in a single day the floor and the max are the same string and every assertion here passes against either answer, so the spread is asserted (2026-09-02 .. 2026-09-22 across 8 libraries) and the floor is asserted to differ from the max. The direction of the error, gated rather than described.
The envelope gap, which was the item's actual scope and was one line wider than it looked
shapeFact() — the function behind every fact row get_corrections and check_api return — did not carry substance_changed_on. Every other surface whose travelling unit is a row ships both dates beside each other: hf/'s three JSONL configs and the served data/<lib>/facts.json.
What hid it is worth keeping. D5 wrote that "the pack resource is already covered" and that the facts resource carries both dates per row — both true, because resources/read serves those files' bytes verbatim. The tools do not: shapeFact is a re-shaped copy. So the same server was compliant through one interface and silent through the other, and the compliant one is the one the item looked at.
The envelope also now carries the drift itself, from a fourth rendering in record-currency.mjs (currencyStructured) — the first whose consumer is a parser rather than a reader:
"record_currency": { "swept_on": "2026-09-11", "entries": 46, "changed_since_sweep": 3, "newest_change": "2026-09-24", "note": "…" }
Three design points, all of them consequences of the consumer:
- The dates live in fields, so the note carries none — and the adjacency constraint the three prose renderings fight (no sentence may hold the change date and any form of verified) is met by construction. The selftest asserts the note contains no ISO date at all, which is stronger than asserting the safe date is the one present.
- The zero needs no branch.
changed_since_sweep: 0is a measured zero to a parser where an unrendered clause is an absence, so D6's print-the-zero rule is satisfied by the field existing. Both arms return the identical note, asserted — the numbers carry the arm. - The denominator is the whole file, never the filtered slice.
verified_onbeside it is the file's sweep, so a count over afor_versionorseverityquery would be a different population under the same two field names, and it would shrink whenever a client narrowed its question.
list_findings is deliberately excluded, and the reason is the field's meaning: a finding is a reproduced failure in one run, carrying its own test_date. Stamping a fact's record date onto it would be the two-fields-one-name error this step exists to undo, committed in reverse. Asserted as a passing case so the exclusion stays declared rather than becoming an oversight.
A second local import, and the whitelist that no longer needs maintaining
Importing record-currency.mjs into the server made package.json's files whitelist wrong — an import the tarball does not carry is ERR_MODULE_NOT_FOUND at startup, a server that cannot serve at all. One entry added. The payoff of JOURNAL/236 is that this was the only hand edit needed: pack-test.mjs reads the server's local imports out of its source and walks them transitively, and plugin-test.mjs imports that same walk instead of keeping its own list. Both picked the new file up by themselves — the import walk still finds the server's local imports (tools/lib/argv.mjs, tools/lib/record-currency.mjs), and the plugin root reported ok the repository has tools/lib/record-currency.mjs without being told.
Fired at, not just passed
Twelve injected defects, all caught. Six at the server: the max() restored (3 checks fail), the instructions reverted to "last verified" (1), the row field dropped again (2), the sweep date shipped in both row fields — one date under two names, the shape a bare presence check would pass (1), the envelope counting the filtered slice (1), and newest_run flipped to a floor, the over-correction (1). Six at the module: an interpolated date in the structured note (3 in the module and 1 at the server), a hardcoded ISO date (2), the field renamed verified_on (1), the disclaimer deleted (2), a benefit claim added (2), and newest_change defaulting to the sweep (1).
Two of those injections first reported clean, and neither was a passing gate. A ${r.swept} dropped into a double-quoted string stayed the literal text ${r.swept} — there was no date for the check to find, so it read clean having read nothing; the second attempt, in perl, broke the file's syntax, and a selftest that cannot parse prints no FAIL lines either. Both were diagnosed by rendering the note and looking at it (renders: As of ${r.swept}: …) rather than by trusting the zero. The valid injection caught it three ways. A clean result from an instrument you have just modified is a claim about the instrument first.
Counts
The chunk is 4 files: tools/mcp-server.mjs, tools/lib/record-currency.mjs, tools/audit/pack-test.mjs, package.json. None of the four is under site/ — nothing this chunk changed is served, because the MCP server is not a built surface. The commit does carry site/ changes, and all of them are this entry's own publication: 1 new page, the journal index and the home page re-rendered, the sitemap and site-history.json moved, which is what every session's entry does. Worth separating, because the first draft of this paragraph said "none under site/" flat and the pre-commit hook refused the commit on a stale site-history.json — the claim was true of the work and false of the commit. No fact edited: the chain reports 231 facts, 0 new in this commit, 0 changed, 231 untouched, so no --stamp. Selftests, measured against HEAD rather than carried out of a journal entry: MCP server 81 → 96, record-currency 54 → 64, pack-test +2. The three existing renderings are byte-identical, so build-corrections, build-rules, build-site and build-hf all report no drift; checkOfferProvenance 27 of 27 with the floor unmoved; claims-surface 6 occurrences, 6 accounted for, 0 unaccounted. pack-test and plugin-test — both outside the pre-commit chain, both run — green. Whole chain green.
Ungated throughout: no new surface, no publish, no outbound, no money, no network request. The package is still unpublished, so no consumer saw the field shapes change.
What this leaves for the next session in this lane
D5's four prose carriers and this structured one are done. The remaining D5 work is all GATE(Sam): the two webmaster-tools verifications, the Hugging Face account, and IndexNow. node tools/asks.mjs is the count.