Gunnar

nordisk/dwarves

.nornir/completeness-gate.md

<!-- nornir:class: history -->
# autonom completeness gate (n-005) — design + guide

> The CORE that makes **green ⟺ every surface is wired** true. Builds on the
> pure enumerators in [`autonom.md`](../../nornir/.nornir/autonom.md) (§2 the completeness equation,
> §3 discovery). This doc is the n-005 slice: the FEEDERS, the persisted
> verdict, the allowlist, and the CLI / MCP / viz / release-gate surfaces.
>
> **Closing a gap = covering a surface with an inject-assert test.** *How* an
> agent does that — drives the surface headless, reads the emitted DATA, bisects
> to the bug, and writes the fail-on-bug/pass-on-fix test — is the LAW in
> [`agent-ui-test-fixing.md`](../../nornir/.nornir/agent-ui-test-fixing.md) (the canonical way to fix
> any UI/gRPC/render test; see [`test-matrix.md`](../../nornir/.nornir/test-matrix.md) §0).

## 1. The equation, made enforceable

```
Surface  = discover::{viz_tabs×{fat,thin}, cli_commands, mcp_tools, facett, unreached_functions}
Covered  = a surface node reached by an inject-assert test (call_edges closure / handler match)
Allowed  = a checked-in .nornir/autonom-allow.toml entry (excused, WITH a reason)
Gap      = Surface − Covered − Allowed
GATE: Gap == ∅  AND  no STALE allowlist entry      ← HARD zero, not a ratchet
```

## 2. Feeders (nornir, iceberg-backed) — `src/autonom.rs`

The pure enumerators live in `nornir-testmatrix` (`discover` + `coverage`,
std+serde, no warehouse). nornir's feeder layer gathers the REAL inputs:

| surface | feeder |
|---|---|
| viz tabs × {fat,thin} | `autonom::VIZ_TABS` (asserted == `viz::app::Tab::ALL` by `viz_tabs_const_matches_tab_enum`) |
| CLI subcommands | live `Cli::command().get_subcommands()` (clap introspection) |
| MCP tools | `autonom::MCP_TOOLS` (kept in step with the `mcp_matrix` tools/list gate) |
| functions | `symbol_facts − test-reachable(call_edges)` from the warehouse knowledge map |

`build_surface_and_covered` differences the surface against the **test-reachable
closure** over `call_edges` (BFS from test-root fns, at identifier granularity —
the persisted syn facts record callees as last-segments). A function node only
exists when **unreached**; a discrete surface (tab/cli/mcp) is covered iff a
same-named test-reachable handler exists, else it falls to the allowlist.

## 3. Persisted verdict — `surface_coverage` (skade schema-evolution)

`src/warehouse/surface_coverage.rs` writes/reads one row per
`surface_key × mode × workspace × verdict` (mirrors `tests/mcp_tool_coverage.json`
generalized to the whole surface). Additive schema (`iceberg_schema::surface_coverage`):
old binaries keep reading (optional `reason`). Writer/reader mirror
`test_results.rs`: `append_surface_coverage` / `query_surface_coverage` /
`latest_surface_coverage`.

## 4. The allowlist — `.nornir/autonom-allow.toml` (SEED → burn down)

A checked-in TOML of `[[allow]]` entries (`key = "kind:id@mode"`, `reason = "TODO…"`).
`nornir test coverage --seed-allowlist` rewrites it with **every currently-
uncovered surface node** so the gate is GREEN now. Burn it down by **deleting**
an entry once a real inject-assert test covers that surface. A **STALE** entry
(now-covered, or its surface no longer exists) **FAILS** the gate — the excuse
must not outlive its surface.

## 5. Surfaces (CLI / MCP parity + viz + release gate)

- **CLI**: `nornir test coverage [--repo R] [--seed-allowlist] [--json]` —
  discovers, differences, persists, and exits red on any gap or stale entry.
- **MCP** (parity): `test_coverage` returns `{total,covered,allowlisted,gap,green,missing[]}`;
  `release_gate_coverage` errors on a red gate. Both embedded/local (they read
  the warehouse directly).
- **viz** (the visible half): the 🧪 Test pane shows the verdict under
  `state_json["test"]["coverage"]` — `{total,covered,allowlisted,gap,green,missing[]}`
  from the latest persisted `surface_coverage` run (fat/local reads the warehouse;
  thin == fat parity: the SAME `CoverageSummary` renders identically).
- **release gate**: `release::gate::coverage_gate(&report)` fails when `Gap ≠ ∅`
  OR any stale entry — alongside the existing gates.

## 6. Tests (LAW 1 — inject + assert)

- pure (`nornir-testmatrix::coverage`): seed surface + covered + allowlist →
  assert Gap (unreached→gap, reachable→not, allowlisted→excused), seed→green-now,
  stale→red, rows + summary round-trip through serde.
- feeder (`src/autonom.rs`): knowledge→rows mapping detects test roots + idents;
  unreached fn is a gap, reached is not; discrete surface covered when handler
  reachable else seed→green; allowlist TOML round-trips through a file.
- warehouse (`src/warehouse/surface_coverage.rs`): append→query exact verdicts,
  `latest` picks the newest run, empty append is a no-op.
- viz (`src/viz/test_tab.rs`): `state_json["test"]["coverage"]` null-until-injected
  then carries the verdict; **thin == fat** parity.
- release (`src/release/gate.rs`): `coverage_gate` green→ok, gap→err, stale→err.
- MCP (`tests/mcp_matrix`): `test_coverage` + `release_gate_coverage` exercised,
  asserting the structured verdict (no silent gap in the tools/list).