cd /news/ai-agents/who-verifies-the-verifier · home topics ai-agents article
[ARTICLE · art-136588] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=· neutral

Who Verifies the Verifier?

A developer built a verification gate that forces Claude Code to prove each task in a real browser via the Kane CLI agent before it can stop, then audited the gate itself. Across twelve ORBITAL build tasks, eight failed at least once but only one was a real app defect; the rest were verifier problems such as slow agents, brittle assertions, and stale recordings, and six required human-reviewed overrides. The developer also found that their own write-up had misread the verifier's failures the same way the verifier misread the app, and that a standing self-override authorization weakened human oversight as the build progressed.

by read7 min views2 publishedSep 22, 2026

The premise of this series is that you should not take an agent's word that it is done. So I built a gate that makes Claude Code prove each task in a real browser before it may stop. The browser is driven by Kane CLI, which is itself an agent.

The obvious question arrives late and uncomfortably: why would I take that agent's word either?

This is the part of the story where the gate turns around and looks at itself. It has three layers: the verifier's failures, my own, and the rule that decides when to stop asking.

ORBITAL is the densest build in the project, the one with the doubled chart from Part 1. Every task went through the gate, and the Stop hook wrote each attempt to an append-only activity log. Here is the whole build, from that log.

12 of 12 verified. One sweep catch. Six overrides.

Eight tasks failed a check at least once. T1 failed on an assertion timing mismatch after the navigation it was checking had already happened, and passed on retry. Six more (T2, T3, T4, T9, T10, T11) failed badly enough to need a human-reviewed override. For every one of the six, kane-cli's own triage came back confirmed: false, family automation_bug. The causes were specific:

--author, all eight test files passed. The eighth was T7, the sweep catch from Part 1. That was the one real problem in the app across twelve tasks.

Eight failures, one bug. Read by exit code, all eight look the same.

Every raw failed result gets read against the verifier's structured verdict: verdict.confirmed, family, category, and confidence. Never the exit code. Then, before an override is allowed:

kane-cli's triage on the repeated failure. The same held across the other experiments. On the booking studio, six toast-timing failures were Kane's agent being too slow for a four second toast. On the todo build, a persistence check looked under the storage key the other build happened to use.

A slow verifier, a brittle assertion, a stale recording. None of those is the app. All of them look exactly like the app from outside.

This is the part I did not expect to write.

While putting this series together I went back to the repo's build log, OBSERVATIONS-AND-REPORTINGS.md, and checked each ORBITAL claim against the raw activity log. My write-up had done to the verifier's failures exactly what the verifier had done to the app. What my write-up said against what the log said.

The notes say the sweep "caught a real state-tracking defect" on the chart at T2. The log shows no sweep finding on T2 at all, only three scripted failures that triage called automation. The notes credit the sweep on T3 and T4; both were test problems. The notes call T9 "a genuine race"; the log shows all four export toasts confirmed in the same run and a redundant step failing afterwards.

Kane's bug_title fields made this easy to get wrong. Triage titles read like bug reports: "Replay misclassifies unlocked chart state". Lift that string out of its context, forget the confirmed: false next to it, and it reads as a finding. I lifted them. The first draft of Part 1 repeated them, before I checked.

The repo's own evidence gif has the same problem. The README captions this one as a caught defect:

A failed run on the chart lock, evidence pack 31fcd34b. Every failure on the chart task was triaged automation_bug, so I now read this as the verifier failing, not the chart.

Look at who cleared each override. T2 was recommended by a second Claude session and approved by me explicitly. T3 needed triage evidence and then my approval. T4, T9, T10 and T11 were cleared "under standing self-override authorization": a standing grant, not a fresh decision each time.

The evidence supports each of those calls. But the process got weaker as the build went on, and the log shows it. A human in the loop who has pre-approved the loop is not really in it.

All of which forces a design question I had to answer in code before I could answer it in prose. When the gate says no, how many times do you send the agent back? An agent told "try again" will try forever. It does not get tired or embarrassed. Somebody has to decide when the loop has stopped producing information and started producing noise.

