Rationale
For as long as this repository had a Rust crate, its gate rendered the crate's reference
documentation on every run and threw the result away. scripts/rust-check ran
RUSTDOCFLAGS='-D warnings' cargo doc --no-deps --quiet, proved that every exported item was
documented and that the pages rendered without a warning, and left the pages where cargo wrote
them. No web surface declared them, no build step carried them, the publication job had no
Rust toolchain, the public verification read one file that could not tell whether they were
there, and nothing mapped an item to the page rustdoc gives it. When the owner asked on
2026-09-24 where the reference was, every candidate route of the public site answered 404.
Nothing in that list is a defect of the documentation. Each is a stage after the renderer that nothing owned, and the gate's green was read — by nobody in particular, which is how it happens — as though the reference existed. A check at one stage says nothing about the next seven. That is the general shape this rule refuses, and generated reference documentation is where this repository met it: a closure is valid only when every stage is decided, and the stage with the most evidence behind it is usually the first.
The second half is how each stage is decided. A reference is a large set — every item, every page, every link — and the tempting way to check a large set is a list. A list of modules kept for the reference's check goes stale the first time the crate gains one, and it goes stale in the direction that passes: the new module is not on the list, so its missing page is not a finding. The sets are therefore derived: the items from the crate's own measurement of itself, the routes from the items by the toolchain's convention, the mount from the surface's declaration, and what the publication carries from the resolved topology.
Required behaviour
Every stage of the closure holds, and each is decided by something executable.
- Source. Every exported item is documented, and carries what
project.rust-public-api-qualityasks of it. This rule adds no threshold:missing_docswith-D warningsand therust-qualityratchet are the coverage policy. - Generation. One producer,
scripts/rust-check --doc, runs the samecargo docinvocation the gate proves warning-free — there is exactly one such line — and writestarget/web/rustdoc/with asurface.jsonthat records the commit it was built from and a landing page. No second invocation exists for publication and the library's private items are not documented, because what is published must be what the gate proved and what ADR 0028 decides is public; the executable is documented as cargo documents any binary target. - Embedding. The surface
rustdocis declared by discovery from the crate, in the topology whether or not the producer has run, mounted at/rustdocand available both to a running process and to the publication. The committed topology projection carries no value that differs between checkouts. - Routing.
majordomus serveanswers/rustdoc/from the tree, and the publication carries the tree at the same mount. No path to it is written anywhere but its declaration. - References. Every exported item has its page at the route derived from its path and
kind, no item page exists without its item, every internal link of the tree resolves, and a
link from a site page into
/rustdoc/resolves against the composed tree. A site page that describes a module the crate exports links that module's page, through the same module routes the check derives, and only in a build that composed the reference. - Tests. Each stage has a case that breaks it and watches the refusal. A case that cannot reach its subject says so rather than passing.
- Deployment. The publication is composed from the committed topology: every published static surface is copied to its mount, with no line naming this one. A published surface whose artifact is absent refuses the build and names its producer, and a composed surface built from another commit than the build is refused before anything is pushed. The tree is produced in CI and never committed.
- Deployed verification. Once the site serves the deployed commit, the public reference is
verified against it: its declaration and the crate's own
COMMITpage name that commit, and the crate's index answers with its identity. A deployment that fails this is a failed deployment.
Inventories and routes come from canonical metadata. The item inventory is
quality::source::Inventory, the crate's syntax-tree measurement; the routes are derived from
it; the mount is the surface's declaration; the composition is docs/generated/web.json. A
list of modules, items, pages or routes written for one consumer is a defect regardless of
whether it currently agrees, unless it is generated and a check refuses its drift.
A generation that succeeded is not evidence of a deployment. The cargo doc step going green
says the pages render; it says nothing about whether they are served, composed, complete,
current or public, and no report may present it as though it did.
Failure behaviour
majordomus quality rustdocexits10with one finding per violation — an item without its page, a page without its item, a tree built from another commit or declaring none, a crate index without its identity, an index asset missing, an internal link that does not resolve, a machine path or a secret in a page — each naming the item or page and the remedy. It exits12when there is no tree to judge, which is never reported as a pass over nothing (project.empty-is-not-failure).scripts/site-buildexits12when a surface the topology publishes has no artifact, naming the producer that writes it, and10when the site itself already fills the surface's mount.scripts/site-checkfails (section 13m) when a composed surface is missing from the build, carries no declaration, declares another id or mount than the topology, or was built from a commit other than the build's, and when/build.jsonrecords it differently.scripts/ci/link-checkexits10for a link from a site page into/rustdoc/that does not resolve in the composed tree.scripts/pages verify-rustdocfails when the public reference is absent, broken or built from a commit other than the one deployed. Inpages.ymlit is a hard step, so the deployment run is red; inscripts/ci/pages-checkit is a section of thepages-livegate, which asks again on the next full validation and atfinish.majordomus web validate, theweb-topologygate, refuses a topology in which the surface collides with another or nests inside one.
The gates are rust-check (whose rustdoc step denies warnings and produces the tree),
rustdoc (the integrity check over the tree that run produced, which it requires; both in the
rust job), site-build (composition and the static checks over the composed tree),
web-topology, and pages-live.
Verification
test/cases/486_rustdoc_composition.sh through test/cases/490_rustdoc_new_module.sh, and
test/cases/492_rustdoc_module_links.sh, one stage each:
- 486: composition — the site build carries the reference at its mount from the topology, and refuses, naming the producer, when the artifact is absent.
- 487: staleness — a tree built from another commit is refused by the integrity check and by the public verification.
- 488: discoverable and reachable — the surface is in the topology and its projections whether
or not the producer ran, and a served process answers
/rustdoc/. - 489: deployment — the composed tree is deployed to a bare remote and the published branch carries the reference built from the commit the deployment names.
- 490: completeness — a module added to a fixture crate becomes a required page without a list being edited, and its absence is a finding.
- 492: referenced — every builtin module's site page links its rustdoc page exactly when the check derives one for it, the linked file is in the composed tree, and a build whose topology lacks the reference links none.
The crate's own suites hold the two Rust halves:
cargo test --manifest-path apps/majordomus-cli/Cargo.toml quality::rustdoc for the integrity
check — a clean tree has no finding and each way of failing produces its own — and
cargo test --manifest-path apps/majordomus-cli/Cargo.toml web::discover for the declaration —
present before the producer runs, checkout-independent in the committed projection — and
apps/majordomus-cli/tests/http_serve.rs for the tree served whole over a real socket.
scripts/rust-check, scripts/site-build, scripts/site-check, scripts/ci/link-check,
scripts/pages and scripts/ci/pages-check are the executable stages the cases break. The
decision is ADR 0086; the operating document is docs/RUSTDOC.md.