fix(checks): read files through Gitea's contents endpoint, not raw

The three checks that read another repository -- checkFacts, checkQuickstart,
checkReference -- fetched source files from the API's `raw` route, which answers
`Cache-Control: public, max-age=21600`. The CDN in front of Gitea caches that,
so the checks can read a blob most of a working day old.

It bit on cutover day. checkFacts reported

    FAIL  moduleApi
          platform.json says : 1.9.0
          website main:server/src/modules/version.js says : 1.6.0

against a `main` that says 1.9.0 -- the served copy was two weeks old
(`cf-cache-status: HIT`, `Age: 15713`, `last-modified: 18 Aug`). No edit in this
repository could have made it pass, and the same run reported a bundle triple
that had already been republished as still current: a stale read fails BOTH
ways, and the false pass is the dangerous one.

The `contents` endpoint answers `private, must-revalidate`, which the CDN
bypasses, so it is always the ref's current blob. The cost is a JSON parse and a
base64 decode. checkReference's canonical-document existence loop already used
it, which is why that half was never affected.

PLAN.md 12 records the finding next to the check it constrains.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-09-01 12:41:01 -05:00
parent 3574bba4d5
commit 5e987518c6
4 changed files with 51 additions and 8 deletions

11
PLAN.md
View File

@@ -1622,6 +1622,17 @@ a mechanism rather than diligence:
replaceable by a file copy, and that promise survives exactly as long as nobody types the address
into a paragraph. Same argument as `checkTokens.mjs` and colour literals — the check is the
mechanism, diligence is not.
**All three network checks read a file through Gitea's `contents` endpoint, never `raw`** —
`checkFacts.mjs`, `checkQuickstart.mjs`, `checkReference.mjs`. Phase 12b found the reason.
`raw` answers with `Cache-Control: public, max-age=21600`, so the CDN in front of Gitea keeps
a copy for six hours: on cutover day this check read `website`'s `version.js` from a fortnight
earlier and failed the site for saying Module API 1.9.0 when `main` said 1.6.0 — except that
`main` said 1.9.0, and nothing anyone could edit here would have made it pass. `contents`
answers `private, must-revalidate` and is not cached, at the cost of a base64 decode. Same
argument as `checkLinks.mjs` fetching nothing: a check that goes red on someone else's
infrastructure is a check people learn to ignore, and one that goes red on a stale copy is
worse — it is indistinguishable from the failure it exists to report.
- **`scripts/checkLinks.mjs`** — every internal link resolves; every outbound link into a
`RunicGateway` repo points at a branch path, not a commit permalink. **Built in phase 4** (D23),
and it reads `dist/client` rather than `src/`: half the links these pages carry are assembled from