Documentation: cover every module, map what lives where, and halve CI wall time - #5
Conversation
CI. The `test` job ran `cargo test` and then `cargo llvm-cov` as
consecutive steps, so its wall time was their sum -- fifteen to nineteen
minutes against about two hundred seconds locally. llvm-cov is not a
reporting step that reads what `cargo test` produced; there is nothing
to read. It compiles the crate with -C instrument-coverage into its own
target directory and runs the whole suite again, because running the
tests is how it collects coverage. The two therefore do the same work
twice whatever we do, and the only question is series or parallel. They
are now separate jobs, so the wall time is the slower of them and the
plain test result comes back without waiting behind the instrumented
rebuild.
Two other things turned up in that file.
The cache was doing nothing. It cached ~/.cargo/registry and
~/.cargo/git, which are empty for a crate whose Cargo.lock holds exactly
one package -- itself -- and keyed on hashFiles('**/Cargo.lock'), which
therefore never changes, so after the first save it restored a stale
tree and never wrote again. Every run logged "Cache hit occurred on the
primary key, not saving cache". Replaced with Swatinem/rust-cache@v2,
already used by verify.yml, which keys on the compiler version and the
job and saves each run. The two jobs get separate keys, which is the
point: instrumented artifacts fingerprint differently and sharing one
cache between them would thrash it.
The separate `cargo build` step is gone -- `cargo test` builds the same
artifacts -- and verify.yml's comment saying five tests carry
cfg_attr(miri, ignore) said five when there are six.
README. It claimed 1,659 tests at 99.98% coverage across 67 files, and
described none of transforms, dsp, resonance, audio, cfd, manifold,
exact, discrete, graph, codes, stochastic, optimization, fem, learn,
finance or units. Rewritten against measured numbers: 6,365 public
functions and methods, 429 public types, 71 top-level modules across 296
files, 265,190 lines, 4,193 unit tests, 577 property tests, 97.89% line
and 99.33% function coverage, 20 Kani harnesses.
Every domain now carries the governing equations the code actually
implements -- Galerkin orthogonality and the Pythagoras identity for
FEM, the leapfrog energy and Courant condition for FDTD, Buckingham's
theorem as a rank computation, the Baillie-PSW composition, LP duality
and the KKT conditions, Black-Scholes with put-call parity, the
Hodgkin-Huxley currents, Marchenko-Pastur, and so on. A "how it's
tested" section explains why the coverage figure is not the interesting
number, with the three rare branches that mutation found sitting behind
full coverage.
A script checked all 158 module references in the prose against the
source tree; every one resolves, and all 71 top-level modules are
covered. The equations were proofread against their definitions, which
caught a mismatched contraction index in the Riemann tensor and an
ambiguous Marchenko-Pastur support.
The Quick start snippet is now examples/readme_quickstart.rs, run by CI,
so the front page of the repository cannot drift out of date. Its
assertions are the check.
4,193 lib tests, 577 property tests, clippy clean under --all-targets
-D warnings, nightly-2025-11-21 clean.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUkMGnfUbaopkUJLWeYCYi
The README rewrite covered the front page but not the documentation the
crate actually publishes, and `cargo doc` was emitting 81 warnings.
They are rendering bugs rather than style. Rustdoc parses `[k]` in a
formula as an intra-doc link, so `X[k] = Σ x[n]·e^(−j2πkn/N)` rendered
with two broken links in it and no way for a reader to see the formula
as written. It parses `<counts>` and `<R>` as HTML tags, so
`"B<counts>/S<counts>"` and `R = <R>_0 + <R>_2` lost content in the
rendered output entirely. Fifty-one doc comments were affected, across
transforms, statistics, signal_processing, dsp, linalg, biophysics,
chemistry, color_science, manifold, fractals, sim, numerical and core.
Each is now wrapped in backticks so it renders as the mathematics it is.
Three cases needed more than that:
- Two-line Mur boundary formulas in sim/wave_sim.rs became a ```text
block, which is what they always were.
- Three links pointed at private items -- MAX_QUBITS, RESTARTS and
mc_table -- which rustdoc cannot link to. They now name the item as
code, with its value where that is the useful part.
- audio/effects.rs linked [`read`] from a sibling method, which does
not resolve without the Self:: prefix. Its summary also read "Alias
of read for tap taps", which was a typo for nothing in particular.
CI now builds the documentation with RUSTDOCFLAGS=-D warnings in the
test job, so the count stays at zero.
docs/ROADMAP_PART4.md carried no indication that the work in it was
finished. It now opens with a status block recording that all thirty
sessions plus the two unlisted cross-references are delivered, and what
the test counts went from and to. The body is left exactly as written --
it is the specification the work was built against, and the signatures
in it are the ones that shipped.
README gains the documentation facts in the stats table, the
`cargo doc` invocation, and a Further reading section pointing at the
roadmap.
cargo doc --no-deps: 0 warnings, from 81. 4,193 lib tests, 577 property
tests, clippy clean under --all-targets -D warnings, nightly-2025-11-21
clean.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUkMGnfUbaopkUJLWeYCYi
Sixty-three of the 296 source files had no `//!` module documentation at
all, so they rendered as blank pages. Among them was src/lib.rs, which
is the landing page of the whole generated documentation -- the first
thing anyone opening the docs sees was empty.
lib.rs now carries an orientation page: what the library is for and the
principle the API shape follows, a table routing the 71 top-level
modules by subject, and the three conventions a caller has to know
(SI units and radians; f64 except where exactness is the point; and that
monte_carlo::Rng is an LCG whose low bits are short-period, so
Rng::below is the one to use).
The other 62 are documented from what they actually contain, and each
says something a reader would otherwise have to work out: that Sabine's
reverberation formula never reaches zero however absorptive the room and
Eyring's does; that metals yield on the deviatoric stress alone, which
is why von Mises ignores hydrostatic pressure; that the chirp mass is
the combination an inspiral waveform actually determines; that Verlet is
used in the cloth solver because velocity is inferred from positions
rather than integrated; that the buildup factor matters because ignoring
it underestimates dose behind a thick shield; that L4 and L5 are stable
below a mass ratio of about 1/24.96, which is why the Trojans stay put.
Cross-references point at the fuller treatment where one exists -- from
sim/ to cfd/ and fem/, from gravitation to astrophysics and general
relativity, from optics to photonics.
Three links needed disambiguating: `cholesky`, `svd` and
`transforms::fft` are each both a module and a function, so they are now
written `mod@`.
docs/MODULE_MAP.md is the "what exists where" document: a size-annotated
tree of all 295 modules, tables by subject area, and a row per module
with its line count, public function, method and type counts, and
summary. It is generated by tools/gen_module_map.py rather than written,
because a hand-maintained map of 295 modules is stale the day after it
is written. Every figure is parsed from the sources -- counts skip
anything inside #[cfg(test)] by tracking brace depth, and summaries are
the first sentence of each module's //! block.
Getting the totals to reconcile took two corrections. `verification` is
declared `mod` rather than `pub mod`, so counting it gave 72 top-level
modules against the README's 71; it is now excluded and labelled
private. And excluding lib.rs from the line total made the map disagree
with `wc -l` over src/ by exactly lib.rs's length; the crate root is now
counted, and the map's 266,122 matches `wc -l` exactly.
Two CI gates keep all of this honest, both tested in each direction
before committing:
- `gen_module_map.py --check` re-derives the map and fails if the
committed copy differs.
- `check_module_docs.py` fails if any source file lacks a `//!`
summary. Nothing else catches this: rustdoc's missing_docs covers
items, not modules, so an undocumented module is silent.
README gains the map in Further reading, and its line count is updated
for the documentation just added.
296 of 296 files documented. cargo doc --no-deps: 0 warnings under
-D warnings. 4,193 lib tests, 577 property tests, 2 doc tests, clippy
clean under --all-targets -D warnings, nightly-2025-11-21 clean.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUkMGnfUbaopkUJLWeYCYi
There was a problem hiding this comment.
🟡 Changes recommended
tools/gen_module_map.py has verified counting and tree-rendering bugs that make the generated docs/MODULE_MAP.md inaccurate.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR is a documentation and CI-quality pass for the crate: it adds/repairs rustdoc module-level docs across the codebase, introduces a generated module map, and reduces CI wall time by splitting coverage into a separate job and adding doc/module-map gates.
Changes:
- Added module-level (
//!) documentation across manysrc/modules and corrected rustdoc-rendering pitfalls in formula-like doc comments. - Added generated documentation artifacts and tooling (
docs/MODULE_MAP.md,tools/gen_module_map.py,tools/check_module_docs.py) and CI checks to keep them current. - Updated CI workflow to run tests, docs, module-map, and module-doc checks in the
testjob and runcargo llvm-covin a parallelcoveragejob (with rust-cache).
File summaries
| File | Description |
|---|---|
| tools/gen_module_map.py | New generator for docs/MODULE_MAP.md (counts + summaries + tree + tables). |
| tools/check_module_docs.py | New gate to ensure every Rust source file starts with a //! module summary. |
| src/waves.rs | Added module-level documentation. |
| src/trigonometry.rs | Added module-level documentation. |
| src/transforms/fft.rs | Fixed rustdoc rendering by backticking formula-like text in doc comments. |
| src/thermodynamics.rs | Added module-level documentation. |
| src/statistics/fourier.rs | Backticked formula-like doc text to avoid rustdoc link parsing issues. |
| src/spatial/octree.rs | Added module-level documentation. |
| src/solid_mechanics.rs | Added module-level documentation + cross-references. |
| src/sim/wave_sim.rs | Added module-level docs + formatted Mur boundary formulas as text block. |
| src/sim/rigid_body.rs | Added module-level documentation. |
| src/sim/mod.rs | Added module-level documentation and cross-references to other solver modules. |
| src/sim/heat_sim.rs | Added module-level docs + adjusted some unit wording in field docs. |
| src/sim/fluid_sim.rs | Added module-level documentation. |
| src/sim/em_sim.rs | Added module-level documentation. |
| src/sim/cloth_sim.rs | Added module-level documentation. |
| src/signal_processing/mod.rs | Added module-level documentation + rustdoc link fix (mod@...). |
| src/rf.rs | Added module-level documentation. |
| src/relativity.rs | Added module-level documentation. |
| src/radiation.rs | Added module-level documentation + cross-references. |
| src/quaternion.rs | Added module-level documentation + cross-reference. |
| src/quantum/circuit.rs | Replaced non-linkable private constant link with literal + value. |
| src/propulsion.rs | Added module-level documentation + cross-reference. |
| src/plasma.rs | Added module-level documentation + cross-reference. |
| src/photonics.rs | Added module-level documentation. |
| src/particle_physics.rs | Added module-level documentation. |
| src/optimization/mod.rs | Added module-level documentation with submodule pointers. |
| src/optics.rs | Added module-level documentation + cross-reference. |
| src/numerical/ode/explicit.rs | Backticked function signature text in docs to avoid rustdoc parsing. |
| src/numerical/interpolate.rs | Backticked indexing/math-like doc text. |
| src/nuclear.rs | Added module-level documentation + cross-reference. |
| src/nonlinear.rs | Added module-level documentation + cross-reference. |
| src/neutronics.rs | Added module-level documentation. |
| src/monte_carlo/mod.rs | Added module-level documentation with RNG warning section. |
| src/mesh/isosurface.rs | Replaced non-linkable private function link with literal identifier. |
| src/math.rs | Added module-level documentation + cross-reference to CODATA constants. |
| src/materials/mod.rs | Added module-level documentation describing tables. |
| src/materials/gases.rs | Added module-level documentation. |
| src/materials/fluids.rs | Added module-level documentation. |
| src/materials/elements.rs | Added module-level documentation. |
| src/materials/common.rs | Added module-level documentation. |
| src/manifold/polytope4.rs | Backticked [0,1]^n to avoid rustdoc link parsing. |
| src/manifold/metric.rs | Backticked math-like identifiers in docs to avoid intra-doc links. |
| src/manifold/clifford.rs | Backticked <...>-like content to avoid HTML-tag parsing. |
| src/magnetohydrodynamics.rs | Added module-level documentation. |
| src/linalg/tridiagonal.rs | Backticked equation to avoid rustdoc link parsing. |
| src/linalg/mod.rs | Added module-level documentation + backticked transpose equation. |
| src/linalg/matrix.rs | Backticked transpose equation. |
| src/lib.rs | Added crate-level landing/orientation docs + conventions + example snippet. |
| src/learn/cluster.rs | Replaced non-linkable private constant link with literal + value. |
| src/information_theory.rs | Added module-level documentation. |
| src/gravitation.rs | Added module-level documentation + cross-reference. |
| src/geophysics.rs | Added module-level documentation. |
| src/geometry/mod.rs | Added module-level documentation + cross-references. |
| src/general_relativity.rs | Added module-level documentation + cross-references. |
| src/fractals/mod.rs | Added module-level documentation + cross-reference. |
| src/fractals/lsystem.rs | Backticked L-system rewrite strings to avoid rustdoc parsing issues. |
| src/fractals/automata.rs | Backticked bracket/index and quoted-string examples to avoid rustdoc parsing. |
| src/fractals/attractors.rs | Backticked indexing expression in docs. |
| src/fluids.rs | Added module-level documentation + cross-reference. |
| src/fluid_instabilities.rs | Added module-level documentation. |
| src/electronics.rs | Added module-level documentation. |
| src/electromagnetism.rs | Added module-level documentation. |
| src/dsp/windows.rs | Backticked formula-like docs for window definitions. |
| src/curves.rs | Added module-level documentation + cross-references. |
| src/core/dual.rs | Backticked Jacobian indexing expression in docs. |
| src/control_systems/mod.rs | Added module-level documentation. |
| src/continuum_mechanics.rs | Added module-level documentation. |
| src/color_science.rs | Added module-level documentation + backticked range notation in docs. |
| src/classical.rs | Added module-level documentation. |
| src/chemistry.rs | Added module-level documentation + backticked equations in docs. |
| src/biophysics/mod.rs | Backticked equations/tuples in docs to avoid rustdoc parsing issues. |
| src/audio/effects.rs | Fixed intra-doc link to sibling method with Self:: prefix. |
| src/atmosphere.rs | Added module-level documentation. |
| src/astrophysics/tidal.rs | Added module-level documentation. |
| src/astrophysics/orbital_elements.rs | Added module-level documentation + cross-reference. |
| src/astrophysics/nbody.rs | Added module-level documentation + corrected cross-reference target. |
| src/astrophysics/mod.rs | Added module-level documentation describing submodules. |
| src/astrophysics/magnetosphere.rs | Added module-level documentation. |
| src/astrophysics/lagrange.rs | Added module-level documentation. |
| src/astrophysics/habitable_zone.rs | Added module-level documentation. |
| src/astrophysics/gravitational_waves.rs | Added module-level documentation. |
| src/astrophysics/collisions.rs | Added module-level documentation. |
| src/acoustics.rs | Added module-level documentation. |
| README.md | Major rewrite: updated metrics, expanded module descriptions, added CI/testing/docs/module-map explanations, and updated badges. |
| examples/readme_quickstart.rs | New CI-run example mirroring README quick start snippet. |
| docs/ROADMAP_PART4.md | Marked roadmap status as complete and added context on delivered work. |
| docs/MODULE_MAP.md | New generated module map output committed to the repo. |
| .github/workflows/verify.yml | Updated comment count about Miri-skipped tests. |
| .github/workflows/ci.yml | Split coverage into separate job, added rust-cache, added docs/module-map/module-doc gates, and ran README quickstart example in CI. |
Review details
Suppressed comments (1)
tools/gen_module_map.py:97
- Public-item counting in
scan()currently relies on whether the line starts at column 0 to decide between “free function” vs “method”, and only countspub struct/enum/traitwhen they start at column 0. This produces incorrect totals for nested modules (e.g. indentedpub fninpub mod presets { ... }) and misses public types declared inside nested modules (e.g.pub enuminsidepub mod ... {}).
- Files reviewed: 90/90 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| free = meth = types = 0 | ||
| depth = 0 | ||
| test_depth: int | None = None | ||
| summary_parts: list[str] = [] |
There was a problem hiding this comment.
Confirmed and fixed in b90cd00.
I checked before changing anything: there are 175 indented pub fn outside any impl — 89 in manifold/clifford.rs across its cl3, pga3, cga3 and sta modules, 85 across the four fractals/ preset modules, and one macro template in units/quantity.rs. Every one was landing in the method column.
scan() now tracks enclosing impl blocks on a stack, so a multi-line impl header with a where clause still opens the body at the line that actually opens the brace, and a pub fn is a method iff that stack is non-empty.
Your suppressed comment on the same function was also right, so I fixed that too: PUB_TYPE was matched against the raw line rather than the stripped one, so only types at column zero counted. That missed CgaObject inside clifford's pub mod sta and the k-d tree type inside spatial/kdtree.rs's macro.
Totals move from 3,949/2,416 to 4,124 free functions and 2,241 methods. The sum is unchanged at 6,365, which is the expected signature of a pure misclassification — both bugs only moved items between the two columns. Types go 429 → 431. README updated to match.
One case neither bug caused, now stated in the generated map so a reader is not misled: the count is syntactic, so a macro-generated item is counted once where the macro defines it rather than once per expansion. That under-counts units::quantity by roughly thirty constructors and spatial::kdtree by one type.
Generated by Claude Code
| for j, child in enumerate(children): | ||
| leaf = child.split("::")[-1] | ||
| cstem = "└── " if j == len(children) - 1 else "├── " | ||
| L.append(f"{pad}{cstem}{(leaf + '.rs'):<24}{mods[child]['lines']:>8,}") |
There was a problem hiding this comment.
Confirmed and fixed in b90cd00. src/numerical/ode/ was exactly the case that broke, and it was worse than losing the directory — the ordering went with it:
├── numerical/ 2,563
│ ├── bvp.rs 201
│ ├── integrate.rs 270
│ ├── interpolate.rs 648
│ ├── ode.rs 11 ← ode/mod.rs, rendered as a file
│ ├── adaptive.rs 309 ← hoisted a level, and out of order
│ ├── explicit.rs 63
│ ├── implicit.rs 232
│ ├── symplectic.rs 125
│ └── roots.rs 280
The renderer made one flat pass and printed each module's last path segment, so nothing below the first directory level could survive. It is now recursive over the module hierarchy:
├── numerical/ 2,563
│ ├── bvp.rs 201
│ ├── integrate.rs 270
│ ├── interpolate.rs 648
│ ├── ode/ 740
│ │ ├── adaptive.rs 309
│ │ ├── explicit.rs 63
│ │ ├── implicit.rs 232
│ │ └── symplectic.rs 125
│ └── roots.rs 280
A directory's figure is now its own mod.rs plus everything beneath it, which the map states: ode/ is 740 = its four files at 729 plus its 11-line mod.rs. roots.rs sorts after ode/ again.
numerical/ode is currently the only directory more than one level deep, so this was the only visible instance — but the flat pass would have broken silently on the next one, which is why it was worth fixing rather than special-casing.
Generated by Claude Code
Both found by Copilot's review on #5, both verified against the source before fixing. Free functions were told from methods by whether the `pub fn` sat at column zero. That is wrong for an indented `pub fn` inside an inline `pub mod { ... }`, which is a free function and not a method. There are 175 of them -- 89 in manifold/clifford.rs across its cl3, pga3, cga3 and sta modules, 85 across the four fractals/ preset modules, and one macro template in units/quantity.rs. Classification now follows the enclosing `impl` block, tracked with a stack so a multi-line impl header with a where clause still lands in the right place. Public types were matched against the raw line, so only those at column zero counted. That missed `CgaObject` inside clifford's `pub mod sta` and the k-d tree type inside spatial/kdtree.rs's macro. Matching the stripped line finds both. Totals: 4,124 free functions and 2,241 methods, against 3,949 and 2,416. The sum is unchanged at 6,365 -- both bugs only moved items between the two columns -- and types go from 429 to 431. The README is updated to match. The tree was rendered in one flat pass that printed each module's last path segment, so anything below the first directory level lost its parent: src/numerical/ode/ came out as an `ode.rs` sibling with adaptive.rs, explicit.rs, implicit.rs and symplectic.rs hoisted up beside bvp.rs, and the ordering broke with them. It is now recursive over the module hierarchy, so ode/ renders as a directory with its four files nested under it and roots.rs sorting after. A directory's figure is its own mod.rs plus everything beneath: ode/ is 740, which is its four files at 729 plus its 11-line mod.rs. The generated map now states both counting rules, including the one neither bug caused: the count is syntactic, so a macro-generated item is counted once where the macro defines it rather than once per expansion. That affects units::quantity's unit_ctor! and spatial::kdtree's macro. Both gates re-tested in each direction. 4,193 lib tests, 577 property tests, 2 doc tests, clippy clean, rustdoc clean under -D warnings, nightly-2025-11-21 clean. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VUkMGnfUbaopkUJLWeYCYi
Everything documented so far is reference. The README is a catalogue, MODULE_MAP.md is a table, rustdoc is an index. None of them tells anyone how to actually use this. docs/GUIDE.md is a walk through the library by doing things with it: putting a spacecraft in orbit and transferring it to geostationary, pulling a 440 Hz tone out of noise louder than the signal and filtering away the interference, solving -u'' = f and proving the answer converges at the rate the theory predicts, and the tools for not being wrong. The rule the guide follows is that no code block is written by hand. Each chapter is an example file, and the output quoted is what that file actually prints: examples/guide_02_orbit.rs orbits, elements, Hohmann transfer examples/guide_03_signal.rs FFT, FIR design, Welch PSD examples/guide_04_fem.rs finite elements and convergence rates examples/guide_05_correctness.rs units, formula checking, exact rationals All four assert their own results and are run by CI, so a chapter that describes something that does not work fails the build rather than misleading a reader. The numbers are worth having in the guide precisely because they are real: the orbit chapter prints the ISS's actual 7,673 m/s and 92.4 minutes, the transfer's 3,857 m/s and 5.3 hours; the signal chapter gets 67 dB of rejection; the FEM chapter measures L2 and H1 rates of 2.00 and 1.00 for P1 and 3.00 for P2, against a theory stated before the measurement. The guide also says the things a reference cannot. Why finite elements rather than finite differences, and what the change of question buys. Why an error that merely shrinks is worth nothing while one that shrinks at exactly h-squared settles the matter. Why Buckingham's theorem has to run over exact rationals rather than floats. And a closing section on what will bite you: the LCG's low bits, the conditional stability of explicit stepping, that pcg_jacobi's tolerance is relative to the right-hand side, and that a surprising result may be a documented specification choice rather than a bug. README points at it first in Further reading. 4,193 lib tests, 577 property tests, 2 doc tests, five examples running, clippy clean across all targets, rustdoc clean under -D warnings, both doc gates passing, nightly-2025-11-21 clean. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VUkMGnfUbaopkUJLWeYCYi
Five commits, 96 files. No library behaviour changes — every
src/edit is a doc comment.All six checks green on
9194eeb, and the CI claim in the title is now measured rather than predicted:testjobCoveragetest)testis no longer even on the critical path.CI ran the test suite twice
The
testjob rancargo testand thencargo llvm-covas consecutive steps, so its wall time was their sum.llvm-covis not a reporting step that reads whatcargo testproduced — there is nothing to read. It compiles the crate with-C instrument-coverageinto its own target directory and runs the whole suite again, because running the tests is how it collects coverage. The two do the same work twice whatever we do; the only question is series or parallel. They are now separate jobs.Two other things turned up in that file:
~/.cargo/registryand~/.cargo/git, which are empty for a crate whoseCargo.lockholds exactly one package — itself — and keyed onhashFiles('**/Cargo.lock'), which therefore never changes. After the first save it restored a stale tree and never wrote again; every run loggedCache hit occurred on the primary key, not saving cache. Replaced withSwatinem/rust-cache@v2, whichverify.ymlalready used. The two jobs get separate keys deliberately — instrumented artifacts fingerprint differently, so sharing one cache would thrash it. This is most of whytestmore than halved.cargo buildstep is gone;cargo testbuilds the same artifacts.cargo docemitted 81 warningsRendering bugs rather than style. Rustdoc parses
[k]in a formula as an intra-doc link, soX[k] = Σ x[n]·e^(−j2πkn/N)published with two broken links in it. It parses<counts>and<R>as HTML tags, so those doc comments lost content entirely in the rendered output.Fifty-one doc comments across
transforms,statistics,signal_processing,dsp,linalg,biophysics,chemistry,color_science,manifold,fractals,sim,numericalandcore. 81 → 0, and CI now builds docs withRUSTDOCFLAGS=-D warnings.Three needed more than backticks: the two-line Mur boundary formulas in
wave_sim.rsbecame a```textblock, which is what they always were;MAX_QUBITS,RESTARTSandmc_tableare private so rustdoc cannot link to them; andaudio/effects.rslinked[`read`]from a sibling method without theSelf::prefix.63 modules had no documentation at all
Including
src/lib.rs— the landing page of the entire generated documentation was empty.lib.rsnow carries an orientation page: what the library is for, a table routing all 71 top-level modules by subject, and the three conventions a caller needs (SI units and radians;f64except where exactness is the point; and thatmonte_carlo::Rngis an LCG whose low bits are short-period, soRng::belowis the one to use).The other 62 are written from what they contain, and each says something a reader would otherwise have to derive — that Sabine's reverberation formula never reaches zero however absorptive the room and Eyring's does; that metals yield on deviatoric stress alone, which is why von Mises ignores hydrostatic pressure; that L4 and L5 are stable below a mass ratio of about 1/24.96, which is why Jupiter's Trojans stay put; that the buildup factor matters because ignoring it underestimates dose behind a thick shield.
docs/GUIDE.md— documentation a person can readThe README is a catalogue, MODULE_MAP is a table, rustdoc is an index. None of them teaches anyone to use this.
The guide walks through the library by doing things with it: putting a spacecraft in orbit and transferring it to geostationary, pulling a 440 Hz tone out of noise louder than the signal, solving
−u″ = fand proving the answer converges at the rate the theory predicts, and the tools for not being wrong.No code block in it is written by hand. Each chapter is an example file, and the output quoted is what that file actually prints:
examples/guide_02_orbit.rsexamples/guide_03_signal.rsexamples/guide_04_fem.rsexamples/guide_05_correctness.rsAll four assert their own results and are run by CI, so a chapter describing something that does not work fails the build. The numbers earn their place by being real: the ISS's actual 7,673 m/s and 92.4 minutes, 3,857 m/s and 5.3 hours for the transfer, 67 dB of filter rejection, and L2/H1 rates of 2.00/1.00 for P1 and 3.00 for P2 against theory stated before the measurement.
It also says what a reference cannot — why finite elements rather than finite differences, why an error that merely shrinks proves nothing while one shrinking at exactly h² settles it — and closes with what will bite you: the LCG's low bits, conditional stability of explicit stepping, and that
pcg_jacobi's tolerance is relative to the right-hand side.docs/MODULE_MAP.md— what exists whereA size-annotated tree of all 295 modules, tables by subject area, and a row per module with line count, public item counts and summary. Generated by
tools/gen_module_map.py, because a hand-maintained map of 295 modules is stale the day after.Getting the totals to reconcile took two corrections:
verificationis declaredmod, notpub mod, so counting it gave 72 top-level modules against the README's 71; and excludinglib.rsfrom the line total made the map disagree withwc -loversrc/by exactlylib.rs's length. The map's 266,122 now matcheswc -lexactly.Copilot's review found two real bugs — both fixed in
b90cd00Verified against the source before changing anything:
pub fninside an inlinepub mod { ... }— there are 175 of those (89 inclifford.rsacross itscl3/pga3/cga3/stamodules, 85 in thefractals/presets, one macro template). Now classified by the enclosingimplblock, tracked on a stack so a multi-linewhereclause still opens the body at the right line. Counts move to 4,124 free / 2,241 methods; the sum is unchanged at 6,365, which is the signature of a pure misclassification.CgaObjectand the kdtree macro type. 429 → 431.src/numerical/ode/came out as anode.rssibling with its four files hoisted up besidebvp.rs, ordering broken with them. Now recursive.The map states the one limitation neither bug caused: the count is syntactic, so a macro-generated item is counted once where the macro defines it rather than once per expansion.
README
Claimed 1,659 tests at 99.98% coverage across 67 files, and described none of the Part 3 or Part 4 work. Rewritten against measured numbers, with the governing equations per domain — Galerkin orthogonality and the Pythagoras identity for FEM, the leapfrog energy and Courant condition for FDTD, Buckingham's theorem as a rank computation, LP duality and KKT, Black–Scholes with put–call parity, Hodgkin–Huxley, Marchenko–Pastur.
Two verification passes on the document itself: a script checked all 158 module references in the prose against the source tree (every one resolves, all 71 top-level modules covered), and proofreading the equations caught a mismatched contraction index in the Riemann tensor and an ambiguous Marchenko–Pastur support.
New CI gates
Six, all tested in both directions before committing, all passing on their first real run:
cargo run --example readme_quickstartguide_*examplescargo docunder-D warningsgen_module_map.py --checkcheck_module_docs.py//!summaryThe last matters because nothing else catches it: rustdoc's
missing_docscovers items, not modules, so an undocumented module is completely silent.Verification
cargo doc --no-depsclean under-D warnings(from 81)cargo clippy --all-targets -- -D warningscleancargo +nightly-2025-11-21 check --lib --testsclean (the Kani-pinned toolchain)mergeable_state: cleanOne open question
Coverage still runs on PRs, just in parallel rather than in series. If you would rather it ran only on
mainpushes it disappears from PR latency entirely — one line to change.🤖 Generated with Claude Code
https://claude.ai/code/session_01VUkMGnfUbaopkUJLWeYCYi