GuardianKane's answer is three.

Every gate that can fail a task follows the same shape: increment attempts; under three, set KANE_FAILED and deny the stop with a reason; on the third, set BLOCKED_NEEDS_HUMAN. The details around the number matter more than the number:

IN_PROGRESS. CLAIMED_DONE. The agent cannot re-assert done on the same code. The clearest log of the cap in action comes from a later project, an ecommerce demo built with the rebuilt GuardianKane and committed with its unedited history. The three-strike rule is unchanged there. Here is its first task, T0:

| Time | Event |

|---|---|
| 20:15:30 | sweep FOUND ISSUE (attempt 1/3): (no summary) | 
| 20:27:58 | SECRET SCAN FAILED (attempt 1/3): server.js, high-entropy value assigned to "secret" | 
| 20:29:56 | sweep FOUND ISSUE (attempt 2/3): (no summary) | 
| 20:30:23 | sweep FOUND ISSUE (attempt 3/3): (no summary) | 

| 20:30:23 | BLOCKED_NEEDS_HUMAN after 3 sweep failures | | 22:11:02 | sweep found no issues, KANE_VERIFIED |

The escalation works. And the log taught me three things.

The counter went backwards. The first sweep failure is attempt 1. Twelve minutes later the secret scan failure is also attempt 1. The hook only ever increments attempts; nothing in it sets the field back to zero. But the counter lives in the task tracker, a YAML block in a markdown file the agent also edits, because the agent is the one who flips tasks to IN_PROGRESS. Nothing guards that field. I do not have data on what reset it in this run. The log only shows that it was reset.

That is the most important finding in this series. "Only the hook writes verification states" is a rule the agent is told, not one the file system enforces, and the same is true of the retry budget. A cap the capped party can edit is a suggestion. The fix is to keep attempts and the verification states in a file only the hook writes, and treat the tracker as a view.

The last two sweeps were not a browser looking at a page. Attempt 3 started at 20:30:21 and reported an issue at 20:30:23. Two seconds, no summary. A sweep drives a real browser against a running app; a two-second verdict with nothing behind it is not evidence about the app. The escalation was reached mostly on verdicts like that, which is the lesson from the top of this post again.

The human step is invisible. T0 sits blocked for about an hour and a half, then comes back clean. Whatever happened in between, a fix, a restart, a tracker edit, is not in the log, because the log only records what the hook does. For an audit trail, the most consequential step, a person deciding to reopen a blocked task, is the one it cannot see.

I do not have data that three is the right number. I did not run the loop with two or five and compare. What I am more confident about is the structure around it: honest failures retry, tampering does not, the verifier's own failures do not count, and the budget has to live somewhere the agent cannot write. The hackathon version got the first three right.

It does not weaken it. It sharpens it.

The original claim was "do not trust the agent's self-report". The better claim is "do not trust any unverified claim, including the verifier's, including your own summary of the verifier". Each layer needs its structured evidence kept next to its conclusion, so the next reader can check the step instead of the sentence.

In practice: read structured verdicts, not exit codes. Keep confidence and family next to every finding, everywhere it is quoted. And go back to the raw log when you write it up, because the summary is where the drift happens.

The raw log was right the whole time. Everything that went wrong went wrong in a summary.

That is also where the hackathon version runs out. A pass or fail line in a terminal cannot show you what the agent touched, which requirements are only designed and which are proven, or which failures were the checker. Answering that took a second build, and it is a different story.

Part 3 of 3, and the last. Previously: the requirement nobody wrote. The story continues in GuardianKane: it will not let your agent lie, starting with the second build was mostly wiring.

Part 3 of Your Agent Might Actually Lie to You. The original, with the full series navigation, is on my site.

── more in #ai-agents 4 stories · sorted by recency
── more on @claude code 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/who-verifies-the-ver…] indexed:0 read:7min 2026-09-22 ·