Raw capture â raw/agentic-verification.md
url: https://addyo.substack.com/p/agentic-verification date_fetched: 2026-10-18
If you give an AI agent a way to independently verify its work, that can heavily improve the quality of output. Agents write code âmuch better on average at scaleâ. The âat scaleâ part comes from verification. Agents make checking cheap.
The stuff that made âGood Codeâ expensive (tests, benchmarks, specs, real e2e runs) is now a cheap thing you can ask an agent for. You can improve the checks.
So our work is less âreview every lineâ and more âbuild loops the agent can run itselfâ. Give the agent a way to verify the work. That loop is where quality comes from.
And make taste compound. When the agent gets something wrong, write it down (shared config, a hook, a test) so it doesnât happen twice. A human still owns what ships but now theyâre reviewing evidence and not just diffs.
To make your agent produce high-quality output, equip it with a way to check its work. Tests are part of that.
Here are some of the ones I think are worth investing in.
Write end-to-end tests that simulate real user flows and act as the ground truth
Use property-based testing to specify what should never happen and generate thousands of test cases that attempt to break those constraints
If replacing a system, compare the old and new versions using randomly selected inputs
Require tests to run quickly and deterministically, which reinforces the agent to retry when the loop is slow or unreliable (the agent may learn to retry, not fix the problem)
Example tests say what should happen; properties say what must not.
Todayâs models are good enough that the major bottleneck is not code-writing but the ability to verify that the code theyâve written is correct.
If your agent canât verify its output, itâs essentially guessing, and a wrong guess ends up being verified by your test suite. That is, youâll have a feedback loop in which youâll go back and forth until you can read diffs, run your tests, check out the app, find bugs, and report them back. This is the slowest, costliest feedback loop, and itâs not scalable to more than one human.
But if your agent can test its own output, itâll write a change, run the check, read the output, and try again over and over until it can pass the check. This is what happens before a single human even has to see anything. Itâs hard to overstate the improvement in quality that you can get out of a self-verifying agent vs a feedback loop dominated by humans. I would always prefer a much better feedback loop to a slightly better model.
This is a new definition of tests. For years, tests were the main tool humans used to identify bugs and refactor reliably. These are still good reasons to write tests, but tests are also how your agent senses the world and knows when itâs done.
Not every test is equally valuable for this purpose.
If you had to choose only one test to use, it would be E2E tests. They describe what a real user does.
An E2E test is what a human would do: sign up, add an item to the cart, checkout, and see a confirmation. It ignores the internal structure of your code and sees only what the user can see.
This is the kind of oracle you want for your agent. Machines will often write code that passes checks but misses the big picture. A mock-based unit test might pass, and the feature could be broken because the agent and your test share a misunderstanding. An E2E test, on the other hand, is very hard to trick. Either the whole thing works, or it doesnât.
What makes E2E tests especially valuable for agents beyond their use in CI/CD pipelines?
They cover only important, meaningful user flows, not all possible paths.
They tell you whatâs wrong: Screenshots, tracing, and an explanation of which step failed tells the agent what went wrong, rather than making it flail in the dark. âTimeout after 30sâ tells you nothing.
They work on the agentâs local configuration as well as its deployment environment.
They define âdoneâ: âImplement this featureâ is too vague. âMake this E2E test passâ is a target the agent can chase on its own.
Itâs important to say that E2E tests have trade-offs that are real: they are slower and flakier than traditional unit tests. The choice is not to eliminate them, but to prefer a small set of high-value tests.
Note: E2E tests are excellent, but as Lauren (@poteto) stresses giving the agent hands and eyes on the real running system is worthwhile: a maintained skill/CLI that knows how to launch, drive and observe the app (CDP, simulator, API harness, etc.), plus a feature map. A feature map is a user-POV inventory: what features exist, how a real user reaches them, keyboard shortcuts/selectors, expected outcomes and gotchas.
Many kinds of tests are about what a human thinks might go wrong. Property tests are about what a human doesnât consider: the cases where agents go wrong.
Much of what humans write in tests is about examples: âIf this is the input, then the output should be this.â These tests are good at ensuring that something should work, but theyâre poor at ensuring that something should never fail: Humans canât think of all possible inputs that would fail.
Property-based tests reverse the premise: You create a rule that should hold, and a tool will generate hundreds or thousands of inputs to break it. Tools like fast-check for JS/TS, Hypothesis for Python, and proptest for Rust do this well. When a failure is found, the input is reduced to the minimal case that breaks the test: It wonât bomb with a random blob of data.
Here are some properties that are common in nearly every software project:
When youâre working with agents thatâs crucial, because the agent is going to make up its own test examples that succeed based on its own internal logic. The property forces the agent to deal with any input generated, not just ones it chooses.
*Note: Property tests and differential checks cover a lot, but Boris Cherny of Claude Code has been using models (Lean, TLA+) on the hairiest state machines, concurrency and data-flow pieces. Short prompts can surface race conditions and subtle bugs by building a model, finding counterexamples, reproducing them, and fixing. *
Properties are a great way to specify your requirements. If I say that the total for a cart must always be the same as the sum of its line items, thatâs a great specification. The agent can use that specification to construct its own code, and a generator can look for discrepancies.
One of the classic failure modes of a rewrite is that itâs able to pass the new test suite, but it diverges from the old system in many small, undocumented ways. This is the difference between the official specification and actual behavior. Users end up relying on what actually works, not what the specification says should work.
Differential testing bridges that gap. Instead of relying on your new test suite, run the old and new systems side by side with the same inputs. If thereâs a discrepancy in the outputs, youâve either introduced a bug in the new system, or youâve deliberately made a change you should document as a breaking change.
This is where choosing your input matters. If youâre using test cases manually chosen by you, youâll miss rare edge cases. Randomly generate inputs, replay a sample of live traffic, or both. This is equivalent to property-based testing, with the property that your new systemâs outputs match the old systemâs outputs.
Differential testing is brilliant for agent-assisted large-scale migrations. You loop between tweaking the new system, running the differential test, reviewing the mismatches, fixing them, and restarting the loop. Because the old system is the oracle, you donât have to explain every edge case to the agent. Teams thatâve done both versions and run the diff tell me that it was a shift from fixing one breakage and creating another to carefully and methodically progressing through the comparison.
Tests must be fast and deterministic, or the agent will pick up the wrong lesson.
Itâs not merely a time sink - itâs a training exercise. If the tests are slow or unstable, the agent will learn that sometimes just restarting the test is better than trying to fix the problem.
Humans are kinder to bad testing infrastructure. We know which tests are flakes, we know to rerun the CI in case of failure, weâre willing to wait 20 minutes for a build that might be flaky. The agent, however, learns from the incentives of the loop. If itâs possible to retry a failing test and have it work once in a while, itâll pick retrying as its preferred strategy. If it takes 15 minutes to run the tests, itâll run them less often, batch more changes between each run, and lose the ability to pinpoint exactly which change caused a failure.
Both failure modes cause the agent to get worse, but without any visible sign of failure, so you produce lower-quality output for humans to review.
Here are a few ideas of what I think âgoodâ might look like - the agent should learn from the incentives of the loop.
Note: A few extra practical habits include explicit goal restatement (ârestate what you think the success criteria areâ) before coding, fresh-context or separate reviewer agents for verification and treating generated tests themselves as artifacts that need some scrutiny (does this test actually distinguish correct from plausible-incorrect implementations?).
Before telling your agent to make something, you have to know what itâs supposed to succeed at. That could be an end-to-end workflow, a specific property, or a comparison to a prior system. Whatever it is, make sure that itâs fast and deterministic, and you can let the agent iterate over a solution.
Your job doesnât need to be reading each line of output, but you need to define what success looks like. Youâre getting better value out of your judgment and it will scale better than you will ever read a diff.
When youâre testing your agent, you need to have examples of what should happen and properties of what should not. To win, your agentâs testing process needs to be fast and accurate.
Tracks with what weâre learning as well, using real user session data to map our application runtime surface and self-healing e2e test coverage: https://sightmap.org/blog/building-in-layers
This matches where I ended up. I stopped reading diffs a while ago and now only look at the decisions: schema, boundaries, what talks to what. What I'm still unsure about is who writes the E2E test. If the same agent writes the feature and the test that defines done, don't they share the same misunderstanding you describe with mocks?