You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Markdown.md tells authors: "Prefer relative links within a repository; use the canonical published URL for cross-repository references."Test-DocumentationLink.ps1 then ignores external links on purpose. The one link form the standard actively asks for is the one form nothing verifies.
The checked case is the easy one. A relative link points at a file on disk, in the same commit, changed by the same pull request. A cross-repository link points at something that moves on someone else's schedule, without anyone here being told. The check covers the case that is hard to get wrong and skips the case that is hard to keep right.
It has already happened. Storhaug-ting/Kilden moved its source folders under docs/, and seven cross-repository links in Storhaug-ting/S62 became 404s. A reader found them, not a check – see Storhaug-ting/S62#10.
Acceptance criteria
A cross-repository link to a file that does not exist fails the check.
A cross-repository link whose fragment matches no heading in the target fails the check.
The check is proven negatively: a deliberately wrong target and a deliberately wrong anchor each produce exit code 1, and the output names which link and why.
A network or rate-limit failure is reported distinctly from a broken link, so a red run says which of the two happened.
Technical decisions
Scope by ownership, not by scheme. Checking every external URL makes the check slow, flaky, and hostage to other people's outages. Links into organisations we control are a bounded set, and they are where the breakage originates: the target moved because we moved it. The list of in-scope hosts and organisations is a decision this issue must record, not leave to the implementation.
An anchor cannot be checked with a HEAD request. The fragment is never sent to the server, so …/file.md#heading answers 200 whether or not that heading exists. The content has to be fetched and its headings slugged, which is precisely the case that broke in S62.
The oracle must be independent. Anchors have to be derived from GitHub's own slug rules – github-slugger is the reference – not from this repository's ConvertTo-Slug, which mirrors python-markdown for the published site. A cross-repository link resolves against GitHub's rendering, not ours; reusing the site slugger here would check the wrong algorithm and quietly agree with itself.
Answer the third-copy question before it is written. This logic exists twice today: .github/scripts/Test-DocumentationLink.ps1 here, and scripts/Test-MarkdownLink.ps1 in Storhaug-ting/Kilden, adapted from it with GitHub's slug rules instead of the site's. Storhaug-ting/S62#10 is about to make three, in a repository with no .github directory at all. The two slug dialects are a real difference and not duplication to collapse blindly – but whether this ships as a managed file through MSXOrg/Custo rather than being copied and adapted a third time is a question this repository owns, and it is cheaper to answer now than after the third copy exists.
Network calls belong in their own job. A separate job means the name of the red job says the network check failed rather than the docs being wrong. Consider a scheduled run as well: a target repository can move content long after a pull request here has merged, and nothing in the pull-request trigger will ever notice.
Implementation plan
Decide the in-scope hosts and organisations, and where that list is configured
Add a failing check first: a link to a non-existent file in a controlled repository, and a link whose anchor matches no heading
Resolve in-scope cross-repository links against the target content and validate anchors with GitHub's slug rules
Report a network or rate-limit failure distinctly from a broken link
Context and request
Markdown.mdtells authors: "Prefer relative links within a repository; use the canonical published URL for cross-repository references."Test-DocumentationLink.ps1then ignores external links on purpose. The one link form the standard actively asks for is the one form nothing verifies.The checked case is the easy one. A relative link points at a file on disk, in the same commit, changed by the same pull request. A cross-repository link points at something that moves on someone else's schedule, without anyone here being told. The check covers the case that is hard to get wrong and skips the case that is hard to keep right.
It has already happened. Storhaug-ting/Kilden moved its source folders under
docs/, and seven cross-repository links in Storhaug-ting/S62 became 404s. A reader found them, not a check – see Storhaug-ting/S62#10.Acceptance criteria
Technical decisions
Scope by ownership, not by scheme. Checking every external URL makes the check slow, flaky, and hostage to other people's outages. Links into organisations we control are a bounded set, and they are where the breakage originates: the target moved because we moved it. The list of in-scope hosts and organisations is a decision this issue must record, not leave to the implementation.
An anchor cannot be checked with a HEAD request. The fragment is never sent to the server, so
…/file.md#headinganswers 200 whether or not that heading exists. The content has to be fetched and its headings slugged, which is precisely the case that broke in S62.The oracle must be independent. Anchors have to be derived from GitHub's own slug rules –
github-sluggeris the reference – not from this repository'sConvertTo-Slug, which mirrors python-markdown for the published site. A cross-repository link resolves against GitHub's rendering, not ours; reusing the site slugger here would check the wrong algorithm and quietly agree with itself.Answer the third-copy question before it is written. This logic exists twice today:
.github/scripts/Test-DocumentationLink.ps1here, andscripts/Test-MarkdownLink.ps1in Storhaug-ting/Kilden, adapted from it with GitHub's slug rules instead of the site's. Storhaug-ting/S62#10 is about to make three, in a repository with no.githubdirectory at all. The two slug dialects are a real difference and not duplication to collapse blindly – but whether this ships as a managed file through MSXOrg/Custo rather than being copied and adapted a third time is a question this repository owns, and it is cheaper to answer now than after the third copy exists.Network calls belong in their own job. A separate job means the name of the red job says the network check failed rather than the docs being wrong. Consider a scheduled run as well: a target repository can move content long after a pull request here has merged, and nothing in the pull-request trigger will ever notice.
Implementation plan
Markdown.mdthat cross-repository links are checked, so the standard and the gate say the same thing