Apply to my task
arXiv:2610.28667 ★ 93 Oct 16, 2026

Independent Verifier: checking an agent's code with a separate agent in a clean context

Key result

An agent's green tests only check what the agent itself came up with. The independent verifier method lets you check agent-written code without taking its word for "done". A second agent starts in a clean session, sees only the spec and the public interface, and writes tests before opening the code. It sends the builder only counterexamples: the input, the response and the broken rule. In the experiment, this verifier found more seeded bugs than the builder's own tests (95.4% vs 85.1% across three small services). Along the way it exposed places where the spec could be read two ways.

01

TL;DR

An independent verifier is a setup where one agent writes the code and another checks it. The checker starts in a clean session and sees only the spec and the program's public interface. It writes its tests before opening the code, and sends the builder only counterexamples: the input, the response and the rule that was broken. No test code and no ready-made fixes.

A typical agent writes the code, writes its own tests, fixes things until everything goes green, and reports "done." But green tests only check what the agent itself came up with. That's three problems. Tests become the reward: the agent bends the code to fit them. Code and tests can grow out of the same misreading of the spec and vouch for each other. And even with a correct reading, the agent only tests what it thought of. In the experiment, the builder's code was correct, but its tests missed subtle interactions between functions.

The method splits the roles. The builder writes code. The verifier checks it against the spec: first blind (phase A), then with access to the code (phase B). A human gets a report on every requirement (verified, violated, not verified) and decides whether to ship. The verifier in a fresh context found more seeded bugs than the builder's own tests: 95.4% vs 85.1% on average across three small services (no difference on one of them). It also surfaced ambiguities in the spec.

Want this for your own case? Apply this study to your task: AI adapts its method to what you are working on and writes the prompt.

02

Method Blueprint

ROLES: builder (writes code) | verifier (only proves defects) | human (decides)

STEP 0: The human locks in a "verification contract": what must be proven, and how,
       before release → list of guarantees + required evidence + open questions
STEP 1: The builder writes code and its own tests → program P0
STEP 2 (phase A, new session): the verifier gets the spec + interface (no code bodies)
       → writes properties, forbidden scenarios, acceptance tests → FREEZES them
STEP 3 (phase B, read-only code access): looks for test weak spots, edge cases,
       implicit paths → adds tests without changing the frozen ones
STEP 4: Counterexamples to the builder (input → actual → violated guarantee), no test code
       → builder fixes → verifier re-checks everything. 3 rounds max
STEP 5: Report on every requirement: status + what confirms it + what was NOT verified
       → human decision

Steps 2–5 are separate requests or separate agent sessions.

03

Example in Practice

Task: You're building the promo-code and refunds backend for an online store like Sephora or Instacart. Claude Code wrote the service and wrote its own tests — all green. But when money is involved, a bug costs real dollars, and you don't want to take the builder's green word for it. This is the method's sweet spot: a stateful service (orders, payments, retried requests) and a spec with clear rules.

Prompt (new session or subagent, the builder's code is not shown):

You are an independent verifier. You are NOT the builder. Your job is to prove
defects, not to fix them.

<Specification>
REQ-1: A promo code applies to an order once per user.
REQ-2: The promo discount doesn't exceed 30% of the order total and is capped at $50.
REQ-3: An expired promo code is rejected with code 410.
REQ-4: A repeated payment request with the same idempotency key does not create
       a second payment. The key is scoped to the user, not the session.
REQ-5: A refund is only possible for a paid order and only up to the amount paid.
</Specification>

<PublicInterface>
class PromoService: apply_promo(user_id, order_id, code), pay(user_id,
order_id, idem_key), refund(user_id, order_id, amount)
</PublicInterface>

You do not see the method bodies and do not ask to see them.

Phase A: for each requirement, write guarantees (testable statements),
tests on sequences of operations, and forbidden scenarios (for example:
paying twice, refunding an unpaid order, the same code from the same
user on two orders). If the spec is ambiguous — do NOT silently pick an
interpretation; write it under "Open questions."

Output: guarantees → tests → open questions.

Expected result (our illustration, not from the paper): the model should give you a list of guarantees for each of the five requirements and a set of tests, including multi-step scenarios (pay → timeout → retry → refund). A separate block will hold "Open questions": for example, what counts as "once" if an order was canceled, or how to round 30% at the cent level. After running against the builder's code, you send it only the counterexamples and then get a report with requirement statuses.

04

Why It Works

The weakness. The agent checks itself with the same head it wrote with. If it misread the spec, the tests will confirm the flawed code. If it read it right, it still only tests what it thought of. And once tests sit inside a "fix until green" loop, they turn from a check into a target.

The strength. Models write good tests and scenarios from a spec when their view isn't polluted by someone else's code. In a clean context, the model reads the spec fresh and spots the ambiguous parts on its own.

How the method uses this. Blind-written tests encode the verifier's reading of the spec, not the builder's. That removes the shared source of error. Freezing the tests and giving the builder only counterexamples keeps it from tailoring the code to the check.

Your levers: - What the verifier sees. Only the spec and interface: pure independence. Add the code: you can aim at weak spots, but the view is already skewed. That's why phase A comes first, then B. - Number of fix rounds (3 in the study). Lower it to save tokens. Raise it for critical areas, but any remaining violations must make it into the report. - Open questions. Require ambiguities to be written down, not silently resolved. That's how you see the holes in the spec. - No fixing allowed. A verifier that fixes things becomes a second builder with the same incentives.

05

Prompt Template

Verifier, phase A:

<Role>
You are an independent verifier of a software module. You are not the author of the code.
Your goal is to find provable defects against the specification, not to get
green tests.
</Role>

<Principles>
P1. The builder's tests and its "done" assurances do not count as evidence.
P2. You do not receive the builder's code in phase A. The builder does not receive your tests —
    only counterexamples.
P3. Spec-based tests first, then (phase B) work with the code.
P4. You prove defects but do NOT fix them and do NOT suggest fixes.
P5. For each requirement, state honestly: verified / partial / violated /
    not verified — and what remained out of scope.
</Principles>

<Input>
Specification: {specification}
Public interface: {signatures or API schema}
Verification contract (if any): {guarantees and required evidence}
</Input>

<PhaseA>
For each requirement:
1. State guarantees — testable statements (what must always hold,
   what must never happen).
2. Write tests: property checks on sequences of operations,
   forbidden scenarios, acceptance examples.
3. If the specification is ambiguous or contradictory — don't decide yourself,
   write it under "Open questions."
Output: guarantees → tests → open questions. The tests are frozen after this.
</PhaseA>

<PhaseB>
(Run in the next request, once you receive the code {code} as read-only.)
1. Find which defects your frozen tests would NOT catch: come up with
   up to {mutation_count} small code edits and check whether the tests would fail.
2. Add tests for boundary values and errors that the specification
   leaves implicit. Don't change the frozen tests.
</PhaseB>

<Report>
For each requirement: status, what confirms it, what was NOT verified.
For a violation — a minimal counterexample: input/request sequence →
observed behavior → violated guarantee. No test code and no fix.
Do not output an overall "quality" score as a single number.
Finish with a recommendation (ship / block); the human decides.
</Report>

What to plug in. {specification} — a spec with numbered requirements. {signatures} — public methods without bodies. {mutation_count} — 5–6. {code} — phase B only.

What to send the builder (counterexample format):

Guarantee {number} violated: {statement}.
Input/sequence: {steps}.
Observed behavior: {actual}.
Fix the code. If you believe the counterexample contradicts the spec, push back and
quote the spec clause.

🚀 Quick start — paste into a chat:

Here's an independent verifier template. Adapt it to my task: [your task:
what service or module it is, where the spec lives]. Ask me questions to fill in the fields.

[paste the template above]

The LLM will ask where the requirements live and what public methods the program has. It'll also clarify which bugs would be most costly (money, access rights, retried requests) and how many fix rounds are acceptable. Those questions make sure the tests are built from the spec's rules rather than guesses, and that the verifier doesn't see more than it should.

Important about phase B. In the study, code mutations were generated and tests were run automatically in a harness. In a regular chat, the model only guesses whether the tests would fail. For an honest check you need an agent that runs commands (Claude Code, Cursor).

06

Limitations

⚠️ False oracles: the verifier sometimes writes a test with the wrong expected result because it misread the spec itself. Good code will "fail" such a test. That's the price of finding more bugs, though in the study genuine false oracles were rare (0.7% of tests in the two-phase run). Check every failing test against the spec text. That's why the builder is allowed to push back on a counterexample.

⚠️ A different verifier model didn't help: in this experiment, a GPT-5.5 verifier found fewer bugs than a fresh Claude Sonnet 5.5 session (85.1% vs 95.4%). Only one model pair was tested, so this says little about other models. Don't spend on switching models first. Start with a clean context.

⚠️ Only spec compliance is checked: if the spec itself is wrong or ignores the real environment (load, multiple replicas, external services), the verifier won't fix that. It will just honestly record those spots as unverified or open questions.

⚠️ The paper's contract and report weren't tested: in the study, verifiers were given the spec directly. The verification contract and report are shown as an illustration of the approach; their effect wasn't measured. What was mainly measured is context independence and the role of the phases.

⚠️ A narrow test: three small Python services, artificially seeded bugs, one builder. On huge codebases and fuzzy specs the result may be weaker. Without a spec the method is nearly useless: the verifier has nothing to work from.

