Skip to content

docs: ENG-4684 doctests + deny(missing_docs) + clippy::pedantic - #21

Draft
jimbofreedman wants to merge 11 commits into
mainfrom
worktree-ENG-4684
Draft

docs: ENG-4684 doctests + deny(missing_docs) + clippy::pedantic#21
jimbofreedman wants to merge 11 commits into
mainfrom
worktree-ENG-4684

Conversation

@jimbofreedman

Copy link
Copy Markdown
Contributor

Closes ENG-4684 — https://app.clickup.com/t/86c9umm6g

Promotes the crate to library-grade docs and lints: every public item documented, every doc example a live doctest, clippy pedantic enforced across every target.

What changed

Area Change
src/lib.rs The ticket's six-lint #![deny(...)] group + #![warn(clippy::pedantic, clippy::nursery)] + a three-entry allow list, each entry justified inline
src/loader.rs # Examples on all 9 public methods, # Errors on every Result-returning fn, # Panics on archived; use_self ×5, #[must_use] ×5, const fn resolution_km
src/graph.rs, src/data.rs All 9 missing_docs items documented with units, ranges and index semantics
build/*.rs, src/bin/, benches/, 18 × tests/*.rs Pedantic clean — mostly doc backticks, plus justified allow blocks
.github/workflows/ci.yaml One line: -W clippy::pedantic on the existing clippy step
Cargo.toml [lints.clippy] pedantic baseline — see Two decisions for the reviewer

Doctests: 1 ignored / 0 passed15 passed / 0 ignored. Each loads a real 50 km graph and asserts real values (7,390 nodes, 15,498 edges, a 16,354 km Suez route) — no fixture, no network, 0.4 s total. Graph::load, Graph::from_bytes and Graph::route are each covered twice.

Acceptance criteria

AC Command Result
AC1 RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items --all-features clean
AC2 RUSTDOCFLAGS="-D rustdoc::broken_intra_doc_links" cargo doc --no-deps --all-features clean
AC3 cargo clippy --all-targets --all-features -- -D warnings -W clippy::pedantic exit 0
AC4 cargo test --doc --all-features 15 passed, 0 ignored
cargo test --all-features 190 passed, 0 failed (29 targets)
cargo +1.93.0 test --doc --all-features (MSRV) 15 passed
cargo fmt --all --check clean

The new gates were verified to actually bite, not just be declared: an undocumented pub field fails cargo check, and a fresh pedantic violation is a hard error under -D warnings.

Reviewability — ~6 files need close reading, the rest are mechanical

  • Semantic: src/lib.rs, src/graph.rs, src/data.rs, src/loader.rs, tests/lint_state.rs, tests/ci_workflow.rs, Cargo.toml
  • Mechanical: build.rs + build/*.rs, src/bin/rustyroute.rs, benches/route.rs, 18 tests/*.rs. ~110 findings are one-token doc backticks; 72 more are a single crate-root allow in tests/vendored_data.rs (the FIPS 180-4 SHA-256 constant table, which must stay character-for-character comparable to the spec).

Two decisions for the reviewer

1. Cargo.toml [lints.clippy] pedantic is an addition beyond the ticket and can be reverted on its own without unpicking anything else.

The ticket puts the lints in src/lib.rs, but crate-root attributes reach only the librarybuild.rs, tests/*, benches/ and src/bin/ are separate crate roots. Without this table those ~120 pedantic findings are gated solely by one line of CI YAML, invisible to .pre-commit-config.yaml's clippy hook and to every contributor's editor. Proven empirically: with the table, a bare cargo clippy flags a pedantic violation in build.rs; without it, zero diagnostics. priority = -1 keeps per-file allows winning.

2. The missing_errors_doc / missing_panics_doc allows are now dead weight. They're kept because the ticket specifies them, but this PR adds # Errors to every Result-returning public fn and a real # Panics to archived — leaving one missing_panics_doc site and two missing_errors_doc sites, all fixed at source. Dropping both allows would convert two apologetic allows into two live gates. Happy to do it in this PR if you agree.

Things worth knowing

  • The ticket's suggested justification for missing_panics_doc — "no public panics" — is factually wrong. Graph::archived and Graph::route both .expect(...) (src/loader.rs:290, :495). Replaced with an accurate comment.
  • src/graph.rs exposes no public functions (only two already-documented pub consts and struct fields), so the ticket's "# Examples per public function" clause is vacuous there — that file is docs-only, not under-delivered.
  • clippy::suboptimal_flops was deliberately NOT fixed in haversine_km or build/geometry.rs. mul_add's single fused rounding step would shift results in the last bits, rebaking every .rkyv archive and drifting the golden distance table. Allowed with that reasoning inline; tests/golden_routes.rs is the tripwire and stays green.
  • bytes_for was deliberately NOT made const fn. tests/data_module.rs asserts on its exact signature string as an ENG-4688 wasm-gate guard; a nursery cosmetic isn't worth breaking a live guard. Site-allowed instead.
  • tests/lint_state.rs and tests/ci_workflow.rs only ever assert more. lint_state goes from 1 assertion to 5 (keeping the forbid(unsafe_code) rejection); ci_workflow gains a pedantic-flag assertion and a check that the doctest carrier is never narrowed — nothing in CI names cargo test --doc, so the 15 doctests ride on cargo test --all-features.
  • Sequencing from the ticket is satisfied: ENG-4679 is already merged, and the mmap #[allow(unsafe_code)] + SAFETY comment were already in place.

Residual risk: CI runs stable, newer than the local 1.97.1 used here. Pedantic/nursery lint sets shift between releases, so a follow-up lint-name fix after the first CI run is possible.

🤖 Generated with Claude Code

jimbofreedman and others added 10 commits July 27, 2026 12:30
Replace src/lib.rs's lone `#![deny(unsafe_code)]` with the ticket's full
posture: a six-lint deny group (unsafe_code, missing_docs,
missing_debug_implementations, rust_2018_idioms, rust_2024_compatibility,
rustdoc::broken_intra_doc_links), `#![warn(clippy::pedantic,
clippy::nursery)]`, and a three-entry allow list where every entry carries
its justification on the lines directly above it.

The ticket's suggested `missing_panics_doc` comment ("no public panics")
is factually wrong -- `Graph::archived` (src/loader.rs:290) and
`Graph::route` (:495) both `.expect(...)`. Replaced with an accurate
justification; both sites get a real `# Panics` section in a later commit.

Also add a package-wide `[lints.clippy] pedantic = { level = "warn",
priority = -1 }` table to Cargo.toml. This is a deliberate addition
beyond the ticket: `#![...]` in src/lib.rs reaches only the library crate,
so without it the pedantic findings in build.rs, tests/*, benches/ and
src/bin/ are gated solely by one line of CI YAML and stay invisible to
.pre-commit-config.yaml's `cargo clippy --no-deps -- -D warnings` hook.
`priority = -1` keeps per-file allows winning over the group.

tests/lint_state.rs grows from one assertion to five, all additive: the
existing deny/forbid check gains whitespace normalisation so the
multi-line attribute layout still matches, and new tests lock the full
deny group, both clippy groups, the absence of any blanket allow, and the
Cargo.toml table. The `forbid(unsafe_code)` rejection is unchanged.

Refs ENG-4684

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jimbo Freedman <jimbo@spot-ship.com>
`#![deny(missing_docs)]` (previous commit) surfaced nine undocumented
public items. All are now documented to the standard the ticket asks for
-- units, ranges and index semantics, never a restatement of the
identifier:

  * `NodeCoord::lng` / `::lat` -- decimal degrees, WGS84 (EPSG:4326),
    sign convention and valid range. The struct doc now also warns that
    its field order is `(lng, lat)` while the public routing API uses
    `(lat, lng)`.
  * `GroupEntry::name` -- the lowerCamelCase identifier
    `Graph::edges_for_groups` matches on, and therefore part of the
    on-disk contract.
  * `GroupEntry::edge_ids` -- indices into `edge_endpoints` /
    `undirected_weights`, explicitly *not* into `edges`; sorted and
    duplicate-free.
  * `data::BYTES_{5,10,20,50,100}KM` x5 -- documented once, on the
    `define_bytes!` generator via `#[doc = concat!(...)]`, so all five
    rendered consts carry the resolution, the required feature, the
    archive layout, and the alignment caveat. Same tactic as
    `build/registry.rs`'s doc on the generated `EDGE_GROUPS`.

Also splits the over-long first doc paragraphs that
`clippy::too_long_first_doc_paragraph` flags on `src/data.rs`,
`NodeCoord`, `DirectedEdge`, `GroupEntry` and `GraphData`, and backticks
`edge_id` in `GraphData::undirected_weights`.

`src/graph.rs` exposes no public *functions* (only `pub const MAGIC` and
`pub const SCHEMA_VERSION`, both already documented), so the ticket's
"# Examples per public function" clause has no targets in this file --
the nine public methods all live in `src/loader.rs` and are handled in
the next commit.

Verified: `cargo check --all-features` clean; `RUSTDOCFLAGS="-D warnings"
cargo doc --no-deps --document-private-items --all-features` clean (AC1);
`RUSTDOCFLAGS="-D rustdoc::broken_intra_doc_links" cargo doc --no-deps
--all-features` clean (AC2); `cargo test --test lint_state` 5 passed
(AC6); `cargo fmt --all --check` clean.

Refs ENG-4684

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jimbo Freedman <jimbo@spot-ship.com>
The ticket's headline deliverable. `cargo test --doc --all-features` goes
from `1 ignored / 0 passed` to **15 passed / 0 ignored** in 0.25 s, with
no fixture, no network and no `ignore` / `no_run` / `compile_fail` escape
hatch anywhere.

Every one of the nine public methods now carries an `# Examples` section
that asserts real behaviour, plus the crate root and the `Graph` type:

  * `from_bytes` x2 -- loads the bundled 50 km archive; rejects `b"nope"`
    with `BadMagic`.
  * `load` x2 -- resolution is populated (50, vs 0 for `from_bytes`);
    `load(42)` is `UnknownResolution` before any I/O.
  * `resolution_km`, `node_count`, `edge_count`, `archived` -- pinned
    counts (7,390 nodes / 15,498 undirected edges / 13 groups).
  * `directed_edge_count` -- pins 30,976 and demonstrates the documented
    `edge_count..=2*edge_count` range: the 20-half-edge shortfall is 20
    self-loops whose reverse half is suppressed.
  * `route` x2 -- Marseille to Shanghai is 16,354 km via Suez and >8,000
    km longer with `suezCanal` blocked; a self-route is a
    single-coordinate zero-distance path; `(91.0, 0.0)` is
    `BadFromCoord`.
  * `edges_for_groups` -- two-group union is a superset of one, and
    `"Suez Canal"` is `UnknownGroup` (matching is byte-exact).
  * The `Graph` type's long-lived-handle example, previously fenced
    ```ignore, now runs -- it compiles and passes as written. The doc now
    states that it deliberately leaks the archive handle for the doctest
    process lifetime, so a reviewer does not have to discover that.

Conventions: setup `use` lines and the trailing `Ok::<(), Box<dyn
Error>>(())` are hidden behind `#`; `?` throughout, never `.unwrap()`;
intra-doc links rather than plain backticks. Examples prefer
`Graph::from_bytes(data::BYTES_50KM)` over `Graph::load(50)` because
`load`'s step 1 makes it sensitive to `$RUSTYROUTE_DATA_DIR` -- `load` is
used only where the example is specifically about `load`, and both such
examples say the variable must be unset and why.

Also adds the `# Errors` sections the ticket asks for on `from_bytes` and
`load` (enumerating every `LoadError` variant each can produce; `route`
and `edges_for_groups` already had theirs), a real `# Panics` section on
`archived` explaining that its `.expect` is unreachable via the public
API, splits the over-long first doc paragraphs on `Graph`, `load`,
`resolution_km`, `archived` and `directed_edge_count`, and backticks
`OUT_DIR` in `LoadError::DataNotAvailable`.

Verified: `cargo test --doc --all-features` 15 passed / 0 ignored (AC4);
`RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items
--all-features` clean (AC1); `RUSTDOCFLAGS="-D
rustdoc::broken_intra_doc_links" cargo doc --no-deps --all-features`
clean (AC2); `cargo fmt --all --check` clean (AC10).

Refs ENG-4684

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jimbo Freedman <jimbo@spot-ship.com>
The library target now reports **zero** clippy findings under pedantic +
nursery. Fixed where the fix is a strict improvement, allowed with a
stated reason where the current form is deliberate.

Fixed:
  * `use_self` x5 -- `Self` in `from_bytes`/`load`/`load_file` return
    types and the two struct literals.
  * `must_use_candidate` x5 -- `#[must_use]` on the getters and on
    `route`, whose message says why (computing a Route and dropping it
    does no work).
  * `missing_const_for_fn` -- `resolution_km` is now `const fn`
    (verified on MSRV 1.93.0).
  * `redundant_closure_for_method_calls` x3 --
    `std::sync::PoisonError::into_inner` in the unit-test env lock.
  * `doc_markdown` -- `GeoPackage` in `NodeCoord`, `OUT_DIR` in the unit
    tests, and `DataFileMissing` upgraded to an intra-doc link.

Allowed, each with the reason immediately above it:
  * `suboptimal_flops` on `haversine_km` -- MUST NOT be "fixed".
    `f64::mul_add` is a single fused rounding step and returns
    bit-different results, which would shift nearest-node snapping and
    drift the golden distance table in tests/fixtures/routes.json.
    tests/golden_routes.rs is the tripwire and stays green (8 passed).
  * `needless_pass_by_value` on `load_file` -- taking `File` by value is
    deliberate ownership transfer: the mapping must outlive the handle,
    and `&File` would let a caller mutate the file under a mapping the
    SAFETY note assumes immutable.
  * `cast_possible_truncation` x3 in the count getters -- node indices and
    `EdgeId` are `u32` by the on-disk schema, so neither table can exceed
    `u32::MAX`.
  * `missing_const_for_fn` on `data::bytes_for` -- deliberately NOT made
    `const fn`. tests/data_module.rs:31-33 asserts on the literal source
    text `"pub(crate) fn bytes_for"` as an ENG-4688 wasm-gate guard;
    adding `const` renames the signature out from under it, trading a
    live regression test for a nursery cosmetic. tests/data_module.rs is
    therefore NOT modified by this ticket and passes unchanged.

Also fixes the `$OUT_DIR/data_lens.rs` generator (build/mod.rs) to emit
`#[allow(dead_code, clippy::unreadable_literal)]`. The five raw archive
byte counts are `include!`d into src/data.rs, so the warnings land on the
*library* with spans in a generated file nobody can edit -- which is why
this one line of the build-script story has to ride with the library fix
that its absence would block.

Verified: library target has 0 clippy findings under `-W clippy::pedantic
-W clippy::nursery` (all remaining diagnostics are `custom-build`, next
commit); `cargo test --test data_module --test golden_routes --test
route_smoke --all-features` 15 passed; `cargo test --doc --all-features`
still 15 passed / 0 ignored; `cargo fmt --all --check` clean.

Refs ENG-4684

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jimbo Freedman <jimbo@spot-ship.com>
This is where the ticket's acceptance command actually dies: `cargo
clippy --all-targets --all-features -- -D warnings -W clippy::pedantic`
exited 101 on 28 build-script errors and never reached the library, which
is why the build crate could not be deferred to a follow-up.

Fixed (strict improvements):
  * `doc_markdown` x14 -- backticks on `GeoPackage(s)`, `SQLite`,
    `LineString`, `RawEdge`, `SCHEMA_VERSION`, `ArchivedGraphData` across
    build.rs and six build/ modules.
  * `uninlined_format_args` x4 -- build/mod.rs x3, build/groups.rs x1.

Allowed as **module-level inner attributes** in each build/*.rs, each
preceded by its reason. Placement is the point: build/csr.rs,
build/geometry.rs, build/groups.rs and build/gpkg_io.rs are compiled into
the build script *and* into four test crates that re-include them via
`#[path]`, and an inner attribute on a module file is scoped to the
module, so one edit covers every including crate. The alternative --
repeating each allow at five crate roots -- drifts on the first edit.

  * `cast_possible_truncation` x9 (csr.rs, groups.rs) -- every `usize as
    u32` narrows a node id, edge id or CSR row pointer, all `u32` in the
    on-disk schema; every `f64 as f32` narrows a coordinate or haversine
    weight, and `f32` is the schema's deliberate precision choice.
  * `must_use_candidate` / `missing_panics_doc` / `missing_errors_doc` --
    these fire only in the test-crate inclusion context, where a `pub fn`
    of the module becomes public API of a crate rooted at a test file.
    They are build-time internals with one production caller each.
  * `match_same_arms` at build/geometry.rs (site allow) -- `2 => 6, 3 =>
    6` transcribes the GeoPackage envelope-indicator table row for row
    (2 = XYZ, 3 = XYM). Merging to `2 | 3` would hide that
    correspondence.

`suboptimal_flops` at build/geometry.rs:79 is nursery, outside the AC's
command, and deliberately left alone: `mul_add` would change the
haversine edge weights baked into every .rkyv archive.

Verified: `cargo clippy --all-targets --all-features -- -D warnings -W
clippy::pedantic` reports nothing under build.rs or build/; `cargo test
--test build_artifacts --test graph_types --test golden_routes --test
group_assignment --all-features` 23 passed -- the archives are rebaked
byte-identically and the golden distance table is unchanged; `cargo fmt
--all --check` clean.

Refs ENG-4684

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jimbo Freedman <jimbo@spot-ship.com>
`doc_markdown` only -- five backticks in the `cli`-gated binary
(`GeoJSON` x3, `FeatureCollection`, `LineString`) and two in the bench
(`html_reports`, `CodSpeed`). No behavioural change, and the binary keeps
its own crate-level `#![deny(unsafe_code)]`.

`missing_const_for_fn` (src/bin/rustyroute.rs) and
`significant_drop_tightening` (benches/route.rs) are nursery. Nursery is
deliberately library-scoped -- the AC's clippy command carries only
`-W clippy::pedantic` -- so both are left alone.

Verified: `cargo clippy --all-targets --all-features -- -D warnings -W
clippy::pedantic` reports nothing under src/bin/ or benches/; `cargo test
--test cli_smoke --all-features` passes; `cargo fmt --all --check` clean.

Refs ENG-4684

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jimbo Freedman <jimbo@spot-ship.com>
Completes AC3: `cargo clippy --all-targets --all-features -- -D warnings
-W clippy::pedantic` now exits 0 across every target in the package.

Fixed (strict improvements, no behavioural change):
  * `doc_markdown` x28 across 11 files -- backticks on identifiers and
    file paths in module docs.
  * `map_unwrap_or` x5 -- `map_or_else` in downstream_consumer_smoke.rs
    and feature_matrix.rs, `map_or` in pre_commit_config.rs, and
    `Result::is_ok_and` for the two `.output().map(...).unwrap_or(false)`
    probes in pre_commit_e2e.rs.
  * `redundant_closure_for_method_calls` x4 --
    `std::sync::PoisonError::into_inner` in env_data_dir.rs x2,
    graph_load.rs, feature_matrix.rs.

Justified allows. Crate-root blocks, one prose justification per lint:
  * tests/vendored_data.rs -- `unreadable_literal` x72,
    `many_single_char_names`, `items_after_statements` x2. The file
    transcribes FIPS 180-4 so the vendored-data integrity check needs no
    third-party hash crate. `K`/`H0` are the round-constant and
    initial-hash tables from §4.2.2 / §5.3.3 and `a`..`h` are the §6.2.2
    working-variable names; separators and renames would destroy the
    character-for-character comparability the implementation is reviewed
    against.
  * tests/build_helpers.rs -- `unreadable_literal` x4: Menai Strait bbox
    corner coordinates at grid-snap precision, which must stay
    byte-comparable against build/groups.rs.
  * tests/golden_routes.rs -- `float_cmp` x4: exactness is the point. A
    fixture pinned at `expected_km == 0` must be exactly zero, and the
    `from`/`to` comparisons check two rows describe the same voyage. An
    epsilon anywhere here would let real drift through.
  * tests/route_smoke.rs -- `float_cmp` x1: `Graph::route` returns a
    literal `0.0` on the `start == goal` short circuit, so there is no
    accumulated error for a tolerance to absorb.
  * tests/feature_matrix.rs -- `manual_assert` x3: each panic body
    interpolates the full multi-line stdout AND stderr of a `cargo check`
    subprocess; `assert!` reads far worse across twenty lines of captured
    compiler output.
  * tests/build_artifacts.rs -- site allow for `cast_possible_truncation`:
    node indices are `u32` by the on-disk schema.

tests/downstream_consumer/ is a separate `[package]`, not covered by the
root lint config or `cargo fmt --all`, and needs no change.

NOTE on tests/data_module.rs: the plan says not to modify it. The single
change here is backticking `BYTES_50KM` in that file's own module doc
comment, required because AC3 is all-or-nothing. The instruction's purpose
-- protecting the ENG-4688 wasm-gate guard, which asserts on
`src/data.rs`'s `"pub(crate) fn bytes_for"` source text -- is fully
honoured: the guard and that signature are both untouched, and `cargo test
--test data_module` passes. See concerns.md C5.

Verified: AC3 exits 0; `cargo fmt --all --check` clean.

Refs ENG-4684

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jimbo Freedman <jimbo@spot-ship.com>
Exactly one line of ci.yaml changes -- the clippy step at :47 gains
`-W clippy::pedantic`. It has to be the same line: `tests/ci_workflow.rs`
asserts there is exactly ONE `cargo clippy` line in the file, so a second
step would break the suite.

tests/ci_workflow.rs gains two assertions:

  * `clippy_job_uses_deny_warnings` now also requires
    `-W clippy::pedantic` on that line. `#![warn(clippy::pedantic)]` in
    src/lib.rs reaches only the library crate, so this flag is what keeps
    the ~120 findings resolved across build.rs, tests/, benches/ and
    src/bin/ from going latent again.

  * `test_job_does_not_narrow_away_doctests` (new). Nothing in the
    workflow names `cargo test --doc`: the fifteen library doctests ride
    entirely on the test-matrix's `cargo test --all-features`, and
    `cargo llvm-cov` in the coverage job does not run doctests without
    `--doctests`, which it is not given. Narrowing that line to `--lib` or
    `--tests` would silently stop executing this ticket's headline
    deliverable with nothing going red. The test locates the single
    un-narrowed `- run: cargo test` line and rejects `--lib`, `--tests`,
    `--bins`, `--benches` and `--examples` on it.

Two edits from an earlier draft are deliberately CUT as overreach:
  * `RUSTDOCFLAGS` (:160) does NOT gain
    `-D rustdoc::broken_intra_doc_links`. Triply redundant: the lint is
    warn-by-default so the existing `-D warnings` already denies it,
    src/lib.rs now carries `#![deny(rustdoc::broken_intra_doc_links)]`,
    and it would burn the single-RUSTDOCFLAGS-line budget that
    `docs_job_denies_rustdoc_warnings` enforces.
  * `cargo doc` (:167) does NOT gain `--document-private-items`. The
    ticket runs that as a local acceptance command; adding it would
    permanently widen a CI gate to private-item rustdoc lints.

Verified: `cargo test --test ci_workflow --all-features` 15 passed;
`cargo fmt --all --check` clean.

Refs ENG-4684

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jimbo Freedman <jimbo@spot-ship.com>
Review found six defects, all inaccurate justification/doc prose rather
than behavioural bugs -- the conclusions were right but the citations
pointed at the wrong field, file, or literals. On a ticket whose
deliverable is the prose, a confidently-wrong comment is worse than none.

P2 src/loader.rs -- load_file's needless_pass_by_value reason claimed
`&File` would let a caller mutate the file under the mapping. Unsound:
both call sites pass a read-only `File::open` handle, an mmap outlives
the descriptor regardless, and by-value stops nothing anyway
(try_clone, a second open, another process). Restated as the tidiness
argument it actually is, and points at the SAFETY note for the real
immutability contract.

P2 tests/build_helpers.rs -- unreadable_literal reason named "Menai
Strait bbox corner coordinates ... at 5 km grid precision" and claimed
byte-coupling to build/groups.rs. The four flagged literals are the
100 km Menai edge's segment endpoints at full f64 precision; the real
bbox constants are the last four args and never trip the lint.

P3 tests/golden_routes.rs -- float_cmp reason described a comparison
between two fixture rows' endpoints. No such comparison exists; the
only float-tuple compare is a single row's own `from == to`, which is
what licenses the exact zero-km assertion.

P3 src/loader.rs -- node_count's cast cited node_offsets: Vec<u32>,
a CSR row pointer that bounds edges.len(), not nodes.len(). Now cites
NodeId / DirectedEdge::source,target.

P3 src/lib.rs -- the crate-root Cape-route doctest pinned
`> 25_000.0` against a real 25,047 km, a 0.19% margin that any archive
rebake could redden. Switched to the relative form the equivalent
assertion on Graph::route already uses (8.7% margin).

P3 build/csr.rs, build/gpkg_io.rs -- the #[path] inclusion lists that
tell a maintainer how far each module-level allow reaches were wrong in
both directions: csr.rs named build_helpers.rs (which includes only
geometry.rs) and said five crate roots for four; gpkg_io.rs omitted
tests/graph_load.rs.

Gates re-run: fmt clean, clippy --all-targets --all-features
-D warnings -W clippy::pedantic exit 0, 15 doctests 0 ignored,
rustdoc -D warnings clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jimbo Freedman <jimbo@spot-ship.com>
Round-2 re-review found three P3s, including one I introduced in
f5ca648 by transcribing round 1's suggested citation instead of
grepping it. Applying the review's own prescription to the review.

src/loader.rs -- node_count's cast justification named
`DirectedEdge::source`, which does not exist: that struct has only
`target`, `weight_km` and `edge_id`, because in CSR the source node is
implicit in the `node_offsets` row index. It also claimed the bound is
"enforced at build time in build/csr.rs", but csr.rs:70 is
`nodes.len() as u32` -- a truncating cast that mints ids, not a check,
and the step-6 assertions all still pass under a wrapped table. Now
cites NodeId / DirectedEdge::target / GraphData::edge_endpoints and
states plainly that the bound is structural rather than asserted.
`edge_count` and `directed_edge_count` were already correct and are
untouched.

build/gpkg_io.rs -- the module doc named one `#[path]` re-includer while
the lint-posture comment three lines below named two. Added
tests/graph_load.rs, which also compiles `iter_edges` and so is part of
why `rusqlite` is a dev-dependency.

build/gpkg.rs -- same omission in RawEdge's re-includer list.

src/graph.rs -- resolves the open question both review rounds raised.
`GroupEntry::name` said changing a value "requires a SCHEMA_VERSION
bump", stricter than SCHEMA_VERSION's own contract ("incompatible layout
changes", and a field-level MUST in the module doc). A value rename
changes no layout, so the two docs disagreed. Widened SCHEMA_VERSION
rather than softening the claim: a bump makes a stale archive fail fast
in the header check instead of surfacing later as a confusing
UnknownGroup from edges_for_groups. First paragraph split to satisfy
too_long_first_doc_paragraph -- the nursery lint this ticket enables,
which caught the edit.

Verified every identifier the new comments name actually exists.
Gates: fmt clean, clippy -D warnings (with and without
-W clippy::pedantic) exit 0, 15 doctests 0 ignored, rustdoc -D warnings
and broken_intra_doc_links clean, full suite 190 passed 0 failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jimbo Freedman <jimbo@spot-ship.com>
Copilot AI review requested due to automatic review settings July 27, 2026 13:35
@codspeed-hq

codspeed-hq Bot commented Jul 27, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 6 untouched benchmarks


Comparing worktree-ENG-4684 (635155f) with main (c248547)

Open in CodSpeed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Raises documentation and lint strictness across the crate to “library-grade” standards by enforcing missing_docs, enabling clippy pedantic/nursery, and converting doc examples into runnable doctests across library + supporting targets (tests/build/bin/benches).

Changes:

  • Added crate-level lint posture (deny group + clippy warn groups + narrowly-justified allows) and package-wide clippy pedantic baseline via Cargo.toml.
  • Expanded public API docs across src/loader.rs, src/graph.rs, src/data.rs (examples/errors/panics, doctests, #[must_use], and some signature/formatting cleanups).
  • Updated CI to gate pedantic via a clippy flag, and performed mechanical doc/lint cleanups across build code, tests, benches, and bin.

Reviewed changes

Copilot reviewed 36 out of 36 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/vendored_data.rs Adds crate-root clippy allow block with rationale for FIPS-transcribed SHA-256 constants.
tests/tampered_gpkg_panic.rs Mechanical doc backticks/wording updates in test docs.
tests/route_smoke.rs Adds justified crate-root clippy::float_cmp allow for exact-zero assertions.
tests/release_plz_config.rs Doc backticks + minor AC mapping text tweaks.
tests/release_dist_workflow.rs Doc backticks + minor AC mapping text tweaks.
tests/pre_commit_e2e.rs Refactors Result handling with is_ok_and for pedantic cleanliness.
tests/pre_commit_config.rs Refactors Option handling with map_or for pedantic cleanliness.
tests/lint_state.rs Expands lint-posture “contract tests” to assert deny/warn/allow state and Cargo.toml clippy lints.
tests/graph_load.rs Doc wording/backticks + poison-lock handling refactor (PoisonError::into_inner).
tests/golden_routes.rs Adds justified crate-root clippy::float_cmp allow for exactness checks.
tests/feature_matrix.rs Adds justified allow for manual_assert + minor refactors for pedantic.
tests/env_data_dir.rs Refactors poison-lock handling (PoisonError::into_inner).
tests/downstream_consumer_smoke.rs Refactors env var handling with map_or_else for pedantic.
tests/data_module.rs Mechanical doc backticks for exported const name.
tests/codspeed_workflow.rs Mechanical doc backticks/wording consistency.
tests/cli_smoke.rs Mechanical doc backticks/wording consistency.
tests/ci_workflow.rs Adds assertions that CI clippy includes pedantic flag and that doctests aren’t narrowed away.
tests/build_helpers.rs Adds justified crate-root clippy::unreadable_literal allow for transcribed floats.
tests/build_artifacts.rs Doc backticks + targeted cast_possible_truncation allow with rationale.
tests/audit_workflow.rs Mechanical doc backticks.
src/loader.rs Major public API doc expansion (Errors/Panics/Examples), doctests, #[must_use], and minor signature/formatting cleanups.
src/lib.rs Adds crate-level Examples section + consolidated lint posture (deny group, clippy warn groups, justified allows).
src/graph.rs Documents schema items (units/ranges/index semantics) to satisfy missing_docs.
src/data.rs Documents feature-gated byte slices via macro-generated docstrings; adds justification for a lint allow.
src/bin/rustyroute.rs Mechanical doc backticks/wording consistency.
Cargo.toml Adds [lints.clippy] pedantic baseline with low priority and rationale.
build/mod.rs Minor formatting refactors + generated-code lint allow to prevent unfixable spans in include! output.
build/groups.rs Mechanical doc backticks + module-level lint allows with rationale.
build/gpkg.rs Mechanical doc backticks/wording updates.
build/gpkg_io.rs Adds module-level missing_errors_doc allow with rationale for test inclusion context.
build/geometry.rs Mechanical doc backticks + module-level lint allows + a justified match_same_arms allow.
build/csr.rs Mechanical doc backticks + module-level lint posture allows with rationale.
build/archive.rs Mechanical doc backticks/wording consistency.
build.rs Mechanical doc backticks/wording consistency.
benches/route.rs Mechanical doc backticks/wording consistency.
.github/workflows/ci.yaml Adds -W clippy::pedantic to the clippy step.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/loader.rs
Comment thread tests/lint_state.rs Outdated
Addresses both Copilot review comments on PR #21.

tests/lint_state.rs -- cargo_toml_warns_pedantic_package_wide had two
scoping holes, not just the one Copilot named. The `table` slice ran from
`[lints.clippy]` to end-of-file rather than stopping at the next header,
and the lint-level check scanned `toml.lines()` across the whole file. So
a `pedantic = ...` key in any later table could satisfy the test while
the real package-wide gate had been removed or downgraded.

Now walks lines tracking the active table header and collects only those
inside `[lints.clippy]`, asserting presence and level against that slice
alone. Verified against the exact decoy Copilot described -- a
`[package.metadata.decoy] pedantic = "warn"` entry with the real table
downgraded to `nursery = "allow"`: the old form passed, the new form
fails with "must set `pedantic` ... Table as read: [nursery = allow]".

src/loader.rs -- documented why Graph::load's example is not made
hermetic. Clearing $RUSTYROUTE_DATA_DIR inside the example would need
`std::env::remove_var`, which is `unsafe` in edition 2024, and this
ticket requires doctests to stay free of unsafe blocks. The caveat was
already stated; now the reason it is a caveat rather than a fix is too,
with a pointer to Graph::from_bytes for callers who need a loader no
environment variable can redirect.

Gates: fmt clean, clippy --all-targets --all-features -D warnings
-W clippy::pedantic exit 0, 15 doctests 0 ignored, rustdoc -D warnings
clean, lint_state 5 passed, ci_workflow 15 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Jimbo Freedman <jimbo@spot-ship.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 36 out of 36 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (2)

src/loader.rs:145

  • This doctest is now runnable and asserts on the loaded graph, but it calls Graph::load(50), which can fail on developer machines when $RUSTYROUTE_DATA_DIR is set (even if CI passes). Since the example’s goal is demonstrating the OnceLock + Box::leak pattern, using Graph::from_bytes(data::BYTES_50KM) keeps it hermetic and still runnable.
/// assert_eq!(graph().resolution_km(), 50);
/// assert!(std::ptr::eq(graph(), graph()));

src/loader.rs:398

  • This example runs Graph::load(50)?, so it can fail in environments where $RUSTYROUTE_DATA_DIR is set (even though CI is clean). Making the snippet no_run keeps it as a compile-checked doctest without depending on the caller’s runtime environment.
    /// ```
    /// # use rustyroute::{Graph, data};
    /// assert_eq!(Graph::load(50)?.resolution_km(), 50);
    /// assert_eq!(Graph::from_bytes(data::BYTES_50KM)?.resolution_km(), 0);

Comment thread tests/feature_matrix.rs
Comment on lines 9 to +10
//! — exercises AC4's "load(100) succeeds, load(50) is
//! DataNotAvailable" matrix.
//! `DataNotAvailable`" matrix.
Comment on lines 29 to +31
//! AC mapping (spec at .ship/tasks/eng-4692-.../plan/spec.md):
//! AC1 -> release_plz_toml_* tests
//! AC2 -> release_plz_workflow_* tests
//! AC1 -> `release_plz_toml`_* tests
//! AC2 -> `release_plz_workflow`_* tests
Comment on lines 15 to +17
//! AC mapping (spec at .ship/tasks/eng-4692-.../plan/spec.md):
//! AC3 -> release_workflow_* tests
//! AC4 -> dist_workspace_toml_* tests
//! AC3 -> `release_workflow`_* tests
//! AC4 -> `dist_workspace_toml`_* tests
Comment thread src/lib.rs
Comment on lines +48 to +50
//! ```
//! # use rustyroute::Graph;
//! let graph = Graph::load(50)?;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants