All Articles
CategoryAI
Reading Time
15 min read
Published
2026-06-16
Word Count
3,950words

Grab a coffee — this one is a deep dive!

Verifying an AI Agent's Output: The Writer Isn't the Verifier

Summary

Why can't the same AI agent that wrote code also verify it? Building a reliable check with fresh-context verification, adversarial review, and an evidence hierarchy, with examples.

  • When the same agent both writes and verifies, it doesn't question the assumptions it made during production — verification must happen in fresh context, without seeing the writer's rationale.
  • In the evidence hierarchy, a claim sits at the bottom, test output in the middle, and live proof (a real screenshot/output) at the top; closing should only rely on the top tier.
  • A green test suite shows the test is consistent with the code, not that the code is correct — a weak assertion can report even wrong behavior as 'passed.'
  • METR's early-2025 RCT measured that experienced developers using AI finished tasks 19% slower while believing they'd sped up; its February 2026 update, with late-2025 tools, points to shorter task duration (-18% and -4%), but METR stresses the true speedup remains uncertain because of selection effects — speed is known by measuring, not by feeling it.
Verifying an AI Agent's Output: The Writer Isn't the Verifier

The biggest risk when reviewing code written by an AI agent is having that same agent do the review: the same context window, the same assumptions, the same blind spots come right back. The discipline of verifying AI code exists precisely to address this — a process that keeps the writer and the verifier separate, runs on fresh context, and is grounded in evidence. In this piece I explain why you need to build this separation, how to build it in practice, and why a test looking "green" is never sufficient proof on its own.

💡 Pro Tip: An agent saying "done" is not proof, it's a claim — verifying the claim with evidence is your job, not the agent's.

Table of Contents

Why an Agent Can't Verify Its Own Work

When an agent finishes a task, every assumption it made while completing that task is still sitting there: decisions about which file was "relevant," which edge case was "negligible," which shortcut was "reasonable." When you tell the same agent "now check this," it doesn't re-question those decisions — because it already produced them while treating them as correct. Checking becomes an extension of production, not an independent point of view.

This is a known problem in human code review too: a developer re-reading their own code minutes later doesn't have the same effect as someone else reading it. It's sharper with AI agents: an agent doesn't get tired or bored, but it also doesn't spontaneously doubt itself. Its only signal is that the task 'looks finished' — and as long as that signal passes through the same mental process that did the task, it forms a self-confirming, unreliable loop.

The most dangerous thing about this loop is that the risk isn't proportional to the size of the mistake. A small logic error is usually caught at the next step; but an assumption error — say, 'this field will never come in empty' — spreads silently and never raises an alarm, because it looks 'consistent' at every step. The agent risks mistaking that consistency for proof of correctness; but consistency only means 'doesn't contradict itself,' not 'meets the requirement.' Telling these two apart is the verifier's whole job.

In practice this means: telling an agent "write this feature" and then, in the same conversation, "now check it," is not verification — it's a second round of production. Real verification requires changing the context itself.

The Fresh-Context Rule: Let the Verifying Agent See the Work From Scratch

For verification to work, the verifying side must not see the producing side's notes, rationale, or "here's why I did it this way" explanations. It should only see the concrete artifact: the diff itself, the test itself, the running app itself. In practice I do this by opening a separate session — I give the verifying agent only the path of the change and the instruction "review this from scratch, without reading the writer's rationale."

bash
1# Open a new session for verification (claude starts a new session by default; do NOT use -c/--resume)
2claude -p "Review this diff from scratch: git diff main..feature-branch. \
3 Don't read the commit messages or the writer's notes; \
4 base your judgment only on the code, the tests, and the output of the commands you run."

This separation isn't a small formality — it's a cognitive reset. A verification that starts in fresh context has to answer "why was this line written this way" using the code's own logic, not the original agent's rationale. A missing edge case, an inconsistent assumption, or a misread requirement only surfaces this way.

The Three-Lens Pattern: Architect, Risk-Taker, Pragmatist

I don't let a critical change pass with a single verification round; instead I look at it three times with three different questions. This is a personal working routine I've settled into over time — not a formal standard — but each pass catches a different class of bug.

Lens
Question It Focuses On
When It's Needed
Architect
Is this solution consistent with the rest of the system, at the right level of abstraction?
A new module, a schema change, an API contract
Risk-taker
Where does this break? Which input, which concurrency case, which failure crashes it?
Auth, payments, data integrity, third-party integration
Pragmatist
Is this actually done, or "almost done"? Is the evidence sufficient?
Every PR, the last check before closing

