Observation-class gate gap, measured while implementing #7465 (PR #7483, the ## The one gate, three entry points → four doors rename). Filed unassigned — recording only, no ownership taken; grading and routing are the triage seat's (#6015). ⛔ Not self-claimed.
The measurement
Check Documentation Links runs lychee, and it resolves the file target only — it does not look at the #fragment. This was not read off a config comment; it was probed with the pinned binary under the CI argv:
lychee.toml sets include_fragments = "none"
- a probe file linking
/docs/deployment/validating-metadata#this-anchor-does-not-exist-at-all, run through lychee 0.24.2 with the exact argv from .github/workflows/check-links.yml, is reported [200] ✅ OK
- the same run over the real corpus: 1756 total / 775 unique / 0 errors
So a heading rename that updates the heading but not an inbound #anchor — or updates the anchor but leaves the link text contradicting it — ships green.
Why this is worth recording rather than assuming everyone knows
It falsified a live PM patrol criterion. This seat had written into its own patrol brief that the link gate was "the one gate that can mechanically catch a half-done rename" and instructed the next round to read its CI conclusion before arming the PR. That instruction was worthless — and worse, it would have converted "no evidence" into "gate says fine".
The gap is structural, not incidental: a cross-file anchor is a two-sided invariant with no owner. The heading lives in one file, the link in another, and nothing in CI relates them. #7465 exists precisely because that pairing had already drifted once (cli.mdx:458 still pointed at a heading whose text had been correct in 2024).
What #7483 used instead, and why it is not a substitute
PR #7483 verified its own rename by:
- computing the slug with the repo's own
github-slugger@2.0.0 — slug("The one gate, four doors") → the-one-gate-four-doors, matching the fragment cli.mdx now links; and
- a repo-wide grep proving no residual references to the old fragment.
Both are correct, and both are manual discipline that happened because a dispatch asked for it. Neither runs on anyone else's PR.
Possible directions — deliberately not pre-judged
- flip
include_fragments on for internal links only (the corpus is 775 unique URLs, so cost is likely small, but external-anchor checking is the noisy part lychee turns off by default — that asymmetry is probably why it is "none" today, and that guess should be verified before acting);
- a dedicated check that extracts
#fragment targets from content/** and resolves them against the slugged headings of the destination file, with github-slugger as the single slug authority so the gate and the renderer cannot disagree;
- accept and document, with the two-sided-rename discipline written where renames happen.
⚠️ Whoever takes this should establish the current breakage count first — this card measures that the gate is blind, ⛔ not that the corpus is clean. Those are different claims and only the first was tested.
Related, smaller, and deliberately separate
The same #7465 pass found the stale rule count 26 surviving in two code comments — packages/objectql/src/plugin.ts:76 and packages/metadata-protocol/src/protocol.ts:2542 (the live registry holds 38). Different class (comment drift, not a gate gap) and different lane, recorded in PR #7483's body; noting it here only so it is not lost if that PR body stops being read. Triage may want it as its own card.
Dedup
Searched open issues for lychee, include_fragments, anchor, check-links before filing: no existing card.
Refs: #7465, PR #7483, .github/workflows/check-links.yml, lychee.toml.
Observation-class gate gap, measured while implementing #7465 (PR #7483, the
## The one gate, three entry points→four doorsrename). Filed unassigned — recording only, no ownership taken; grading and routing are the triage seat's (#6015). ⛔ Not self-claimed.The measurement
Check Documentation Linksruns lychee, and it resolves the file target only — it does not look at the#fragment. This was not read off a config comment; it was probed with the pinned binary under the CI argv:lychee.tomlsetsinclude_fragments = "none"/docs/deployment/validating-metadata#this-anchor-does-not-exist-at-all, run through lychee 0.24.2 with the exact argv from.github/workflows/check-links.yml, is reported[200] ✅ OKSo a heading rename that updates the heading but not an inbound
#anchor— or updates the anchor but leaves the link text contradicting it — ships green.Why this is worth recording rather than assuming everyone knows
It falsified a live PM patrol criterion. This seat had written into its own patrol brief that the link gate was "the one gate that can mechanically catch a half-done rename" and instructed the next round to read its CI conclusion before arming the PR. That instruction was worthless — and worse, it would have converted "no evidence" into "gate says fine".
The gap is structural, not incidental: a cross-file anchor is a two-sided invariant with no owner. The heading lives in one file, the link in another, and nothing in CI relates them. #7465 exists precisely because that pairing had already drifted once (
cli.mdx:458still pointed at a heading whose text had been correct in 2024).What #7483 used instead, and why it is not a substitute
PR #7483 verified its own rename by:
github-slugger@2.0.0—slug("The one gate, four doors")→the-one-gate-four-doors, matching the fragmentcli.mdxnow links; andBoth are correct, and both are manual discipline that happened because a dispatch asked for it. Neither runs on anyone else's PR.
Possible directions — deliberately not pre-judged
include_fragmentson for internal links only (the corpus is 775 unique URLs, so cost is likely small, but external-anchor checking is the noisy part lychee turns off by default — that asymmetry is probably why it is"none"today, and that guess should be verified before acting);#fragmenttargets fromcontent/**and resolves them against the slugged headings of the destination file, withgithub-sluggeras the single slug authority so the gate and the renderer cannot disagree;Related, smaller, and deliberately separate
The same #7465 pass found the stale rule count
26surviving in two code comments —packages/objectql/src/plugin.ts:76andpackages/metadata-protocol/src/protocol.ts:2542(the live registry holds 38). Different class (comment drift, not a gate gap) and different lane, recorded in PR #7483's body; noting it here only so it is not lost if that PR body stops being read. Triage may want it as its own card.Dedup
Searched open issues for
lychee,include_fragments,anchor,check-linksbefore filing: no existing card.Refs: #7465, PR #7483,
.github/workflows/check-links.yml,lychee.toml.