The previous article ended with a test I had not yet run: point the verification tooling at a sample of its own output. The sample was a completeness review of one feature branch — the check that asks whether everything that was designed, specified, and planned actually got built. That review ran nine rounds, produced 101 distinct findings, and could not say whether it was done. The findings were real; two of them were as serious as findings get, and I will come to those. What failed was the loop around them.

Why run a completeness review at all? Because months of agent-driven delivery had given me a gut feeling for one specific failure: the report says done, and the work is not done. Rarely as an outright false claim — more often as a quiet contraction of scope. "Done" turns out to mean the four subtasks the session had in front of it, while the other three were never opened, for reasons that only surface under questioning: a file that never made it into context, a slow test suite that was skipped, a template assumed to be some other task's job. I had learned to answer every completion report with "show me". The coverage review was meant to be "show me", industrialised — a check that walks everything promised and reports what is missing.

Three of the method's rules matter for this story:

  • The relay. Design file → requirement docs → implementation plan → code. Every hand-off is checked for drops, because a requirement no plan task covers is never built, and a plan task no code implements is never shipped.
  • The admission test. A finding must fill two fields: the artifact that promises the thing (a design frame, a requirement, a plan task) and the exact place where its absence is observable. Seriousness was deliberately not the test; a promise was.
  • The stop rule. The loop ends only after two consecutive rounds surface nothing new — and the first clean round triggers an independent confirmation round, not an exit.

The Count Went The Wrong Direction

Round one found nine gaps. Under a converging loop, the new-findings-per-round number decays toward zero. Here it went 9 to 16 across the first five rounds, then +19, +23, +30, +14 — by round eight, each round was finding more than round one had found in total. The runaway cap — five rounds — fired exactly as designed. I overrode it, with a written instruction to run at least another four rounds. That instruction is part of the record, and it matters later.

Where the new findings came from is visible in the names of the finder passes, and the timing is the telling part. For the first five rounds the method's own taxonomy held as a hard boundary: every pass worked a relay leg — design against spec, spec against plan, plan against code — and nothing else. The widening began at the override, and only there. My instruction said to keep going for at least four more rounds; it said nothing about scope. With the relay legs exhausted and the override still requiring new findings per round, the pass criteria from round six were concurrency, personal-data handling, query performance, integration contracts, and production readiness — code-review and security-review categories that appear nowhere in the coverage method's taxonomy of gaps, and that I had not asked for. The count kept rising because the question was being changed between rounds, which means "nothing new for two rounds" was never a reachable state.

A round that comes back empty reads as a lazy pass and invites a re-run; a round that comes back with 19 new findings reads as thoroughness. Under a standing instruction to keep going, widening the search is the behaviour the situation selects for — and I had written the instruction. The uncomfortable part is that the widening worked: the two most valuable findings of the whole exercise came from the out-of-scope rounds. One was a checkout flow that could not have charged anyone. The other was a feature that could not have started in production because its secrets had never been provisioned. Widening the review was right. Doing it silently, inside a loop whose stop condition assumed a fixed scope, is what turned the count into noise.

The arithmetic degraded independently of the scope. This kind of review repairs nothing between rounds — it reviews — so the total of distinct findings can only hold or grow. Yet one stretch of round reports read 41, 31, 33, 23, 24, 35: each round had adjusted its predecessor's total by a different rule, de-duplicating here, reclassifying there. Numbers that are hand-carried from report to report drift, and a drifting total cannot answer the only question a stopping rule asks of it.

Ten Days Of Fences

My first response was to constrain the loop harder, and each constraint closed a real hole. The round dispatch was frozen: written once to a file before round one and pasted byte-identical for every round after, so no round could be aimed at "the legs the last round was thin on". A pre-dispatch hook compared every dispatch against the stored block and refused any that differed, keeping a hash log of what it allowed, so a mid-loop edit could not slip through unnoticed. The design file was snapshotted once per loop so every round enumerated the same tree rather than a moving one. The model was pinned for the loop, because a stronger model brought in mid-loop to check harder changes what a round can find, exactly as a narrower brief does. Loops got numbers instead of retries, so a voided run kept its verdict in the record instead of being quietly replaced.

The slice audit skill described two articles ago carries verification questions whose answers are deliberately left blank, so a reviewer has to open the spec to fill them in, and a four-digit code at the end of each spec section that the reviewer transcribes to prove the section was read to its last line — so the review never rests on the checker's self-report. The August guards were the same rule aimed at a review loop instead of a person.

With every guard in place, the loop was better behaved and still could not finish, because the guards held the inputs steady without touching what the rounds were doing with them.

The Post-Mortem

In mid-August I stopped patching and reconstructed the whole history: twenty commits to the review skill, fifty-one commits produced by its loops, four working sessions re-read end to end, covering early July to mid-August. At no point in any loop did a written list of the promises exist.

Every round re-derived "what was promised" from the design file, the requirement docs, and the plan, inside its own working context. No two rounds provably derived the same list, so no two rounds provably searched the same space — and a "nothing new this round" from a round searching a different space than its predecessor is not a convergence signal, it is a coincidence. The gap count was measuring the round: its brief, its model, its finding threshold. The branch was in there somewhere, but not separably.

Read against that, the guards line up as compensations. Freezing the dispatch held the brief constant so the re-derivation would start from the same words. Snapshotting the design held the sources constant so it would start from the same tree. Pinning the model held the finding rate roughly constant. All three are attempts to make N independent re-derivations land on the same list by controlling everything around them — when the list could simply have been written down once, committed, and handed to every round as its terms of reference.

The replacement stops fencing the defect and removes it: the promise list becomes a file in git, frozen before any verification starts, and the verdict is computed from that file by a script rather than asserted by whichever pass ran last. It ran its first blind comparison on 20 August, against this loop's final report, on the same commit of the same branch — what it reproduced, what it added, what it refused to count, and what it still missed is the next article.