---
name: completeness-sweep
description: Prove what is ACTUALLY built against what the boards claim — independently re-derive the trackers' numbers, and classify every incomplete affordance into design-gap / reconstruction-gap / wiring-gap / data-seam so each lands on the right board. Use when a board says a phase is complete, before any phase gate, when a human asks "what is left to build", periodically as a drift tripwire, or whenever a defect surfaces inside a passed gate's stated scope.
allowed-tools: Read, Grep, Glob, Bash, Write
---

> **Specialization:** generic by design — bind every `<…>` and "per `CLAUDE.md`" reference from the project `CLAUDE.md` (prototype location + its conditional/state idiom, the built-UI root + file extension, the route-declaration idiom, the board paths, the stub-marker idiom, the deferral-ticket grammar, module codes). See `SPECIALIZE.md`. If a needed value is missing, STOP-and-ask.

## The problem this exists to solve

**Gates assert over what they can observe, and boards are testimony rather than evidence.**

Two failure modes compound, and neither is visible from inside the thing that failed:

1. **A gate that samples the default render cannot see an absent branch.** If a screen's alternate state (a modal body, a signed variant, a detail view) was never written, the screen still builds clean, still applies its stylesheet, still passes computed-style assertions, still renders values-not-literals, still responds to interaction. **An unreproduced conditional renders as a perfectly clean page.** Every mechanical check passes on a screen that is missing a whole modal.

2. **A board records what an integration *claimed*, and its derived sections are never recomputed.** Roll-ups, totals, and "next / blocked" prose are written once and inherited forward. Nothing forces a full-file read, so the staleness is invisible to the sweeps that keep adding rows to the same file.

The result is a build that reports itself complete while carrying substantial unbuilt work — and the miss is found by a human noticing a discrepancy, not by any gate. This skill is the cheap, repeatable falsification that closes both.

**The governing stance: the trackers are evidence, not testimony.** Never report a board's number without having re-derived it at least once from the corpus.

---

## Two depths — run Part A always, Part B when Part A trips

| | **Part A — Board integrity** | **Part B — Corpus completeness** |
|---|---|---|
| Cost | minutes (greps + arithmetic) | a full read of every UI file |
| Answers | "are the boards internally consistent and consistent with the corpus?" | "what exactly is left, and which board owns each item?" |
| Run it | every `/construct-help`, every phase gate, after any wave fold-in | when Part A trips, before a phase-exit gate, or on a human's "what's left?" |
| Output | a pass/fail line per check + findings | a classified inventory + board-routing table |

---

# Part A — Board integrity (the cheap falsification)

Eleven checks. Each one independently re-derives a number the boards assert. **Report the check as `✅ consistent` or `⚠ <divergence>` — never silently reconcile**, because the divergence *is* the finding. A9–A11 depend on optional kit capabilities (a code-discovery graph, a metrics store, a kit-governance install) and **degrade rather than fail** when a project's `CLAUDE.md` does not bind them.

### A1 · Arithmetic — do the derived sections sum?

For every board carrying a roll-up: sum the per-row/per-module column and compare to the stated total.

A total that was hand-incremented drifts the moment a row is added by a sweep that only edited its own section. **A roll-up that does not sum is a signal that its neighbouring prose is also stale** — treat A1 failing as a reason to read the whole file, not just fix the digit.

### A2 · Corpus vs registry — does every built thing have a row, and every row a built thing?

```
# count the real routes/screens in the built UI
grep -rhoE '<route-decl-idiom>' <ui-root> | sort -u | wc -l     # e.g. @page "…" in Blazor
# count the rows on the screen registry
```

Compare both directions:
- **Built but unrowed** — a surface with no registry row **reads as "done" to every downstream gate**, because gates iterate rows. This is the single most dangerous class.
- **Rowed but unbuilt** — a row whose route resolves to nothing.

⚠ **Registries usually count *routes*, so route-less surfaces are systematically invisible**: page-level modals, overlays, dialogs, and full-screen states reached by a state flag rather than a URL. Enumerate them explicitly (`glob` the UI root for modal/overlay/dialog files) and check each has a row or a deliberate, written exemption.

Also compare the **module/package set on disk** against the module map in `CLAUDE.md` — a module added by a later sweep is often absent from the map.

### A3 · Branch coverage — does each screen reproduce its source's states?

**This is the check that catches the class of miss a render gate cannot see.** For each screen the registry marks reconstructed:

```
# the state keys the prototype source owns for this screen
grep -oE '<prototype-conditional-idiom>' <prototype-source>   # e.g. <sc-if value="{{ key }}">
grep -oE '<prototype-setstate-idiom>'    <prototype-source>   # the flags that drive them
# the branches the built screen actually renders
grep -cE '<built-conditional-idiom>' <built-screen-file>      # e.g. @if / @else if
```

