Feature N — source coverage, maven-style (design + guide)
LLVM source-based line/region coverage (via
cargo-llvm-cov) → the warehouse → the docs/PDF
- the viz 🧪 Test pane. The maven/JaCoCo-report twin of AUT5: where aut5-surface-coverage-gate.md answers "is every testable surface reached by a test?", THIS answers "what fraction of the source lines/regions did the test run actually execute?" — per crate, per file, per function, with a dedicated ui/gRPC/emitter boundary view. Built 2026-06-18. Plan: nordisk_plan.md (the AUT5 follow-up "viz Test-pane coverage VIEW").
1. The pipeline
cargo llvm-cov --json → parse + demangle → CoverageReport → warehouse rows → docs / viz
(src/coverage/runner.rs) (src/coverage/mod.rs) (overall+crate+file+fn) (coverage, coverage_fn)
│ │
name/path boundary tag nornir:gen:coverage + 📐 Test-pane panel
(ui · grpc · emitter · core) (book/PDF) (+ boundary view)
-
Measure —
nornir coverage <repo>shells out tocargo llvm-cov --jsonin the repo dir (honoursCARGO_TARGET_DIR), then the pure parser ([nornir::coverage::parse_llvm_cov_json]) reads the LLVM export: per-filesummary.{lines,regions}for the authoritative totals, and the per-functionregions/countfor the boundary rows. llvm-cov emits mangled symbols, so the parser demangles (v0_R…/ legacy_ZN…) viarustc-demanglebefore classifying. Files under/.cargo/,/registry/,/rustc/,/target/, or outside the repo root are dropped (first-party only). -
Persist — historized like
bench_telemetry: one Iceberg snapshot per run, all rows sharing(run_id, ts_micros), partitioned byrepo— so coverage is time-travellable and feeds docs- viz. Two tables (see §3).
-
Surface — the docs
nornir:gen:coveragemarker (this file's §6) renders a maven-style table into the book/PDF; the viz 🧪 Test pane's 📐 panel reads the same rows live.
2. The CLI verb (parity LAW)
nornir coverage [REPO] [--show] [--boundary] [--json] [-- <extra cargo-llvm-cov args>]
nornir coverage nornir— measure + persist + print the maven table (overall %, per-crate, worst files).--boundary— also print the ui / gRPC / emitter boundary view (task #4): a per-boundary green/red tally + every boundary function with a✓/✗exercised mark.--show— skip the run; READ the latest persisted run from the warehouse (the viz/docs source of truth).--json— emit the report as JSON.-- --all-features— anything after--is passed verbatim tocargo llvm-cov.
If cargo-llvm-cov / llvm-tools-preview is missing, the verb prints the exact install hint (rustup component add llvm-tools-preview + cargo install cargo-llvm-cov).
3. The warehouse schema
coverage — one row per (run_id, repo, scope), scope ∈ {overall, crate:<name>, file:<path>}:
| col | type | meaning |
| run_id, ts_micros, repo | str/ts/str | run id + time + repo (partition key) |
| scope | str | overall | crate:<name> | file:<path> |
| krate, file | str | crate name / file path ("" where N/A) |
| lines, lines_covered, regions, regions_covered | long | the counts → line_pct / region_pct |
coverage_fn — one row per function, carrying its layer boundary:
| col | type | meaning |
| run_id, ts_micros, repo | … | as above |
| name, file | str | demangled fn name + source file |
| boundary | str | ui | grpc | emitter | core |
| lines, lines_covered, regions, regions_covered | long | per-fn coverage; regions_covered>0 ⇒ exercised |
Both schema-evolve additively (ensure_table_schema on append); old binaries keep reading.
4. Boundary classification — the ui/grpc/emitter view (task #4)
Per the layer-boundary-discoverability LAW, a function's boundary is classified by name + file path ([nornir::coverage::classify]), so the hard-to-cover seams are discoverable and the green panel proves they're tested:
- UI —
ui/draw/draw_*/showundersrc/viz/(theimpl Facetrender fns). - gRPC — the proto server's named handlers (
test_results,bench_telemetry,architecture,run_test_matrix, …) insrc/bin/nornir-server.rs— a tonic handler verb IS the mark. - Emitter —
state_json(the readable-data emitter),emit/emit_in|out|end|event, and the$NORNIR_VIZ_TRACEtrace points (viz/trace.rs,selftest.rs).
The 📐 panel + --boundary then show, e.g., ui 2/2 · grpc 2/2 · emitter 1/2 and list each function with ✓/✗ — so an un-exercised state_json emitter reds the boundary view by name.
5. The viz 📐 panel + emitted data (LAW #6)
The Test pane embeds CoverageLive (mirrors bench_live.rs): a lazy + request_repaint_after warehouse read showing the overall badge, per-crate bars, worst files, a history sparkline, and the boundary view. Everything it paints is exposed as DATA under state_json["test"]["src_coverage"] (line_pct, region_pct, crates, worst_files, history, and boundary.{total,exercised,green,tally,fns}) + the test.coverage.{load,build,…} trace spans, so a robot test asserts the picture without pixels. Remote (thin) mode shows the same "no Viz.Coverage RPC yet" split as the Bench-LIVE / Test / Release panes.
6. Coverage report (generated)
(no coverage recorded — run nornir coverage <repo>)
7. Tests (inject-real / assert-real)
src/coverage/mod.rs—parse_real_llvm_cov_export_shape(a known JSON blob → asserted %, crate rollup, worst files, boundary fns + tally),classify_finds_ui_grpc_emitter_boundaries,demangle_unwraps_v0_and_passes_plain_through.src/warehouse/coverage.rs—append_query_round_trip_rollup_and_boundary(report → rows → warehouse → rows back; overall/crate/file + the ui/emitter/grpc fn rows),latest_picks_newest_run.src/viz/coverage_live.rs—inject_renders_overall_crates_and_boundary_into_state_json,remote_has_no_rpc_split.src/docs/sections.rs—coverage_marker_fills_overall_and_per_crate,coverage_marker_empty_is_graceful.tests/viz_coverage_pane.rs— app-level inject +state_jsonassertions + a wgpu golden PNG (tests/snapshots/viz_coverage_pane.png) of the populated panel incl. the boundary view.
Validated end-to-end against a real cargo llvm-cov --json run of nornir-testmatrix (78.2% overall lines, per-crate rollup, demangled fn names).