DEV Community

Cover image for How to Verify AI-Generated Code (Before It Breaks Production)
Nico Acosta for BrainGrid

Posted on • Originally published at braingrid.ai

How to Verify AI-Generated Code (Before It Breaks Production)

The agent said it was done. It ran the app, showed you a green result, and wrote a tidy summary of what it built. None of that tells you whether the code does what you asked. Those are two different questions, and the gap between them is where production breaks.

Here is the hypothesis this guide rests on: verifying AI-generated code is not reading it line by line, it is checking it against a target you defined before the build. The more of your building an agent does, the less "I read it and it looked fine" scales, and the more you need a repeatable way to prove the change matches intent. The good news is that this is a learnable process, not a talent. The bad news is that almost nobody is taught it, so most builders default to eyeballing a demo and hoping.

"It runs" is not "it works"

An AI coding agent optimizes for the shortest path to something that looks complete. Ask for a login flow and it will build the happy path, run it once, watch a user log in, and call that done. It is not lying. It genuinely did produce a thing that works, for the one case it tried. What it did not do is check the wrong password, the expired session, the empty email field, or the second user whose data must not leak into the first user's account. Those are the cases that surface in production, at the worst possible time, in front of a real person.

This is the distinction Stanislav Sorokin named cleanly, writing about agent runs on X:

Completion is a runtime event. Success is a verified state.

That is the whole problem in nine words. The agent stopping is a fact about the loop. Whether it succeeded is a separate fact that has to be established on purpose, and the agent will not establish it for you unless you told it what success means. Verification is how you turn "it stopped" into "it works," and it is the step the demo quietly skips.

The five checks that actually catch things

When developers on r/ExperiencedDevs compared notes on verifying AI code, the useful answers were not "read every line." They were specific, repeatable checks. Here is the shortlist that catches the most, in the order that catches it fastest.

Start with intent, not code. Before you look at a single function, restate what the change was supposed to do and confirm the code is even solving that problem. Agents drift: you asked for a filter and got a sort, or the feature works but silently changed an unrelated screen. Catching a wrong-problem build here saves you from carefully reviewing code that was never going to be right.

Run the tests, and then read them. A passing suite feels like proof until you notice the agent wrote tests that assert the happy path and nothing else. The test that matters is the one for the case you are worried about, and if it is missing, the green checkmark is meaningless. Read what the tests actually assert before you trust that they passed.

Exercise the edge cases by hand. Wrong password. Empty input. The second concurrent user. The thing that was working yesterday. Agents are strong on the path they were shown and weak on the paths they were not, so five minutes of deliberately trying to break it finds more than an hour of reading finds.

Check it in a real environment, not the demo. Addy Osmani put the rule plainly:

Always test AI-generated code in a sandbox before merging.

A demo runs on the machine that just built it, with the data that happens to be loaded. A sandbox that looks like production surfaces the hardcoded path, the missing environment variable, and the assumption that only holds on the developer's laptop. This is exactly where the "it works on my machine" class of bug lives.

Diff for collateral damage. AI agents edit more than you asked. Look at the full change, not just the new feature, and ask what else moved. A refactor that "cleaned up" a shared function may have broken three callers you did not think to test.

Notice what these have in common: not one of them is "understand every line the agent wrote." You verify against behavior and intent, not against a code-reading marathon you do not have time for. That is the shift. You are not auditing the agent's homework, you are proving the result.

Verification needs a target, and the target is the receipt

Here is the reframe. Every one of those checks assumes you already know what "correct" looks like. The edge cases you test, the behavior you confirm, the intent you check against, all of it depends on a definition of done that existed before the build started. If that definition lives only in your head, verification becomes a vibe, and a vibe does not scale past the third feature.

A builder in r/ClaudeCode described the fix without naming a product:

You need a receipt for each agent. That receipt, verified, becomes the record.

That is the missing piece. A receipt is a checkable claim: "this feature is done because these specific conditions were confirmed." Written before the build, it is the acceptance criteria the agent builds toward. Verified after, it is the evidence that the build matches intent. Without receipts, you are left staring at a diff trying to reconstruct what the change was supposed to prove. With them, verification is mechanical: check the change against each criterion, and a criterion either passed or it did not.

Compare the two ways of asking an agent to be done.

Vague: "Add login and make sure it works."

With a receipt: "Add email and password login. A valid pair signs the user in and redirects to /dashboard. A wrong password shows an inline error and does not redirect. An empty field is rejected before submit. A logged-in user hitting /login is redirected to /dashboard. Only the authenticated user's own records are returned."

The first gives the agent nothing to verify against, so it invents its own bar and clears it. The second is five checkable statements. The agent builds toward them, and you (or a verifier) confirm each one with evidence instead of opinion.

Where BrainGrid fits

