cargo doc --no-deps emits 108 warnings across the workspace (101 of them in simlin-engine), and nothing gates them. Neither scripts/pre-commit nor any CI workflow invokes cargo doc -- grep -rn "cargo doc\|rustdoc\|RUSTDOCFLAGS" scripts/ .github/ returns zero hits. So broken doc links have accumulated silently and the count can only go up.
Discovered incidentally while working on the conveyor-engine branch (unrelated to that work).
Current state
$ cargo doc --workspace --no-deps 2>&1 | grep "generated .* warnings"
warning: `simlin-engine` (lib doc) generated 101 warnings
warning: `simlin-mcp-core` (lib doc) generated 3 warnings
warning: `simlin-serve` (lib doc) generated 4 warnings
Breakdown of the 101 simlin-engine warnings by lint:
| Count |
Lint |
| 50 |
rustdoc::private_intra_doc_links |
| 39 |
rustdoc::broken_intra_doc_links |
| 10 |
rustdoc::invalid_html_tags |
| 2 |
rustdoc::redundant_explicit_links |
By file: vdf.rs (16), queue_compile.rs (11), ltm_agg.rs (11), ltm_post.rs (9), common.rs (8), test_common.rs (7), ltm/mod.rs (7), conveyor_compile.rs (6), datamodel.rs (4), project_io.gen.rs (8, generated), remainder scattered.
The four classes are not equally mechanical
1. broken_intra_doc_links (39). Two very different sub-cases:
- Real broken links (~8): bare
[ConveyorNotExpanded], [ConveyorNonEulerMethod], [ConveyorDrivenFlowRead], [ConveyorInSubmodelUnsupported], [QueueState], [LtmCircuitBudgetGuard], [AggNode::read_slice]. These are doc comments in conveyor_compile.rs / queue_compile.rs that meant to reference ErrorCode variants. Fix: [`ErrorCode::ConveyorNotExpanded`] or plain text.
- Not links at all (~31, the majority): array/subscript notation in prose being parsed as markdown link syntax --
[0] (7), [dims] (6), [6] (4), [11] (4), [10] (3), [1] (3), [0,1] (2), [12], [dim1,dim2]. Fix: wrap in backticks. This sub-case is worth calling out because a naive "resolve the link" pass would mangle it, and because subscript notation in doc comments will keep reintroducing it -- which is exactly why the gate matters.
2. private_intra_doc_links (50). Larger and broader than a single offender. CanonicalStorage (3, from CanonicalDimensionName / CanonicalElementName / Ident in common.rs) is only a small slice. The bulk are LTM/conveyor/queue internals referenced from public docs: denom_summand (5), apply_couplings (4), variable_backed_reduce_agg (3), normalized_init_total (3), accept_source_slices (3), serve_secondary_outflows (2), container_value_from_slice (2), effective_slot (2), variable_backed_shape_is_expressible (2), NormGroup::Solo (2), and ~20 singletons. Each needs a judgment call: make the item public, drop the link to plain text/backticks, or restructure the doc. Not mechanical.
3. invalid_html_tags (10). 8 are in src/project_io.gen.rs, which is generated by prost and hash-pinned (project_io_gen_is_up_to_date test in lib.rs). These cannot be hand-fixed -- they'd be clobbered by pnpm build:gen-protobufs, and the hash check would fail. Fortunately the module is included via #[path] at src/simlin-engine/src/lib.rs:72-73:
#[path = "project_io.gen.rs"]
pub mod project_io;
so #[allow(rustdoc::invalid_html_tags)] can be attached at the mod declaration, outside the generated file. The other 2 are real (xmile/model.rs:675,687).
4. redundant_explicit_links (2). queue_compile.rs:789, queue_compile.rs:1393. Trivial.
Why it matters
- Broken links render as literal
[Foo] text in generated docs -- the cross-references silently do nothing.
private_intra_doc_links means public API docs point at items readers cannot navigate to.
- No gate means the count only grows. The conveyor/queue links in class 1 were introduced recently and nothing caught them.
- Documentation quality is load-bearing here: the repo's own standards (
CLAUDE.md, "Comment and Rustdoc Standards") require rustdoc on public items and non-trivial internal functions.
Components affected
src/simlin-engine (primary), src/simlin-mcp-core (3), src/simlin-serve (4), plus CI config (.github/workflows/).
Suggested approach
- Fix class 4 and the real-link half of class 1 (small, unambiguous).
- Backtick the subscript-notation false links (class 1, bulk).
- Add
#[allow(rustdoc::invalid_html_tags)] on the project_io mod declaration; fix the 2 real ones in xmile/model.rs.
- Work through class 2 with per-item judgment (publicize vs. de-link).
- Add a CI job running
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps. Deliberately not in scripts/pre-commit -- a full doc build is slow, and the pre-commit Rust pipeline is already under a 3-minute cap.
Steps 1-3 and 5 could land together (with step 4's lint temporarily #![allow]-ed at the crate root and burned down separately) so the gate goes in before the long tail is finished, preventing regressions in the meantime.
cargo doc --no-depsemits 108 warnings across the workspace (101 of them insimlin-engine), and nothing gates them. Neitherscripts/pre-commitnor any CI workflow invokescargo doc--grep -rn "cargo doc\|rustdoc\|RUSTDOCFLAGS" scripts/ .github/returns zero hits. So broken doc links have accumulated silently and the count can only go up.Discovered incidentally while working on the conveyor-engine branch (unrelated to that work).
Current state
Breakdown of the 101
simlin-enginewarnings by lint:rustdoc::private_intra_doc_linksrustdoc::broken_intra_doc_linksrustdoc::invalid_html_tagsrustdoc::redundant_explicit_linksBy file:
vdf.rs(16),queue_compile.rs(11),ltm_agg.rs(11),ltm_post.rs(9),common.rs(8),test_common.rs(7),ltm/mod.rs(7),conveyor_compile.rs(6),datamodel.rs(4),project_io.gen.rs(8, generated), remainder scattered.The four classes are not equally mechanical
1.
broken_intra_doc_links(39). Two very different sub-cases:[ConveyorNotExpanded],[ConveyorNonEulerMethod],[ConveyorDrivenFlowRead],[ConveyorInSubmodelUnsupported],[QueueState],[LtmCircuitBudgetGuard],[AggNode::read_slice]. These are doc comments inconveyor_compile.rs/queue_compile.rsthat meant to referenceErrorCodevariants. Fix:[`ErrorCode::ConveyorNotExpanded`]or plain text.[0](7),[dims](6),[6](4),[11](4),[10](3),[1](3),[0,1](2),[12],[dim1,dim2]. Fix: wrap in backticks. This sub-case is worth calling out because a naive "resolve the link" pass would mangle it, and because subscript notation in doc comments will keep reintroducing it -- which is exactly why the gate matters.2.
private_intra_doc_links(50). Larger and broader than a single offender.CanonicalStorage(3, fromCanonicalDimensionName/CanonicalElementName/Identincommon.rs) is only a small slice. The bulk are LTM/conveyor/queue internals referenced from public docs:denom_summand(5),apply_couplings(4),variable_backed_reduce_agg(3),normalized_init_total(3),accept_source_slices(3),serve_secondary_outflows(2),container_value_from_slice(2),effective_slot(2),variable_backed_shape_is_expressible(2),NormGroup::Solo(2), and ~20 singletons. Each needs a judgment call: make the item public, drop the link to plain text/backticks, or restructure the doc. Not mechanical.3.
invalid_html_tags(10). 8 are insrc/project_io.gen.rs, which is generated by prost and hash-pinned (project_io_gen_is_up_to_datetest inlib.rs). These cannot be hand-fixed -- they'd be clobbered bypnpm build:gen-protobufs, and the hash check would fail. Fortunately the module is included via#[path]atsrc/simlin-engine/src/lib.rs:72-73:so
#[allow(rustdoc::invalid_html_tags)]can be attached at themoddeclaration, outside the generated file. The other 2 are real (xmile/model.rs:675,687).4.
redundant_explicit_links(2).queue_compile.rs:789,queue_compile.rs:1393. Trivial.Why it matters
[Foo]text in generated docs -- the cross-references silently do nothing.private_intra_doc_linksmeans public API docs point at items readers cannot navigate to.CLAUDE.md, "Comment and Rustdoc Standards") require rustdoc on public items and non-trivial internal functions.Components affected
src/simlin-engine(primary),src/simlin-mcp-core(3),src/simlin-serve(4), plus CI config (.github/workflows/).Suggested approach
#[allow(rustdoc::invalid_html_tags)]on theproject_iomoddeclaration; fix the 2 real ones inxmile/model.rs.RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps. Deliberately not inscripts/pre-commit-- a full doc build is slow, and the pre-commit Rust pipeline is already under a 3-minute cap.Steps 1-3 and 5 could land together (with step 4's lint temporarily
#![allow]-ed at the crate root and burned down separately) so the gate goes in before the long tail is finished, preventing regressions in the meantime.