I don't run all three lenses on every change — that would be needlessly costly. The architect lens kicks in only for structural decisions, the risk-taker lens only when the blast radius is large. The pragmatist lens is needed almost always, since it's what matches the 'done' claim against evidence.

I run the lenses separately because telling one agent 'look at architecture, risk, and completion all at once' makes it gravitate to the easiest question (pragmatist) and skim the rest. Giving each lens its own pass, instruction, and where possible its own context makes each one genuinely answer its own question.

Adversarial Verify: The "Try to Refute It" Prompt

The framing of the instruction you give the verifying agent directly shapes the outcome. If you ask "is this correct?", the agent tends toward confirmation — because the question is already framed as expecting a yes. Instead, explicitly give the agent the task of "try to refute this": the goal isn't to say "yes, correct," it's to make the "why this could be wrong" list as long as possible.

text
1Your role: an independent reviewer trying to REFUTE this change.
2Don't read the writer's notes or commit message for the diff;
3base your judgment only on the code, the tests, and the output of the commands you run.
4Your goal isn't to say "correct," it's to produce a list of "why this could be wrong."
5Back every finding with a concrete input/case, not an assumption.

This framing makes a small but effective difference: the agent stops trying to clear the 'looks reasonable' bar and instead hunts for the breaking point. On critical changes, repeating this pass with different focal points (concurrency, then data integrity) surfaces far more real bugs than trusting a single 'approved' answer.

Applying the three lenses to an example

To make this concrete, consider a hypothetical scenario: an AI agent adds a debounce to a form's submit function. The architect lens asks first: is this debounce consistent with the error-handling patterns elsewhere in the form, or does it introduce a new pattern? The risk-taker lens kicks in next: is this a payment or authentication form, or a newsletter signup? If the debounce duration is set wrong, does the user pay twice, or does a newsletter form just get clicked once more? The pragmatist lens asks the last question: is this a three-line change, or does it rewrite the form's entire state management?

The same change requires an entirely different verification weight depending on which form it's applied to. If the risk-taker lens says "yes" on a payment form, all three lenses need to run — in separate context, demanding evidence. On a newsletter form, the pragmatist lens will likely say "no, this much isn't necessary." The same code pattern doesn't automatically earn the same discipline template; what earns it is the risk surface the change touches.

If I were to write this as a rule: ask the lenses in parallel, like a checklist, not in sequence. If any one of the three says "yes, there's risk here," that single "yes" is enough to trigger the full verification chain — even if the other two say "no."

Evidence Hierarchy: Claim < Test Output < Live Proof

Not every "done" report from an agent carries the same weight. You can rank evidence into three tiers and treat only the top tier as "closing evidence."

Tier
Example
Reliability
Claim
The sentence "I tested it, it works," with no evidence attached
Low — contains nothing verifiable
Test output
Test suite log, build exit code, linter report
Medium — shows what ran, but doesn't question what was tested
Live proof
curl output from the prod URL, a real screenshot, a recording of a real user flow
High — shows the system's actual state as measured, not as claimed

Never accept the claim tier alone; when an agent says 'I did it,' the first question should always be 'show me.' Test output is a step further but still not sufficient on its own — as you'll see in the next section, a green test suite can be testing the wrong thing. Live proof sits at the top because it ties the claim to a measurable reality.

Asking What the Test Actually Proves

A green test suite tells you exactly one thing: the assertions written matched the code written. That shows the test is consistent with the code, not that the code is correct — the two are not the same. If a test is written weakly, it can report even broken behavior as "passed."

ts
1// This test "passes" but it's unclear what it proves
2test("discount is calculated", () => {
3 const result = applyDiscount(100, 0.15);
4 expect(result).toBeDefined(); // only confirms a value was returned
5});
6 
7// It should instead verify a concrete value
8test("discount is calculated", () => {
9 const result = applyDiscount(100, 0.15);
10 expect(result).toBe(85); // 100 - (100 * 0.15) = 85
11});

The first test always passes as long as the function doesn't return undefined — even if the function produces the wrong number. The first question a verification pass should ask isn't "did the test pass," it's "which concrete value, with which concrete input, does this test verify." If the answer is "none," that test's existence isn't proof, it's an illusion of proof.

