Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/dwarves

.nornir/aut5-surface-coverage-gate.md

AUT5 — the surface_coverage release-blocking GATE (design + guide)

The completeness gate, wired into the release pipeline. A release goes RED if any UI/CLI/MCP/function surface has no covering test row — i.e. Surface − Covered ≠ ∅ — or if any allowlist excuse is stale. HARD zero, not a ratchet. Built 2026-06-15 (branch feat/aut5-coverage-gate, folds into nornir 0.4.40). Parent epic: autonom.md; plan: nordisk_plan.md AUT5.

1. The verdict equation

Surface   = every {viz tab × (thin,fat), CLI subcommand, MCP tool, unreached fn}   ← discovered, never listed
Covered   = surfaces with a covering test row (test-reachable handler / fn closure over call_edges)
Allowlist = .nornir/autonom-allow.toml  (live, reasoned excuses — burn down by deletion)
GATE RED  ⟺  (Surface − Covered − Allowlist ≠ ∅)  OR  (any stale allowlist entry)

A stale allowlist entry is an excuse whose surface is now covered, or whose surface no longer exists — the excuse must not outlive its surface, so it re-reds the gate until deleted.

2. What AUT5 added (vs what already existed)

The PURE model (nornir_testmatrix::coverage::{GateReport, CoverageRow, …}), the Iceberg table (src/warehouse/surface_coverage.rs), the feeder (src/autonom.rs::{enumerate_surface, gather, persist, build_surface_and_covered}), the verdict fn (release::gate::coverage_gate), the CLI nornir test coverage, and the MCP tools test_coverage / release_gate_coverage were already shipped (AUT2/0.4.38). What was missing was the release-BLOCKING wiring — coverage_gate was never called from the gate set the release runs. AUT5 closes exactly that gap:

piece file change
gate flag src/config.rs [gates].coverage: bool (LIGHT — no suite run, may default-on per repo)
wiring helper src/autonom.rs gate_coverage_for_repo() — gather → persist → return GateState (one call shared by CLI/server/MCP)
CLI gate-all src/bin/nornir.rs run_gate_all runs coverage inline when [gates].coverage
CLI per-gate src/bin/nornir.rs ReleaseOp::GateCoverage + release gate coverage + the Gate{name} dispatcher ("coverage")
server gate-all src/bin/nornir-server.rs gate_all RPC coverage arm (spawn_blocking; canonical CLI fallback — no live clap tree)

The CLI nornir test coverage, the MCP test_coverage/release_gate_coverage, and the viz Test pane VIEW are pre-existing; the viz coverage VIEW work stays a follow-up (AUT5 avoided src/viz/ entirely to not collide with the in-flight Architecture tab).

3. Red/green conditions (operator's view)

To unblock a release: either wire a real inject-assert test for the surface, or nornir test coverage --seed-allowlist to excuse the current gap with a reason, then burn it down by deleting entries as tests land.

4. CLI + MCP parity

action CLI MCP
report surface vs covered + list gaps nornir test coverage [--json] test_coverage
run the release-blocking verdict nornir release gate coverage / release gate-all release_gate_coverage
re-seed the burn-down allowlist nornir test coverage --seed-allowlist (CLI only — writes a checked-in file)

The remote path runs coverage through release gate-all (the server owns the warehouse), exactly like the heavy tests gate — there is no dedicated per-gate gate_coverage RPC.

5. Tests (inject-assert)

src/autonom.rs::aut5_gate_red_when_surface_uncovered_green_when_allowlisted drives the WIRING end-to-end over a real Iceberg warehouse:

  1. Persist a real knowledge scan: a test root reaches wired, but orphan_fn is unreached → orphan_fn is the surface gap.
  2. gate_coverage_for_repo + coverage_gate → assert RED and that the message names orphan_fn.
  3. Seed the allowlist with every gap → assert GREEN.
  4. Add a stale entry (a ghost surface) → assert RED again, message contains stale.

The pure verdict (coverage_gate_passes_green_fails_on_gap_or_stale) and the table round-trip (append_query_round_trip_exact_verdicts) remain green. The MCP coverage tools stay covered by mcp_every_tool_exercised_and_asserted.

6. Enabling the gate

# workspace_<name>/release/nornir.toml — per repo
[repo.<name>.gates]
coverage = true   # release-blocking: RED if Surface − Covered ≠ ∅ or a stale excuse

It is LIGHT (reads the warehouse surface_coverage map; no cargo build), so unlike the heavy tests gate it can run on the local CLI path and default-on per repo.