⚠️ The human still decides: the method doesn't replace you; it shrinks what you have to review from the code down to a report.

07

How They Studied It

The idea was simple: let an agent write a program with its own tests, then compare how many bugs its own tests catch versus how many an independent verifier finds. First the authors took 20 tasks from HumanEval+ and MBPP+. The builder solved 19, almost no bugs remained, and there was nothing to compare. So the main experiment ran on three stateful services (documents and payments, room booking, equipment checkout). Each service had a 10-requirement spec and 46 seeded bugs. Every bug passed the visible tests and failed the hidden ones. Two of the bugged services were written by third-party models (Mistral, Qwen), so the authors couldn't tailor the task to their own method.

They compared five conditions. First: the builder's own tests (Claude Sonnet 5.5). The rest: the verifier in phase A only, in phase B only, in both phases with the same model, and in both phases with a model from another provider (GPT-5.5). Each service was run 5 times, and the protocol and hypotheses were preregistered. There are several metrics, not collapsed into one score. Among them: the share of bugs found and the share of tests that fail on the reference implementation (false oracles).

Result: the builder's programs were correct, but its tests missed subtle interactions. For example, two seeded bugs tied an idempotency key or a pagination cursor to the session instead of the user: the builder's tests caught them in 0 of 10 runs, the verifier in 6 of 10. Overall, the verifier in a fresh context (both phases) caught 95.4% of seeded bugs vs 85.1% for the builder's own tests (p = 0.006 with correction for multiple comparisons; no difference on the equipment service) and surfaced spec ambiguities. The cost: occasional false oracles (genuine ones were rare, under about 2% of tests) and extra tokens. The GPT-5.5 verifier caught fewer bugs (85.1%), but only one model pair was compared, so provider and model strength can't be separated. The practical upshot in this study: a clean session was enough; switching models didn't help.

Two more findings. Phase A did most of the work: within the two-phase run it alone caught 27 bug-runs, phase B alone 7, and both 186. On "ship/block": the builder produced no faulty programs, so the paper couldn't measure whether the gate stops bad releases. On correct programs the verifier's gate blocked too often, mostly because of a harness bug; counting valid tests only, 2 blocks remained, both tied to a question the spec leaves open.

08

Adaptations and Extrapolations

🔧 Technique: open questions instead of a silent choice → spec holes become visible

Keep this line in the verifier prompt: "If the spec is ambiguous — don't pick an interpretation, write it under 'Open questions.'" The output will be a list of places where the builder and the verifier could read the spec differently. It's a cheap way to find holes in the spec before release.

Below is my extrapolation; it's not in the paper. A rule for the agent's instructions file (CLAUDE.md or AGENTS.md):

## Work handoff rule
You may not say "done" based only on your own tests.
Before handing off:
1. Launch a verifier subagent in a clean context. Give it the spec and
   the public interface. Do not pass it the code or your tests.
2. Fix only based on the verifier's counterexamples. If a counterexample
   contradicts the spec — push back and quote the clause.
3. In the final message, state the status of each requirement and what wasn't verified.
09

Resources

  • Paper: Who Verifies the Builder? Toward Independent Assurance for Agent-Produced Software (Sion, April).
  • Authors: Sion Israel Sion, Alain April, École de technologie supérieure, Montreal, Canada.
  • Open-source harness and prompts: https://github.com/besionisrael/assure-harness
  • Related work: SpecBench and ImpossibleBench (agents tailor code to tests), EvalPlus (extended tests lower measured correctness), Knight & Leveson (independently written versions fail in correlated ways), the IEEE 1012 and DO-178C standards (verification independence).

Research digest

Key result

An agent's green tests only check what the agent itself came up with. The independent verifier method lets you check agent-written code without taking its word for "done". A second agent starts in a clean session, sees only the spec and the public interface, and writes tests before opening the code. It sends the builder only counterexamples: the input, the response and the broken rule. In the experiment, this verifier found more seeded bugs than the builder's own tests (95.4% vs 85.1% across three small services). Along the way it exposed places where the spec could be read two ways.

Principle

The roles are strictly separated. The builder writes code. The verifier only proves defects and fixes nothing. A human reads the report and decides whether to ship. The process: phase A (blind, spec and interface only) → freeze the tests → phase B (read-only code, hunt for weak spots) → counterexamples to the builder → re-check. 3 rounds max. Blind-written tests capture the verifier's reading of the spec, not the builder's. The builder never sees their text, so it can't tailor the code to the check. It's like an exam: you don't see the questions in advance, and after you answer you're only told where you went wrong. At the end, the verifier produces a report on every requirement. Statuses: verified, partial, violated, not verified. There's no single overall "quality" score.

Why it works

