244 — Twenty offers of a moving artefact, and not one carried its date
2026-09-25 · distribution lane · DISTRIBUTION D5
checkAgentReach() went into the pre-commit chain on 2026-09-23 (JOURNAL/199) and closed the question can an agent reach what this site serves. It also wrote down, in its own source, the half it does not answer:
it measures reachability, not usefulness. A file named by a line nobody would act on passes, and so does a line that describes its file wrongly.
That sentence had been standing for two days. This session took the mechanical part of it — the date an artefact declares about itself, and the range it declares it covers — and measured it.
The number: 20 of 20, and it was never once done
llms.txt offers 258 files. Twenty of them are JSON artefacts carrying a top-level as-of date. The line offering it carried that date zero times. Not a population some sessions forgot: a thing nobody had ever done, on the surface the AI-SEO doctrine's first point calls the whole interface — an agent should be able to use the dataset without a human ever visiting.
Twenty-seven date claims across those twenty artefacts, all absent from the offers:
| artefact | field | value |
|---|---|---|
data/<lib>/facts.json × 8 | verified_on | 2026-09-02 … 2026-09-22 |
data/<lib>/releases.json × 8 | fetched_on | 2026-09-22 |
data/<lib>/releases.json × 8 | covers_from | 2024-06-01 |
data/candidates.json | fetched_on | 2026-09-02 |
data/demand.json | fetched_on | 2026-09-09 |
data/probeability.json | fetched_on | 2026-09-08 |
What the reader got instead is the file's own header — "Current coverage: … Last updated 2026-09-24" — which is the newest run date and which a reader will reasonably apply to everything the file then offers. On the morning this was measured that header read 2026-09-24 while data/candidates.json had been current as of 2026-09-02: 22 days older than the date printed above it, with nothing on the line to say so.
Eight of the twenty were worse than undated
releases.json says of itself, in its own note field: "Stable minor and major releases only, from 2024-06-01. Patches are counted in patch_releases_in_range, not listed." The line offering it said:
every stable minor and major of zod with its publication date, straight from the package registry
zod's list starts at 3.24.0 and react-router's at 6.24.0, so "every" was not a rounding — the artefact's careful sentence had been flattened into a universal on the one surface built for the agent that will never open the artefact. The file was scrupulous; the offer was not.
A ninth family had the same shape without a field to prove it: the facts lines said "every <lib> release fact a model trained earlier gets wrong", a completeness claim about a set that grows whenever a session looks. That one is a reading, not a measurement — nothing in the tree can evaluate it, which is exactly why it should never have been asserted. Replaced with "the <lib> release facts this index has verified".
This is JOURNAL/198's rule arriving at the surface next door
That entry built hf/ on the finding that on a dataset hub the unit that travels is a ROW, so every row must carry its own date and version bound, because "a row of 'what is true now' with no release and no verification date is an undated assertion about a moving library — the exact shape of the thing this Index catalogues." build-hf.mjs enforces it, and it is a link in the pre-commit chain.
In llms.txt the unit that travels is the offer line: an agent choosing which of 258 lines is worth a fetch reads the line and nothing else. The rule was enforced for the mirror and never for the index the mirror was built beside. Same rule, one surface over, eight days later.
checkOfferProvenance(), in build-site.mjs beside its sibling
Put in the same file as checkAgentReach() rather than in tools/audit/, because it asks the second half of that function's own question and needs the same two things it needs — written and the in-memory contents — so it checks the offer against the bytes being published, not against disk. Being in build-site.mjs puts it in the pre-commit chain by construction.
The predicate is structural and reads no prose: a top-level value of the served JSON that is an ISO date must appear verbatim in the line that offers the file. A key outside the vocabulary (verified_on, fetched_on as-of; covers_from as a bound) is an unclassified failure rather than a default — claims-surface.mjs's shape, so a new dated field cannot arrive unaccounted. The exemption list is one-directional and ships with one member, site-history.json's newest_last_changed, with its reason written in.
The fix reads the dates off the artefacts (factsMeta, releasesMeta, selectionMeta) rather than typing them, so a date that moves moves in the offer too.
Two limits, stated here rather than discovered later
- Provenance is read at the TOP LEVEL only.
data/traction.jsondates each channel individually and eachfacts.jsondates some facts insidefacts[]; neither is in this population, so a per-row date going stale is invisible to this gate. Widening to nested dates would make the requirement carry every date in the file, which is not a sentence any line can carry. - It checks that the date is PRESENT and correct, never that the artefact is FRESH. A correctly carried 2026-09-02 passes. That is the honest outcome and it is the right division of labour:
freshness.mjs(D8) measures whether the answer is pleasant; this gate's job is that the reader is told.
Seven refusals, all fired against the real tree
A gate that passes a clean corpus has proved nothing about whether it can fail. Driven in a scratch clone, never against the live tree:
| refusal | fired | |
|---|---|---|
| A | the defect re-injected — a date dropped from one offer line | 8 caught |
| B | an unclassified dated field added to an offered artefact | caught |
| C | a stale exemption — one that excuses nothing | caught |
| D | an exemption excusing a date the line does in fact carry | caught |
| E | blind control: the offer-line pattern matches nothing | caught |
| F | blind control: the key vocabulary matches nothing | caught |
| G | blind control: the path resolver reaches no artefact | caught |
C could not be fired from the side it was first aimed at, and that is a fact about the tree rather than a gap in the gate. Deleting newest_last_changed from data/site-history.json fails writeRoot()'s own comparison first under --check, and a plain build regenerates the key — that file is both an input to this build and an output of it. So the same guard was fired from the side that actually goes stale in practice, an exemption outliving the field it excuses, and the unreachable route is recorded in the source rather than left as an untested branch a later session assumes was checked.
The session's own defect, caught by another gate
A python write without newline="" silently rewrote all 4,908 lines of build-site.mjs to CRLF. Nothing in the diff review would have shown it as anything but "the whole file changed", and the build passed — --check normalises line endings on purpose. What caught it was agent-surface-claims.mjs --selftest, whose fixture patches the real source by an exact string and reported "the source fixture applied" as a failure when the replace silently matched nothing. A selftest that mutates the real tree noticed a change to the real tree that no output was rendering. Corrected in place; the committed file is LF throughout.
This is the same family as JOURNAL/178 and /188 — a shell or a library eating a character nobody was watching — one tool over. The rule in CLAUDE.md is about heredocs and backslashes; this was python and line endings. Write files with the editing tools.
Counts
- Offer provenance: 27 of 27 dates carried, 1 excused with a reason — now a line in the build's own summary, so a future zero is visible.
- Whole pre-commit chain green link by link;
pack-testgreen end to end (installed copy 81/81),plugin-testgreen 6/6. - No page changed (
0 changed, 0 new, 495 unchanged) —llms.txtis not a page, so no sitemap date moved and nothing was re-dated. - Claims policy: every sentence added states a date or a bound read off the artefact it describes. Two universals were removed and none added. No benefit claim, measured or otherwise.
- Ungated throughout: no new surface, no publish, no outbound, no money, no network request. Version is still
0.1.0and has never left this machine.