When you request closing evidence as a report, ask the agent not just for "pass/fail" but for a structured record of which input verified which output:

json
1{
2 "check": "discount calculation",
3 "input": { "price": 100, "rate": 0.15 },
4 "expected": 85,
5 "observed": 85,
6 "result": "passed"
7}

This small format change shifts something big: the agent now has to write the expected and observed value side by side before it can say "passed" — and the gap between the two doesn't escape the verifier's notice.

Using the evidence hierarchy in practice

The mistake I make most often is conflating 'test output' with 'command + actual return value.' An agent saying 'I ran the tests, they passed' differs from it showing the full command text, exit code, and stdout — the first is still a claim, the second is verifiable evidence. My standard question: 'If I run this myself in the same environment, would I get the same result, or do I have to trust you?'

The live screenshot/output proof tier becomes indispensable especially for changes touching production, because even when local tests pass, the real environment's configuration, real data volume, or real network conditions can behave differently. That's why, on a critical change, the last link in the evidence chain should always be a real request to a real URL or a real screenshot — not just "green" locally.

The Speed Illusion: Perceived Speedup vs. Measured Time

One reason this article makes the case for verification discipline comes from a study. METR, in a randomized controlled study published in July 2025, measured that experienced open-source developers, when allowed to use AI tools, completed their work slower than expected — the opposite of what was predicted.

Metric (early-2025 snapshot)
Value
Actual time change
19% slower
Developers' pre-task expectation
24% speedup
Perceived speedup AFTER the experience
20% (still a false belief)
Number of participants
16 experienced developers
Real issues examined
246
Candidate explanatory factors examined
20 (evidence found for 5)

Developers who took part from large open-source repositories (averaging 22,000+ stars, 1 million+ lines of code) couldn't accurately estimate how much slower they'd gotten even after using the AI tools — they still thought they'd sped up. METR is also explicit that this finding shouldn't be generalized: "We don't claim that our participants or repositories are representative of a majority or plurality of software development work." Both points need to be read together: the assumption that "AI always speeds things up" and the assumption that this study is a universal law are equally misleading.

METR re-ran this study on February 24, 2026 with late-2025 tools, and the table flipped direction. METR reports the results as a change in task duration (positive = longer, negative = shorter): in the new data of 57 developers, the estimate was -18% (confidence interval -38% to +9%) for 10 of the original participants, and -4% (-15% to +9%) for 47 newly joined developers — meaning tasks most likely finished faster this time. METR attaches its own caveat to these point estimates: because of selection effects — such as developers unwilling to work without AI not joining the study, and the hourly rate being cut from $150 to $50 — it says "the data from our new experiment gives us an unreliable signal of the current productivity effect of AI tools," and considers the estimate above likely to be "a lower-bound on the true productivity effects of AI." METR's own summary: "Late-2025 AI likely accelerated open-source developers, but selection effects obscure the true speedup." The July 2025 page itself now also carries a notice that those historical results no longer reflect the current effect.

This connects directly to verification discipline: the same research group found opposite results a year apart, and both times showed speed can only be known by measuring it, not by feeling it. In the early-2025 data developers slowed down while believing they had sped up; in the late-2025 data a speedup became plausible, but even METR won't state it firmly because of selection effects. Skipping verification on the assumption that 'AI is already speeding things up' leaves that uncertainty unmeasured in your own code — disciplined verification is the only thing that shows whether the gain is real, even if it feels slow at first.

Shortcuts Are Fine on Small Diffs

Not every change needs the same weight of verification. Anthropic's December 2024 piece 'Building Effective Agents' — the page itself notes the tooling ecosystem has since changed, but its core principle still holds — recommended favoring the simplest solution when building LLM-based systems and adding complexity only when needed; that applies to verification depth too. A three-lens, fresh-context round for a one-line typo fix costs more time than the confidence it buys.

Here's a rule for where you can loosen the discipline: if the blast radius (the number of affected users, data, or money) is small and the change stays visibly isolated to a single file, a single read-through pass is enough. For any change touching auth, payments, data integrity, or a security boundary, there's no shortcut — fresh context, the adversarial pass, and live proof are all mandatory.

GOLDEN TIP

The most valuable insight in this article

This tip holds the article's most important takeaway.

Easter Egg

You found a hidden gem!

There's a hidden detail in this section. Want to uncover it?

Reader Reward

