Skip to main content

Module check_guide_links

Module check_guide_links 

Expand description

cargo dev check-guide-links — G15: every guide citation names a live page.

§Why this is a separate command

M7.D7 de-internalised the public rustdoc: it replaced docs/design/… citations with links to the guide. With no site deployed it had to use the repository form — a github.com/…/blob/main/docs/<page>.md URL — which resolves but points at the source file rather than at the published page, and pins a moving main rather than a version (§1.3.80). M7.D9 swept all 131 of them — 127 in the six documented crates, 4 republished onto generated pages — to crate::markdown::SITE_PAGE_PREFIX, and this command is what keeps them swept.

It earns its place on the second check. Nothing in the tree notices today when a doc comment cites a guide page that has been renamed or deleted: rustdoc does not resolve URLs, mkdocs build --strict never sees a doc comment, and G14 checks the API map rather than prose. A citation of concepts/storage/ after that page is renamed is a link that looks right in every review and 404s for every reader.

§The four checks

  1. No repository form survives. No file outside docs/design/ spells any of REPOSITORY_DOCS_PREFIXES — both of GitHub’s, the file form and the directory form. The sweep stays swept: a doc comment written next year cannot quietly reintroduce a repository link, which is how the first 131 accumulated.

  2. Every site-absolute citation names latest, and a page that exists. A …/latest/<section>/<page>/ URL is parsed back to docs/<section>/<page>.md and the file is required. This is the check nothing else in the tree can make.

    The scan keys on the site root, so it finds a citation naming any version segment and then requires the segment to be markdown::SITE_VERSION. Keying on the whole …/latest/ literal — which is what it did until §1.3.141 was closed — meant it could only ever see the citations that were already right: …/atune/dev/concepts/nonexistent/ was not a citation to it at all, and passed every check while naming nothing. The exceptions are VERSION_EXEMPT and are printed on every green run.

  3. No generated page under docs/ carries a site-absolute URL. Rule (4)’s invariant, checked over the files on disk rather than trusted: crate::markdown::site_links_page_relative is what makes such a URL page-relative, so one surviving means the rewrite did not fire — the page was hand-edited, the citation arrived in a spelling the rewrite refuses (an autolink or bare prose, neither of which has a page-relative form), or the rewrite no longer runs at all. The list of generated pages comes from generate_all::generators, never from a constant here, so a tenth generator is covered by existing.

  4. No doc comment of a registry crate cites the internal corpus. M7.D7 swept 341 such lines out of the five crates that reach crates.io or PyPI and nothing stood guard over the result, so the invariant held only until somebody edited a doc comment. See REGISTRY_CRATES — including for the half that is counted rather than gated, and why.

§What this command covers, and what it does not

It reads every UTF-8 file in the repository except the directories in SKIPPED, symbolic links included and each target walked once, so a citation in a doc comment, a README, a page, a workflow, a manifest comment or a runtime message string is all equally in scope. That breadth is the point: the 131 occurrences the sweep found lived in .rs, .md and .pyi files, and two of them were format! strings a reader sees at run time rather than doc comments at all.

docs/design/** is exempt from all four checks, deliberately. It is the internal design corpus (D25), mkdocs.yml’s exclude_docs keeps it off the site, and it has to be able to quote what the rest of the tree may not write: §1.3.80 records the repository form, and §2’s D38 quotes a …/api/rust/… URL to show both branches of the link resolver. An exemption that cannot be stated is a hole; this one is stated here, in EXEMPT, and on every green run’s own output. It is matched as a path rather than as a string prefix, so it exempts that directory and nothing that merely begins with its name (is_exempt).

A site URL under one of NOT_A_PAGE is skipped by check 2, and that is a genuine gap rather than a tidy exclusion — see the constant.

Three things it cannot see, each already owned elsewhere:

  • whether a page-relative link resolves. mkdocs build --strict with validation.links.not_found and validation.links.anchors does that, on every build, which is the whole reason rules (3) and (4) emit relative links at all (D38 sub-decision 3).
  • whether a generated page equals what its generator would write. generate-all --mode check (G7) does that. This command reads the file on disk, so the two are a pair in the same sense G7 and G14 are: a hand-edited page that reintroduced an absolute URL fails here, and a generator that would emit one fails there.
  • whether a docs.rs URL is right. atune_derive cannot use an intra-doc link — atune depends on it, so the reverse dependency does not exist — so its three citations are hand-spelled docs.rs URLs and must stay absolute. Nothing here or anywhere else resolves them; the anchor they name was verified against a real cargo doc tree by hand at M7.D9b.

Constants§

CHECKER 🔒
This command’s name, for fail-closed error messages.
DOCS_DIR 🔒
Where a guide page lives, for turning a site URL back into a file.
EXEMPT 🔒
The one directory exempt from every check, relative to the repository root.
INTERNAL_CORPUS 🔒
The internal corpus, as a doc comment would spell it.
NOT_A_PAGE 🔒
Site paths that are not published from a docs/**.md page, so check 2 has no file to look for.
REGISTRY_CRATES 🔒
The crates whose doc comments may not cite the internal corpus, and the crates whose doc comments still do.
REPOSITORY_DOCS_PREFIXES 🔒
The repository forms M7.D7 used and M7.D9b swept away.
SKIPPED 🔒
Directory names never descended into.
VERSION_EXEMPT 🔒
Files allowed to name a version segment other than latest, with the reason.

Functions§

check_generated_pages 🔒
Check 3: no generated page under docs/ publishes a site-absolute URL.
check_internal_corpus 🔒
Check 4: no doc comment of a registry crate cites the internal corpus.
check_page_exists 🔒
Check 2: the page a site-absolute citation names exists.
check_repository_form 🔒
Check 1: no repository form appears anywhere.
cites_corpus 🔒
Does this line cite the internal corpus from a rendered doc comment?
collect_files 🔒
Every file under directory, skipping SKIPPED directory names.
crate_of 🔒
The crate a crates/<name>/src/… path belongs to.
is_exempt 🔒
Is this repository-relative path inside the exempt directory?
page_source 🔒
The docs/ source file a site URL’s path came from.
relative_to_root 🔒
A path as the repository-relative, /-separated string a message should name.
report_internal_corpus 🔒
Prints what the published /api/rust/ tree still carries, and from where.
run
Runs the four checks, reporting every failure rather than the first.
site_citations 🔒
Every site-absolute citation on one line, as (version segment, page path).
unclassifiable 🔒
Wraps a message as this command’s fail-closed error.
wrong_version 🔒
A citation naming a version segment this tree may not write.