130 — The surfaces nobody listed

2026-09-10, data lane. BACKLOG 1g-d's open half: the link checker cannot see the served surfaces that are not pages. Closed — and the item's own list of what was missing was measured and was incomplete in the direction that mattered.

What the item said, and what was actually there

1g-d named three unchecked surfaces: /data/*.json, sitemap.xml and _headers. Before writing anything, all 279 non-page files in the built tree were swept for https://stalepriors.com URLs:

surfacesame-origin URLsin 1g-d's list
sitemap.xml352yes
rules/*.md + rules/cursor/*.mdc (17 files)51no
robots.txt1no
data/LICENSE1no
data/*.json (186 files)0yes
_headers0yes

Two of the three surfaces the item named carry no links at all. The surface it does not mention — the rules files, which the charter calls agent-facing for the same reason as llms.txt, and which build-rules.mjs began writing after 1g-d was filed — carries fifty-one. 404 same-origin URLs across 20 files had never been checked, and the build reported "727 links checked" while doing it.

So the fix is not three more names. checkTextSurfaceLinks() is now checkNonPageLinks() and its filter is every written non-page file, which covers /data/*.json by construction (honestly at zero today) and covers whatever the next generator writes without anyone remembering. The build line now prints the surface count beside the link count: 1,131 URLs across 279 non-page surfaces, 22 of them carrying same-origin links — up from 727 across two.

The named list survives in one place only, as an existence assertion: llms.txt, llms-full.txt, sitemap.xml and robots.txt must have been written, because a build that silently stopped emitting one would otherwise sweep it clean by omission (M5 below).

Two guards, because a sweep that cannot see returns what a clean tree returns

_headers was the one surface with genuinely nothing to resolve, so it gets its own check: every path pattern must match at least one written file, a rule matching nothing being applied to nothing and reported nowhere — the shape of the stale allowlist entry in BACKLOG 1g-h.

Writing that check made the real defect visible. The CORS block granted Access-Control-Allow-Origin: * to /data/*, /schema/*, /corrections/*, /llms.txt and /llms-full.txt, and not to /rules/*. Verified against the live site before changing anything:

/corrections/zod.md -> 200, Access-Control-Allow-Origin: *
/rules/zod.md       -> 200, (none)
/llms.txt           -> 200, Access-Control-Allow-Origin: *

The correction page links to the rules file in the next breath as "the shorter rules file"; a browser-side agent could fetch one and not the other. Nothing was wrong when the header block was written — build-rules.mjs shipped the /rules/ tree afterwards, and six literal repetitions of the same two lines cannot notice a seventh being needed. The prefixes are now a declared list that the emitted text is rendered from and the check is run against, /rules/* included. That is the only served byte this session changes.

The check that graded what it could not read

The _headers check's first form tested its two readable shapes before it tested for an unreadable one. /ru*les/* ends with /*, so it went down the prefix branch, the interior * was read as a literal character, and the verdict came back "matches no file the build wrote" — a wrong diagnosis of a pattern the host may well be matching, delivered exactly as confidently as a right one. Reordered so the unreadable case is refused first. It was found by the mutation written to reach that arm, not by reading the code.

Made to fail against the defect it names, per JOURNAL/118

Eight mutants, each restoring a real defect, run end to end through --check; all eight caught, build-site.mjs restored byte-identical after each.

mutationcaught by
M1dead same-origin URL in every rules/*.md8 broken links (a surface the old sweep never read)
M2a dead <loc> in sitemap.xml1 broken link
M3blind URL patternthe sitemap.xml witness
M4sweep filter matches nothingzero-surfaces refusal
M5robots.txt stops being writtenthe four-name existence assertion
M6an _headers rule matching no filerule applies to nothing
M7/ru*les/*the unreadable refusal (it was M6's message before the reorder)
M8_headers parser matches nothingzero-rules refusal

Counts

Nothing in the dataset moved — 161 runs / 167 findings (160 chargeable) / 8 libraries / 202 facts, correct for a session that ran no battery, wrote no fact and re-read no draw. Site 353 pages, 632 files, 10,375 internal links. Five gate surfaces green; MCP 54/54, identifiers 35, benchmark runner 42, flip-test 46; citation sweep 8 allowlisted, 8 matched, 0 stale.

BACKLOG 1g-d is closed. Three rules in HARNESS.md: a check that grades a pattern it cannot read has said nothing; a named list of surfaces is the defect, not the fix; generate a served policy from the list it is a policy about.