Context and request
MSXOrg/docs#142 closed the gap between what the Markdown standard asks for and what CI verifies — for github.com URLs. It left one form uncovered, and this issue records it rather than letting it look settled.
The standard says: "Prefer relative links within a repository; use the canonical published URL for cross-repository references." For an MSX repository the canonical published URL is the Pages site, not github.com/.../blob/.... CONTRIBUTING.md uses https://msxorg.github.io/docs/Ways-of-Working/Contribution-Workflow/; README.md and two pages under src/docs do the same. Neither link check covers those. Test-DocumentationLink.ps1 skips them as external, and Test-CrossRepositoryLink.ps1 only resolves github.com and raw.githubusercontent.com.
They break the same way everything else does — a page is renamed here, the published path changes, and the link 404s until a reader finds it. The failure is self-inflicted, which is the class #142 argued was worth gating.
Acceptance criteria
- A link to a published page that does not exist on the site fails the check.
- A link whose fragment matches no anchor in the published HTML fails the check.
- The check is proven negatively: a wrong path and a wrong anchor each produce exit code 1, naming which link and why.
- A pull request that adds a page and links its published URL does not fail because the page is not published yet.
- A run that resolved no published-URL link at all is a failure, not a pass, per #134.
Technical decisions
The timing problem is the whole difficulty, and it is why this was split out. The published site reflects main. A pull request that adds src/docs/Foo/Bar.md and links https://msxorg.github.io/docs/Foo/Bar/ is correct and will fail a naive check, because the page is not published until the pull request merges. A check that is red for correct work gets disabled. Options, none free:
- Resolve against the local build instead of the live site.
zensical build already runs in the Build job, so the output is there — the site's own URL layout answers the question without a network call, and a pull request's new page is present. It changes what is measured: it proves the link would work after this merges, not that it works now. It also cannot see a page that only exists on main because someone deleted it here, which is the same thing the relative-link check already covers.
- Resolve against the live site, but only on the scheduled run. Cheap and honest, and catches decay. It does not gate the pull request that causes the decay, which is the point of a gate.
- Both. The build output at pull-request time, the live site weekly. Probably the right answer; record the reasoning before implementing it.
The anchor oracle is the built HTML, not a slug function. Unlike GitHub, the site's rendered output is available locally: parse id= attributes out of the generated page. That is an independent oracle in the strict sense — the artifact the reader's browser scrolls through — and needs no third slug dialect. Test-DocumentationLink.ps1's ConvertTo-Slug mirrors python-markdown and would only agree with itself.
Ask first whether these links should exist at all. A published URL pointing back into the repository that publishes it is a relative link written the long way. src/docs should almost always use a relative link, which the existing check already resolves. The Pages form is right for README.md and CONTRIBUTING.md, which are read on GitHub where relative links into src/docs resolve to source files rather than pages. Narrowing the surface before checking it may be most of the work.
Implementation plan
Context and request
MSXOrg/docs#142 closed the gap between what the Markdown standard asks for and what CI verifies — for
github.comURLs. It left one form uncovered, and this issue records it rather than letting it look settled.The standard says: "Prefer relative links within a repository; use the canonical published URL for cross-repository references." For an MSX repository the canonical published URL is the Pages site, not
github.com/.../blob/....CONTRIBUTING.mduseshttps://msxorg.github.io/docs/Ways-of-Working/Contribution-Workflow/;README.mdand two pages undersrc/docsdo the same. Neither link check covers those.Test-DocumentationLink.ps1skips them as external, andTest-CrossRepositoryLink.ps1only resolvesgithub.comandraw.githubusercontent.com.They break the same way everything else does — a page is renamed here, the published path changes, and the link 404s until a reader finds it. The failure is self-inflicted, which is the class #142 argued was worth gating.
Acceptance criteria
Technical decisions
The timing problem is the whole difficulty, and it is why this was split out. The published site reflects
main. A pull request that addssrc/docs/Foo/Bar.mdand linkshttps://msxorg.github.io/docs/Foo/Bar/is correct and will fail a naive check, because the page is not published until the pull request merges. A check that is red for correct work gets disabled. Options, none free:zensical buildalready runs in theBuildjob, so the output is there — the site's own URL layout answers the question without a network call, and a pull request's new page is present. It changes what is measured: it proves the link would work after this merges, not that it works now. It also cannot see a page that only exists onmainbecause someone deleted it here, which is the same thing the relative-link check already covers.The anchor oracle is the built HTML, not a slug function. Unlike GitHub, the site's rendered output is available locally: parse
id=attributes out of the generated page. That is an independent oracle in the strict sense — the artifact the reader's browser scrolls through — and needs no third slug dialect.Test-DocumentationLink.ps1'sConvertTo-Slugmirrors python-markdown and would only agree with itself.Ask first whether these links should exist at all. A published URL pointing back into the repository that publishes it is a relative link written the long way.
src/docsshould almost always use a relative link, which the existing check already resolves. The Pages form is right forREADME.mdandCONTRIBUTING.md, which are read on GitHub where relative links intosrc/docsresolve to source files rather than pages. Narrowing the surface before checking it may be most of the work.Implementation plan
zensical buildoutput, the live site, or both at different triggerssrc/docsthat should be relativeid=attributes in the rendered pageLinksorCross-repository linksjob, or add a third, and say inMarkdown.mdwhich form is checked by what