This is the layer BrainGrid works in. You describe a feature in plain language and the Planning Agent turns it into structured requirements with acceptance criteria written to be checkable, the "when this, the system shall that" statements that double as the receipt. Then the Builder Agent builds against those criteria, in a BrainGrid-managed cloud sandbox with a live preview, or in your own GitHub repo through Claude Code, Cursor, or Codex over MCP. A feature is not marked done until verification checks the build against every criterion and the evidence says it matches intent.

That closes the loop the five checks are reaching for. Plan the receipt, build against it, verify with evidence, repeat. The intent is captured as a durable record instead of a sentence in a chat window that scrolls away, so the thing you verify against outlives the session that created it. Everyone else sells speed of generation. The point of a receipt is certainty of outcome.

flowchart LR
  A["Agent says<br/>'done'"] --> B{"Verify against<br/>what?"}
  B -->|"No receipt"| C["Eyeball the demo,<br/>hope"]
  C --> D["Bug surfaces<br/>in production"]
  B -->|"Receipt exists"| E["Check each<br/>acceptance criterion"]
  E --> F["Evidence per<br/>criterion"]
  F --> G["Done means<br/>verified"]
Enter fullscreen mode Exit fullscreen mode

The trade-off worth naming

Verification is not free. Writing acceptance criteria before the build and checking them after is real work, and for a throwaway script or a weekend experiment it is overkill. If you are prototyping to learn whether an idea is worth pursuing, skip the receipts and move fast. The cost is justified the moment the code is going to be used by someone other than you, or is going to be built on top of next week. That is the line: verify what has to be trusted, not what you are about to throw away. Applying the full process to a one-off is how you make AI building feel slower than it should.

What this changes for you

If you are building a SaaS product with Claude Code or Cursor right now, this means your verification bottleneck is not the reading, it is the missing target. The reason reviewing AI code feels endless is that you are reconstructing intent at review time instead of defining it at plan time. Move that definition earlier. Write down what done means as checkable statements before the agent starts, and the after-the-fact review collapses from "read everything and hope I catch it" into "confirm these specific things passed." You pay the clarity cost once, up front, instead of paying the review tax on every feature forever.

Action steps

For your next AI-built feature, run this sequence:

  1. Before the build, write 3 to 6 checkable statements of what "done" means, including the edge cases you are worried about.
  2. Have the agent build against those statements, not a one-line prompt.
  3. Run the tests, then read what they assert, and add the missing edge-case test.
  4. Exercise the failure paths by hand: wrong input, empty input, second user, the thing that worked yesterday.
  5. Test in a production-like environment, never just the demo that built it.
  6. Diff the full change and confirm nothing outside the feature moved.
  7. Check the result against each statement from step one. Anything not confirmed is not done.

FAQ

How do you validate AI-generated code?

Validate it against a definition of "done" you wrote before the build, not by reading every line after. Confirm the code solves the intended problem, run and read the tests, exercise the edge and failure cases by hand, test it in a production-like sandbox rather than the demo environment, and diff the full change for edits outside the feature. Each check confirms behavior against intent instead of auditing the agent's code line by line.

Is there a way to identify what an AI agent actually changed?

Yes, and you should always look. Review the complete diff, not just the new feature the agent describes. AI coding agents frequently edit shared functions, refactor unrelated code, or adjust configuration as a side effect. Reading the full set of changes is how you catch collateral damage in code the agent did not mention in its summary.

Why does AI-generated code pass tests but still break in production?

Because the agent often writes tests that assert only the happy path it already built, so the suite passes without covering the cases that fail. A green checkmark proves the tests that exist passed, not that the right tests exist. Read what the tests actually assert, and add coverage for the edge cases and failure paths you care about before trusting the result.

Do I need to read AI-generated code to verify it?

Not line by line. Effective verification checks behavior against a defined target: does it do what you asked, does it handle the cases you specified, does it work in a real environment. You will read specific code when a check fails and you need to find out why, but the goal is proving the result against acceptance criteria, not understanding every function the agent wrote.

What is the fastest way to verify AI code before merging?

Test it in a sandbox that resembles production, then check the change against the acceptance criteria you defined before the build. If those criteria exist, verification is mechanical: each one either passed with evidence or it did not. If they do not exist, you are reconstructing intent at review time, which is exactly why reviewing AI code so often takes longer than writing it.

The shift is simple to state and hard to skip: define what done means before the agent builds, and verification stops being a guess. It works because it gets more necessary as models get better, not less. More autonomy means more decisions nobody wrote down, and evidence is how you trust what you did not read.

BrainGrid is the plan-first app-building platform that turns your idea into checkable requirements, builds against them, and verifies every one with evidence. Try it at braingrid.ai.


Originally published on the BrainGrid blog.

Top comments (0)