⚙️ [Maintenance]: Cross-repository links are now verified - #145
Conversation
The check does not exist yet, so every case is red. That is the point: the negative proof comes before the implementation, per the Testing standard's test-first rule. The suite runs entirely offline. An in-process HttpListener stub answers the two GitHub endpoints the check will call, so the cases for a missing file, a missing anchor, an exhausted rate limit, a failing request, and a target repository a reader cannot read are deterministic and locally runnable. The slug expectations are a recorded fixture from github-slugger 2.0.0 - the library GitHub's own anchors come from - not a second derivation of the rule under test. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The check reads the target's content rather than sending a HEAD request: a URL fragment never reaches the server, so an anchor into a file answers 200 whether or not the heading exists - which is exactly the case that broke seven links from Storhaug-ting/S62 into Storhaug-ting/Kilden. Anchors are slugged with GitHub's rules, taken from Kilden's Test-MarkdownLink.ps1 rather than from this repository's ConvertTo-Slug. That one mirrors python-markdown for the published site, and a cross-repository link resolves against GitHub's rendering, not ours. Three outcomes rather than two. A 404 alone cannot tell a deleted file from a repository no reader can open, so the repository is probed before a link is called broken, and both a network failure and an unreadable target are reported under their own heading. Proven negatively as well as positively: disabling the anchor comparison turns exactly the two anchor cases red, and treating a 404 as success turns exactly the missing-file and unreadable-repository cases red. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Every one of these was a live 404 in published documentation, found by the check rather than by a reader - which is the whole point of it. Process-PSModule moved its framework tests from 'scripts/tests' into '.github/actions/Test-PSModule/src/tests', and renamed 'Publish-Docs.yml' to 'Publish-Site.yml'. Test-PSModule's README no longer carries the 'SourceCode tests' and 'Module tests' sections the two anchors pointed at, so those links now point at the test settings themselves, which is where the behaviour they describe actually lives. 'DEPENDENCIES.md' no longer exists in Process-PSModule and has no successor anywhere in the organization, so the sentence promising it now points at the workflows and actions that make up the composition. The Checkout-GitHubRepo link is left in place and marked private: the file is there, the repository is not public, so a reader who gets a 404 now knows why. Personal accounts are outside the check's scope for the same reason - no check can speak for a repository it cannot read. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Its own workflow rather than a job in Docs.yml for two reasons. The name of a red check then says the network check failed rather than the documentation being wrong. And Docs.yml's publish job needs build, lint, links, and test, so a job there would let a GitHub outage block a Pages deploy. It also runs weekly. A target repository moves content on its own schedule, long after a pull request here has merged, and nothing in the pull-request trigger will ever notice. GITHUB_TOKEN is passed for rate-limit headroom only - 60 requests an hour anonymously against 1000 authenticated. It unlocks no private repository elsewhere, so the check still measures what an anonymous reader can reach. Docs.yml's comment claiming to be the only workflow is corrected, and its Links job now says which half of the link checking it owns. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Running the check locally without a token exhausted the anonymous limit of 60 requests an hour part way through, and it then spent another two dozen requests being told the same thing. The quota is a run-level fact, not a per-request one: the first 403 with no remaining quota now stops the rest. The message also says when no token was set, so the reader is told the one thing that would have changed the outcome rather than being left to infer it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The standard asked authors to write a link form nothing verified. It now says which links are checked, by what, and against which slug rules - including that GitHub's anchors differ from the published site's, so an author writing a cross-repository anchor knows which of the two to copy. Two consequences are spelled out because they change what an author writes: a public page must not link into a repository a reader cannot open, and a run that resolved no cross-repository link fails rather than passing on an empty set. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Pushed to make the new check go red in CI on purpose, so the run linked from the pull request shows it failing and shows what it says when it does. Reverted in the next commit. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The GitHub slug rules are expressed as '\p{Nd}' and friends, and codespell
reads the category name as a misspelling of 'And'. An ignore-regex for the
whole '\p{...}' form fixes the class rather than the one word, and leaves
ordinary spell checking intact - a probe file with 'mispelled' and
'sentance' still produces two errors.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ing anchor" This reverts commit 45c6ec5.
There was a problem hiding this comment.
Pull request overview
This PR adds CI validation for cross-repository links (into MSX-controlled GitHub orgs) so that moved files/anchors in other repositories are detected automatically, and it repairs several existing dead cross-repo links in the documentation.
Changes:
- Introduces a new PowerShell validator (
Test-CrossRepositoryLink.ps1) plus an offline Pester suite with an in-process stub GitHub API. - Adds a dedicated GitHub Actions workflow (
Cross-Repository-Links.yml) to run the cross-repository link check on PRs/pushes and weekly. - Updates documentation/standards and repairs broken links into PSModule repositories.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
tests/Test-CrossRepositoryLink.Tests.ps1 |
Adds offline Pester coverage for cross-repository link parsing, resolution, anchoring, caching, and failure classification. |
./.github/scripts/Test-CrossRepositoryLink.ps1 |
Implements the cross-repository link checker (GitHub API resolution + GitHub-style anchor validation). |
.github/workflows/Cross-Repository-Links.yml |
New workflow to run the cross-repo link check (PR/push + weekly schedule). |
.github/workflows/Docs.yml |
Clarifies that the existing Links job is intentionally network-free and that cross-repo checking lives elsewhere. |
CONTRIBUTING.md |
Documents running the new cross-repository link check locally before opening a PR. |
src/docs/Coding-Standards/Markdown.md |
Documents that links are checked and describes the new cross-repo check’s behavior/scope. |
src/docs/Ways-of-Working/Git-Worktrees.md |
Adds context that a referenced helper script link points to a private repository. |
src/docs/Capabilities/process-psmodule/pipeline-stages.md |
Repairs multiple PSModule cross-repo links to moved/renamed targets. |
src/docs/Capabilities/process-psmodule/index.md |
Replaces an obsolete dependency reference with links to current workflow/action structure. |
.github/linters/.codespellrc |
Avoids false positives from \p{...} Unicode-category escapes used in regexes. |
Suppressed comments (2)
src/docs/Coding-Standards/Markdown.md:67
Test-CrossRepositoryLink.ps1is described here as resolving links "as published URLs", but the very next bullet scopes it togithub.comandraw.githubusercontent.com. Rewording this to explicitly say “GitHub URLs” avoids confusion with published-site (Pages) URLs.
**Into another repository** — `Test-CrossRepositoryLink.ps1` resolves the links this standard asks you to write as published URLs. It runs as its own job, so a red check says the network check failed rather than the documentation being wrong, and again weekly, because a target repository moves content long after a pull request here has merged.
src/docs/Capabilities/process-psmodule/pipeline-stages.md:244
- Grammatically, “tests” is plural, so the verb should be “verify” (or rephrase to a singular subject like “test suite”).
The [PSModule - Module tests](https://github.com/PSModule/Process-PSModule/blob/main/.github/actions/Test-PSModule/src/tests/Module/PSModule/PSModule.Tests.ps1) verifies the following coding practices that the framework enforces:
| - **Use sentence-style headings.** | ||
| - **Surround headings, lists, and fenced blocks with a blank line** for readability, even though the linter no longer enforces it. | ||
| - **Prefer relative links** within a repository; use the canonical published URL for cross-repository references. | ||
| - **Prefer relative links** within a repository; use the canonical published URL for cross-repository references. Both forms are checked in CI — see [Links are checked](#links-are-checked). |
There was a problem hiding this comment.
Right, and that sentence was doing exactly what this pull request exists to stop — a standard claiming a gate it does not have.
Fixed in d00db90. The bullet now says relative links, and cross-repository links on \github.com, are checked in CI, the section says the check resolves \github.com\ links rather than 'the links this standard asks you to write as published URLs', and there is a paragraph naming what is not covered: a \msxorg.github.io\ URL, which is the canonical form for a repository publishing to Pages. That gap is #150, which also records why it was not simply added here — a pull request adding a page and linking its published URL would fail until the page is published.
A link of the form 'github.com/OWNER/REPO/tree/REF' carries a reference and no path, and the check only asked whether the repository existed. A renamed or deleted branch passed as resolved - the one thing that link form actually asserts went unverified. It now asks the contents endpoint for the repository root at that reference, so an unknown branch, tag, or commit answers 404 and is reported by name. Proven the same way as the rest: reverting the routing condition turns exactly the new case red. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The standard claimed both link forms it recommends are checked. Only one is. The canonical published URL for a repository that publishes to Pages is a 'msxorg.github.io' URL, and nothing verifies those - the gap is now named in the standard and carried by #150 rather than being papered over by the sentence that was supposed to close it. The Process-PSModule tables are also introduced by 'tests ... verify' rather than 'verifies', on the two lines whose links moved. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.
Suppressed comments (1)
src/docs/Capabilities/process-psmodule/pipeline-stages.md:66
- Grammar: this sentence is missing “to” (“…is used by … evaluate…”). As written it’s ungrammatical and slightly harder to read in the rendered docs.
- [PSModule framework settings for style and standards for source code](https://github.com/PSModule/Process-PSModule/tree/main/.github/actions/Test-PSModule/src/tests/SourceCode)
- This produces a JSON-based report that is used by [Get-PesterTestResults](#get-test-results) evaluate the results of the tests.
…duces (#16) `ConvertTo-GitHubSlug`'s example claimed the wrong answer. It said `Bruksordning for veg - § 3-8` slugs to `bruksordning-for-veg---3-8`; it slugs to `bruksordning-for-veg----3-8`. Four hyphens, not three. The section sign is dropped and the space on each side of it survives, so `veg`, space, hyphen, space, space, `3-8` becomes four hyphens in a row. Anyone copying the example to work out an anchor by hand would have got it wrong. --- <details> <summary>Technical details</summary> Found while reusing `ConvertTo-GitHubSlug` and `Get-RenderedHeadingText` in MSXOrg/docs#145, which adds a cross-repository link check and takes GitHub's slug rules from here rather than writing a third dialect. The function is correct; only the `.EXAMPLE` line was wrong. Verified against `github-slugger` 2.0.0 — the library GitHub's own anchors come from — over fourteen headings including this one: ```text "Bruksordning for veg - § 3-8" => "bruksordning-for-veg----3-8" ``` The PowerShell implementation returns the same string for all fourteen, so the character class here and github-slugger's generated table agree on every case tested. That comparison is now a recorded fixture in `tests/Test-CrossRepositoryLink.Tests.ps1` in MSXOrg/docs. No behaviour change; comment-based help only. </details> <details> <summary>Relevant issues (or links)</summary> - MSXOrg/docs#145 </details> Co-authored-by: Marius Storhaug <MariusStorhaug@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Documentation that points to MSX-controlled GitHub repositories now stays trustworthy after a target changes. Each link's file and referenced heading are verified in pull requests and weekly, with results that distinguish a broken link from a target that cannot be reached.
New: Cross-repository link verification
Links to files and headings in MSX-controlled repositories are now checked before documentation is published and again each week. When a target has moved, its heading no longer exists, or readers cannot access it, the check identifies the link and the reason instead of leaving a dead reference for readers to find.
The check accepts only targets that an anonymous reader can open. No author workflow changes are needed: continue using the canonical cross-repository URLs prescribed by the Markdown standard.
Technical details
.github/scripts/Test-CrossRepositoryLink.ps1, its 31-case Pester suite, and a separate scheduledCross-repository linksworkflow.github.comandraw.githubusercontent.comlinks intoMSXOrg,PSModule, andStorhaug-ting, including repository paths, named references, files, and GitHub-rendered heading slugs.GITHUB_TOKENprovides rate-limit headroom only and does not make private targets valid public references..github/scripts/**(PowerShell)tests/**(PowerShell).github/workflows/**.github/linters/**src/docs/**,CONTRIBUTING.mdIssue convergence sweep: scoped to open documentation-link validation work and the affected repositories. #142 is fully delivered; no other delivery issue is fully satisfied by this diff.
Relevant issues (or links)
Related work