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 (branchfeat/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)
- GREEN ⟺ every discovered surface is wired (test-reachable) OR excused by a live
.nornir/autonom-allow.tomlentry, and no excuse is stale. - RED when a surface has no covering row and no excuse → the message names the uncovered surfaces (
autonom completeness gate RED — N uncovered+un-allowlisted surface(s): …). - RED when an allowlist entry is stale → the message names the stale keys.
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:
- Persist a real knowledge scan: a test root reaches
wired, butorphan_fnis unreached →orphan_fnis the surface gap. gate_coverage_for_repo+coverage_gate→ assert RED and that the message namesorphan_fn.- Seed the allowlist with every gap → assert GREEN.
- 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.