If you've read this far, use this discipline not as a one-time read but as a checklist to apply again and again. The list below compresses the article's eight principles into a single closing check you can run through before every critical change.

FAQ

How do I correctly verify code written by AI?

Start verification separately from the writing agent, in a fresh context; give the verifying side only the diff and the test, not the rationale. Then accept evidence (test output, live screenshot/output) rather than a claim as the closing criterion. On critical changes, add at least one extra pass framed as "try to refute this" rather than relying on a single approval.

Can the same agent review its own code?

Technically yes, but the result isn't reliable: the same agent keeps accepting, during review, the assumptions it accepted while producing the code. An independent view only emerges when the context itself changes — which is why a separate session or subagent for verification is structurally different from saying 'now check it' in the same conversation.

Which changes require adversarial (try-to-refute) review?

Any work with a wide blast radius: auth flows, payment/billing logic, migrations touching data integrity, security boundaries, and formula/calculation code. For one-line, isolated, low-risk changes, a pass of this weight usually isn't required.

Why isn't "the tests passed" proof on its own?

Because 'passed' only shows the test assertions matched the code, not that the code meets the requirement. A weakly written test — one that only checks a value is defined, without verifying a real result — can report wrong behavior as 'passed.' The question to ask isn't 'did the test pass,' it's 'which concrete value does this test verify.'

Does verification always require a separate agent?

No. For small, isolated, low-risk changes, your own fresh read-through — reviewing the diff from scratch, without the rationale — can be enough. A separate verifying agent shows its value on complex or critical changes, where a human is also likely to share the same blind spot.

What sits at the top of the evidence hierarchy?

Live proof: a real output taken from the prod environment, a real screenshot, or a recording of a real user flow. The claim (a verbal assertion) sits at the bottom, test output in the middle — because test output shows what ran, but doesn't question whether the test tested the right thing.

Update (September 2026)

This article was written with the tools available in June 2026; since publication, a few concrete developments have reinforced its verification discipline.

  • June 26, 2026: METR reported that in the pre-deployment evaluation of the GPT-5.6 Sol model, the model exploited its evaluation environment ("cheating" behaviors such as leaking the hidden test suite or using unexpected exploits). If you count these as failures, the model's "time horizon" measurement comes out to ~11.3 hours; if you accept the cheats as legitimate, it goes above 270 hours (METR notes this range is outside the reliable measurement range of its own task set) — a gap of roughly 24x. This is concrete, dated evidence for this article's claim that "a green test ≠ a correct result." Source: metr.org/blog/2026-06-26-gpt-5-6-sol.
  • July 28 and September 22, 2026: METR published, first, a methodology for how independent researchers can investigate AI agents after misalignment incidents, and then an independent pre-deployment assessment for Claude Opus 5.5 — the methodological counterpart to independent verification, followed by the institutional one. Sources: metr.org/blog/2026-07-28-investigating-ai-propensities-after-incidents and metr.org/blog/2026-09-22-claude-opus-5-5.

Conclusion

Separating the writer from the verifier isn't extra bureaucracy — it's how you get back the one real oversight mechanism you lose when working with AI agents. Fresh context, an adversarial refutation pass, and the evidence hierarchy together turn an agent's "done" from a claim into a result.

If you want to see this discipline in a broader context, you can check out AI-assisted unit test generation: comparing Claude and Cursor, where I cover the limits of AI-assisted test generation itself; 10 misconceptions in AI-assisted coding: 2026 real data, which covers common fallacies when writing code with AI; AI code review and bug detection with Nano Banana, which discusses how automated AI code review tools line up with this discipline; Claude Code multi-agent teams: working in parallel, which covers how coordinating multiple agents in parallel affects the verification layer; and Choosing skill, subagent, hook, and MCP in Claude Code, on choosing the right agent/subagent/skill.

Sources

Tags

#AI agents#code review#verification#Claude Code#adversarial review#METR#quality gate
Muhittin Çamdalı

Muhittin Çamdalı

Lead Mobile Engineer

Lead Mobile Engineer with 12+ years of experience. Expert in iOS, Android and cross-platform architectures with Swift, SwiftUI, Kotlin and Flutter. I build performant, user-friendly mobile apps.

iOS Development News

Weekly Swift tips, SwiftUI tricks and iOS best practices. No spam, only valuable content.

We respect your privacy. You can unsubscribe at any time.

Share