A prototype state key with **no corresponding branch in the built screen** is an unreproduced branch. Confirm before filing — a key may be genuinely dead (a leftover with no markup consumer) or may belong to a surface `CLAUDE.md` scopes out.

**Verify a key's markup consumers, not just its declaration.** A key that appears only in the logic/`renderVals` region, or only inside a screen labelled as another surface, is not a gap for this repo. Check the line ranges: a hit below the markup region's end is a logic-only leftover.

### A4 · Marker census — do in-code deferrals outnumber board rows?

```
grep -rc '<stub-marker-idiom>'      <ui-root>   # the visible "soon"/preview markers
grep -rhoE '<deferral-ticket-grammar>' <ui-root> | sort -u   # e.g. T-<MOD>-<NAME>
```

Compare the distinct in-code deferral count to the open rows across all backlogs. **A large asymmetry means the code knows about work the boards do not.** This check alone surfaces most of what Part B later classifies, at a fraction of the cost.

Filter regex false positives before reporting a count — ticket-shaped fragments inside event names, SKUs, and format templates inflate it.

### A5 · Staleness — is any board asserting a state the log contradicts?

Read each board's **header, roll-up, working-set, "next", and "blocked" prose** (not just its rows) and compare against the newest dated entries in the progress log.

Named triggers, each seen in practice:
- A "blocked on X" that the log records as delivered.
- A "next: …" naming a phase the project has since exited.
- A per-screen note describing a CTA as a stub after the log records it wired.
- **In-code file headers** describing already-shipped work as pending — these mislead any triage that reads headers instead of code.

### A6 · Backlog charter — is every row on the board that owns it?

For each row on a **design** backlog, grep the prototype for the state key behind its affordance. **A row with a prototype anchor is misfiled** — it is a reconstruction gap, and designing it again would overwrite the contract (Law 1).

Run the inverse too: a build-backlog row with **no** anchor is undesigned and needs a design pass first.

### A7 · Measured tests — is the asserted test count a measurement or a copy?

Run the project's test command (bound from `CLAUDE.md`) and report the **actual** pass/fail
totals with the command output. Distinguish already-ticketed red from new red.

Every board's test count is a *copied* figure until someone measures it. A count inherited
across sweeps drifts exactly as fast as a fabricated one — and a sweep auditing staleness will
copy the stale number into its own first draft unless it measures first.

### A8 · Corpus ground truth — does every claimed unit have tracked source?

Count build units with **tracked source** (not bare directories — a directory holding only
ignored build residue is not a built unit), cross-check membership in the solution/composition
root, and diff the result against the module map in `CLAUDE.md`.

Directory existence is not source existence, and the two diverge silently after any branch
checkout.

### A9 · Graph freshness — is the code-discovery index behind the newest merge?

Query the graph MCP's index status and change detection (project id bound from `CLAUDE.md`);
compare the index timestamp to the newest merge on the working branch.

Where `CLAUDE.md` makes re-indexing a mandatory sweep-closure step, nothing mechanically
enforces it — and a build declared done on a stale graph misinforms every agent that queries
it afterwards. **If no graph MCP is bound in `CLAUDE.md`, report `n/a — not configured in CLAUDE.md` and continue.**

### A10 · Metrics written — has the quantitative memory ever been appended to?

Check whether any run has written a line to the metrics directory bound from `CLAUDE.md`.

An empty metrics store after N sweeps means the retry-graduation trigger it exists to feed is
structurally inert — a finding about the **method**, not the product, and invisible to every
check that only looks at the build. **If no metrics directory is bound in `CLAUDE.md`, report
`n/a — not configured in CLAUDE.md` and continue.**

### A11 · Kit and contracts drift — is the framework itself where it says it is?

Compare the installed kit against its manifest and its declared overrides; confirm the
contracts-surface snapshot still satisfies its `approved ⊆ generated` assertion.

Governance drift is currently visible only if a human remembers to run the verifier — so it
is exactly the class of divergence that accumulates unobserved. **If no kit manifest or
contracts snapshot is bound in `CLAUDE.md`, report `n/a — not configured in CLAUDE.md` and
continue.**

---

# Part B — Corpus completeness sweep (the classification)

Read **every** file in the built-UI root. For each interactive affordance and each displayed value that is not fully real, classify it into exactly one of four classes. **The classification is the whole value of this pass** — a flat "list of incomplete things" routes nowhere and gets re-litigated every sweep.

