Skip to content

Generated reference documentation is part of documentation closure, from its source to its public URL

Generated reference documentation is part of documentation closure, from its source to its public URL

majordomus://rule/project.the-crate-reference-is-published@1active rustdocumentationwebpublicationtesting

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.

  1. Source. Every exported item is documented, and carries what project.rust-public-api-quality asks of it. This rule adds no threshold: missing_docs with -D warnings and the rust-quality ratchet are the coverage policy.
  2. Generation. One producer, scripts/rust-check --doc, runs the same cargo doc invocation the gate proves warning-free — there is exactly one such line — and writes target/web/rustdoc/ with a surface.json that 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.
  3. Embedding. The surface rustdoc is declared by discovery from the crate, in the topology whether or not the producer has run, mounted at /rustdoc and available both to a running process and to the publication. The committed topology projection carries no value that differs between checkouts.
  4. Routing. majordomus serve answers /rustdoc/ from the tree, and the publication carries the tree at the same mount. No path to it is written anywhere but its declaration.
  5. 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.
  6. 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.
  7. 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.
  8. Deployed verification. Once the site serves the deployed commit, the public reference is verified against it: its declaration and the crate's own COMMIT page 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 rustdoc exits 10 with 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 exits 12 when there is no tree to judge, which is never reported as a pass over nothing (project.empty-is-not-failure).
  • scripts/site-build exits 12 when a surface the topology publishes has no artifact, naming the producer that writes it, and 10 when the site itself already fills the surface's mount.
  • scripts/site-check fails (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.json records it differently.
  • scripts/ci/link-check exits 10 for a link from a site page into /rustdoc/ that does not resolve in the composed tree.
  • scripts/pages verify-rustdoc fails when the public reference is absent, broken or built from a commit other than the one deployed. In pages.yml it is a hard step, so the deployment run is red; in scripts/ci/pages-check it is a section of the pages-live gate, which asks again on the next full validation and at finish.
  • majordomus web validate, the web-topology gate, 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.

Where this comes from

canonical file
.ai/repo/rules/project/the-crate-reference-is-published.v1.md
identity
project.the-crate-reference-is-published@1
also served as
MCP resource majordomus://rule/project.the-crate-reference-is-published@1 · majordomus entity show rule/project-the-crate-reference-is-published-1 · GET /api/v1/entity?uri=majordomus://rule/project.the-crate-reference-is-published@1
in the Cockpit
/cockpit/objects/rule/project-the-crate-reference-is-published-1

This page is generated from the file above by scripts/generate-site-data; editing the page changes nothing, editing the file changes every surface. The relations above are edges of docs/generated/graph.json, which the executable writes from the same index.

Searches the titles and descriptions of every page this site publishes.