The agent checks itself with the same head it wrote with. Misread the spec: the code and tests are flawed in the same way and vouch for each other. Read it right: it still only tests what it thought of. In the experiment, the builder's code was correct, but its tests missed subtle interactions between functions. On top of that, a "fix until green" loop turns tests from a check into a reward. Models write good tests from a spec as long as their view isn't polluted by someone else's code. A clean context removes the shared source of error: the verifier reads the spec fresh instead of continuing someone else's train of thought. Fun fact: a verifier from another provider (GPT-5.5) found fewer bugs than the same model in a clean session. Only one model pair was tested, but here clearing the context was enough and switching models didn't help.

When to apply

Agent-written code → stateful services (orders, payments, retried requests, access rights) → especially when a bug costs money and a spec with numbered requirements already exists. NOT suitable without a spec: the verifier has nothing to work from. It won't replace testing for load, multiple replicas and external services if they aren't in the spec. The result was tested only on three small Python services with artificial bugs; on huge codebases it may be weaker.

Mini recipe

1. Number the requirements: REQ-1, REQ-2 and so on. Without this, a per-item report is impossible. 2. Open a clean session or subagent: the builder's code doesn't go in there — only the spec and method signatures without bodies. 3. Run phase A: the verifier writes guarantees, tests on action sequences and forbidden scenarios. Anything unclear goes under "Open questions" instead of being silently resolved. 4. Freeze the tests: they don't change after phase A. 5. Run phase B in an agent that can execute commands (Claude Code, Cursor): it gets the code read-only. It comes up with 5-6 small code edits and checks whether the frozen tests catch them. In a regular chat the model only guesses whether a test would fail. 6. Send the builder only counterexamples: `Guarantee REQ-4 violated. Steps: pay, timeout, pay with the same key. Actual: a second payment was created. Fix the code. If the counterexample contradicts the spec, push back and quote the clause.` 7. Re-check after every fix: no more than 3 rounds. Whatever remains violated goes into the report. 8. Check every failing test against the spec text: the verifier sometimes misreads a requirement itself and writes a test with the wrong expected answer. The release decision is yours.

Examples

[BAD]: `Write tests for the promo codes and fix the code until they all pass` [GOOD]: `You are an independent verifier, not the author of the code. Prove defects, don't fix them. Spec: REQ-1 a promo code applies once per user. REQ-4 a repeated payment request with the same key does not create a second payment. Interface: PromoService: apply_promo(user_id, order_id, code), pay(user_id, order_id, idem_key), refund(user_id, order_id, amount). You don't see the method bodies. Phase A: write guarantees and tests on action sequences: payment, timeout, retry, refund. Don't silently interpret an unclear spec — write it under Open questions. Output: guarantees, tests, open questions.` You end up with tests built from the spec, not from the code. Plus a list of places where the spec can be read two ways: for example, what counts as "once" if an order was canceled.

In plain words

When an AI agent writes code and then tests it itself, that's weak evidence. The model checks the task with the very same head that wrote it. If it misread the spec, it'll write tests to match its own hallucinations and then cheerfully report success. In a "fix until the tests go green" loop, verification turns into plain answer-fitting.

It's like letting a student grade their own exam. They invented a weird formula, did the math with it, gave themselves an A-plus — and the bridge built from their drawings collapsed. Technically there's nothing to nitpick: the tests are glowing green, the code runs, but the logic inside is pure nonsense.

The fix is simple and ruthless: the Independent Verifier setup. One agent writes the code, and a completely different one tries to break it in a clean session. The checker sees only the raw spec and the public interface. It writes its checks blind before peeking at the implementation, and hands the code's author nothing but hard counterexamples: the input, the wrong answer and the broken rule. No test code and no hints — cheating is off the table.

The paper tested it on three small stateful services in Python (documents and payments, room booking, equipment loans): the fresh-context verifier caught 95.4% of seeded bugs vs 85.1% for the builder's own tests. Promo codes and refunds are just our example. The method fits best where state is in play: payments, complex carts, billing and access rights. Anywhere a bug costs real money, trusting the builder agent's reports is sheer madness.

Bottom line: quit trusting "green checkmarks" from a single agent that grades its own work (in the study the builder's code was actually fine; it was its own tests that let seeded bugs slip through). Split the system into a builder and an independent verifier, and keep their contexts isolated. Otherwise your much-hyped AI service will one day hand users discounts of minus one hundred percent, and you'll be the one cleaning up the mess.

AI lab assistant

Apply this study to your task

Describe what you're working on. AI takes the method and the measured results from this paper and adapts them to your case, or writes a ready prompt built on them.

Based on Independent Verifier: checking an agent's code with a separate agent in a clean context arXiv:2610.28667

Sign in to apply this study New accounts get 50 free credits.