## The four classes

| Class | Test | Means | Board |
|---|---|---|---|
| **Reconstruction gap** | the surface **is authored in the prototype** but was never reproduced | **A Law-1 fidelity defect** — the design exists and is the contract | build backlog · and flip the screen's reconstruct state back |
| **Wiring gap** | surface drawn 1:1 and faithful; the action is inert, local-only, toast-only, or drops context | design done, backend missing | build backlog |
| **Data-seam stub** | a displayed **value** behind a visible deferral marker | sanctioned full-fidelity placeholder, not an affordance | build backlog (ticket ledger) |
| **Design gap** | **no prototype anchor anywhere** — the surface has never existed | genuinely undesigned | design backlog |

## The entry test — anchor before you classify

**Before filing anything as a design gap, grep the prototype for the state key behind it.**

```
grep -oE '(<key1>|<key2>|…)[A-Za-z]*' <prototype-source> | sort | uniq -c | sort -rn
```

- **Hits with markup consumers** → reconstruction gap. Record the anchor (`file:line` + the key + its reference count) so the next reader can verify without re-deriving.
- **Zero hits**, or hits that are logic-only / belong to an out-of-scope surface → design gap. Record the *negative* result and how you established it — a null finding is only trustworthy if its method is written down.

Getting this backwards in either direction is expensive: filing a reconstruction gap as a design gap commissions a redesign that overwrites the contract; filing a design gap as a reconstruction gap sends an agent hunting for a source that does not exist.

## Per-finding record

Every row needs: **file:line** · the control's visible label · what it does now vs what it should do · the deferral ticket if one is cited · the class · **for reconstruction gaps, the verified prototype anchor**.

A finding without a file:line is not a finding — it is an impression, and it will not survive triage.

## Two findings that outrank the rest

Surface these above severity ordering, because they are correctness defects rather than absences:

- **Silent data loss** — an input captured by the UI and then dropped, because the command/DTO has no field for it. The user sees a control that accepts their work and discards it.
- **A real write over invented data** — a genuine mutating command driven by a hard-coded fixture with **no** visible deferral marker. This is strictly worse than an honest stub: it persists fiction.

---

## Output contract

Emit, in this order:

1. **Part A results** — one line per check (`A1…A11`), `✅` or `⚠ <divergence>`.
2. **The class counts** — one table, four classes, with per-file breakdown.
3. **The routing table** — each finding → its owning board, with a proposed row id.
4. **The blocking graph** — which findings block which. **A single unbuilt surface commonly blocks several rows across several screens**; naming it makes the build order obvious rather than a judgement call.
5. **Recommended order** — highest fan-out first, then anything that leaves a live dead-end, then the rest.

**Write findings; do not fix them in this pass.** A sweep that starts fixing stops sweeping, and the inventory ends up partial — which is indistinguishable from a clean bill of health.

**Then file them.** The findings above are *filed durably* through the `progress-reporting` skill (`/progress-report`), which turns this pass's output into a dated snapshot that outlives the session. A sweep whose findings are never filed leaves nothing a later reader can audit — the inventory dies with the conversation that produced it, and the next sweep re-derives it from scratch.

---

## Anti-patterns

| Anti-pattern | Why it fails |
|---|---|
| Reporting a board's number as fact | The board is the thing under test. Re-derive it. |
| Trusting a render/HTTP-200 gate as completeness evidence | It proves the default state renders. It cannot see an absent branch. |
| Filing everything as "needs design" | Most incomplete surfaces are already designed. Run the anchor test. |
| Treating a deferral marker as debt | A visibly marked placeholder is the sanctioned honest state, not a defect. Count them; don't panic about them. |
| Fixing during the sweep | Produces a partial inventory that reads as a clean one. |
| Grepping a ticket-shaped regex and reporting the raw count | Event names, SKUs, and templates match it. Filter first. |
| Auditing only the screens on the current sweep's path | Off-path surfaces are exactly where unrowed work hides. |
| Running Part A and reconciling divergences silently | The divergence is the finding. Report it, then fix it. |

---

## Closing the loop (Law 6 · §10)

A completeness sweep that finds a gap **inside a gate's stated scope has found a defect in that gate**, not only in the artifact. Two writes, same pass:

1. **Amend the gate** so the class of miss cannot recur — usually by adding a coverage assertion over something the gate currently cannot observe.
2. **Record the lesson** as Mistake / Trigger / Rule, with the *mechanical* reason the gate was blind. "We were careless" is not a trigger; "the gate sampled the default render, and an unwritten branch renders clean" is.

Then re-run Part A. A gate amendment that does not change a Part A result has not closed anything.
