Found while implementing #5992 (route C). Out of that card's scope, filed per Prime Directive #10.
Fact
.github/workflows/check-links.yml invokes lychee over exactly three globs:
'content/**/*.md'
'content/**/*.mdx'
'README.md'
docs/adr/ is not among them. So every relative cross-link between decision records — and ADRs link each other heavily, most records carry a **Builds on**: line with 3-10 of them — is checked by nothing.
Evidence that this is not theoretical
The break #5992 fixed lived in docs/adr/0057-erp-authorization-core-business-units-and-scope-depth.md:5:
**Builds on**: [ADR-0010](./0010-metadata-protection.md) (metadata protection / object ownership),
There is no 0010-metadata-protection.md; the record is 0010-metadata-protection-model.md. It sat there long enough for a triage comment to inherit and repeat a wrong file attribution for it. A link gate would have named it the day it landed.
Why this is not a one-line workflow edit
Measured at origin/main a36db28, sweeping all ](./…) targets under docs/adr/ against the filesystem yields 3 unresolved hits, of which only one is a real break:
| file |
target |
verdict |
0057-erp-authorization-core-business-units-and-scope-depth.md:5 |
./0010-metadata-protection.md |
genuine break — fixed in #5992's PR |
0046-package-docs-as-metadata.md:30 |
./crm_lead_guide.md |
illustrative, inside a code span |
0046-package-docs-as-metadata.md:163 |
./crm_lead_guide.md |
illustrative, inside a fenced ```md block |
ADR-0046 is the record that defines the package-docs link convention ("Docs reference each other with plain relative Markdown links"), so its examples name a doc that deliberately does not exist in this repo. Adding docs/adr/**/*.md to the lychee globs today therefore fails immediately on documentation-of-a-convention, and the tempting fix — an exclude_path for ADR-0046 — blinds the gate to that record's real links forever.
Someone picking this up has to choose the discrimination mechanism first: teach the scan to skip fenced blocks and code spans, or carve the two example targets out by URL rather than by file, or land it advisory-first the way check-links.yml itself was landed under #6028.
Severity
Observation-class as filed: no user path, no runtime behaviour, Check Links is advisory (not in the required set) and green today. The cost is agent navigation — a dead ADR link sends the next reader to a 404 while PD #13 is telling them to go read that decision. Labelled finding, no pm:queue; severity is the PM's to grade.
Not the same as #5992
#5992 is about ADR numbers being ambiguous and is closed by a uniqueness gate. This is about ADR links being unverified. Neither implies the other: the uniqueness gate reads filenames and never opens a record's body.
Found while implementing #5992 (route C). Out of that card's scope, filed per Prime Directive #10.
Fact
.github/workflows/check-links.ymlinvokes lychee over exactly three globs:docs/adr/is not among them. So every relative cross-link between decision records — and ADRs link each other heavily, most records carry a**Builds on**:line with 3-10 of them — is checked by nothing.Evidence that this is not theoretical
The break #5992 fixed lived in
docs/adr/0057-erp-authorization-core-business-units-and-scope-depth.md:5:There is no
0010-metadata-protection.md; the record is0010-metadata-protection-model.md. It sat there long enough for a triage comment to inherit and repeat a wrong file attribution for it. A link gate would have named it the day it landed.Why this is not a one-line workflow edit
Measured at
origin/maina36db28, sweeping all](./…)targets underdocs/adr/against the filesystem yields 3 unresolved hits, of which only one is a real break:0057-erp-authorization-core-business-units-and-scope-depth.md:5./0010-metadata-protection.md0046-package-docs-as-metadata.md:30./crm_lead_guide.md0046-package-docs-as-metadata.md:163./crm_lead_guide.md```mdblockADR-0046 is the record that defines the package-docs link convention ("Docs reference each other with plain relative Markdown links"), so its examples name a doc that deliberately does not exist in this repo. Adding
docs/adr/**/*.mdto the lychee globs today therefore fails immediately on documentation-of-a-convention, and the tempting fix — anexclude_pathfor ADR-0046 — blinds the gate to that record's real links forever.Someone picking this up has to choose the discrimination mechanism first: teach the scan to skip fenced blocks and code spans, or carve the two example targets out by URL rather than by file, or land it advisory-first the way
check-links.ymlitself was landed under #6028.Severity
Observation-class as filed: no user path, no runtime behaviour,
Check Linksis advisory (not in the required set) and green today. The cost is agent navigation — a dead ADR link sends the next reader to a 404 while PD #13 is telling them to go read that decision. Labelledfinding, nopm:queue; severity is the PM's to grade.Not the same as #5992
#5992 is about ADR numbers being ambiguous and is closed by a uniqueness gate. This is about ADR links being unverified. Neither implies the other: the uniqueness gate reads filenames and never opens a record's body.