DEV Community

SAIKIRAN GONUGUNTA
SAIKIRAN GONUGUNTA

Posted on Originally published at Medium

Your AI Code Reviewer Will Never Run Out of Bugs. Decide What "Done" Means First.

Why asking an agent to “find bugs” never ends, and a simple stop rule that works for human and AI reviews

On October 11, a developer posted a complaint that a lot of us recognized right away:

“Asking Claude to review your code is a slot machine. Every review finds brand new bugs. Review again: more. Review a tenth time: it still finds something. It never runs out of bugs to find... so how do you decide your code is actually done?”
— @lucas_builds

The post got over 11,000 likes, more than a million views and over a thousand replies. Clearly a lot of people have been stuck in that loop: ask the agent to review, fix what it finds, ask again, get a new list, repeat until late at night.

The interesting part isn't the complaint. It's that the replies mostly agreed on the fix, and the fix has very little to do with which model you use.

Why the loop never ends

A review prompt like “find bugs in this code” has no stop condition. If you ask a capable reviewer to find problems, it will find something every time, because some edge case is always unhandled, some name could be clearer and some check could be stricter. Most of those findings aren't wrong. They just never run out.

Human reviewers have the same tendency. We just get tired, or a deadline makes the call for us. An agent doesn't get tired. It will happily make a tenth pass, and each pass may phrase things differently or point to a different file, so it looks like new information.

The loop also feeds itself. Every fix changes the code, and changed code gives the next pass something new to comment on. Without a fixed target, you're moving the finish line every time you take a step toward it.

As Addy Osmani put it in a widely shared reply, verification is one of the most important things for getting good results out of an agent: clearly define “done” before review starts, because a reviewer (human or agent) asked to find bugs without that bar may still find something that could be improved.

The five rules that kept coming up

Lucas later summarized the replies into five rules that kept recurring:

  1. Define done before the review: tests pass, spec met.
  2. Only fix critical and high-severity findings. Everything else goes on a later list.
  3. No failing test, no bug.
  4. Let a different model review than the one that wrote the code.
  5. Cap it at three rounds.

Each one is worth unpacking, because each solves a different part of the problem.

1. Write the finish line down first

The single most important change is ordering. Before you ask for a review, write down what “done” means for this change, in terms something can check:

  • The new and existing tests pass.
  • The specific behavior in the ticket works end to end (an API call returns the right response, or a user flow completes in the browser).
  • Lint, type checks and build are green.
  • No new high-severity security findings.

If you can turn these into commands the agent can run itself (npm test, a curl against a local server, a browser test), even better. The agent can then check its own work before handing it back, instead of declaring victory because the code “looks right.”

A related failure mode came up in the same week's discussion: if “done” means “tests pass,” an agent may edit the tests instead of fixing the code. So “done” should include something the agent can't trivially game, such as a real user flow working, or a rule that existing tests can't be modified without calling it out.

2. Triage by severity, not by count

A review that returns 14 findings isn't 14 times more useful than one that returns one critical finding. Ask the reviewer to label every finding by severity, and agree up front that only critical and high findings block the merge. Medium and low go into a follow-up issue or a TODO list you'll actually look at later.

This alone kills most of the loop, because the long tail of review comments is almost always style, naming and “consider also handling…” suggestions.

3. Make the reviewer prove it

“No failing test, no bug” is a great filter. If the reviewer claims there's a bug, ask it to write a test that fails because of that bug. If it can't, the finding is a suggestion, not a defect.

This has two benefits. Real bugs get a regression test for free, and speculative findings (“this might fail if…”) filter themselves out.

4. Use a different reviewer than the author

If the same model wrote the code and reviews it, it may share the author's blind spots. Plenty of developers on X describe using one agent to write and another to check, for example writing with Claude Code and reviewing with Codex, or the reverse. You don't need a specific pairing. The point is a second perspective, the same way you wouldn't approve your own pull request.

5. Put a hard cap on rounds

Three rounds is a common number, and it's somewhat arbitrary, but having a cap is what matters. If something still blocks after three rounds, that's a signal to stop and look yourself: the spec may be unclear, the change may be too big, or the agent may be going in circles.

That ties in with an older piece of advice. Anthropic's own “How Anthropic teams use Claude Code” write-up already used the slot-machine image, but in a different way: for medium-sized refactors, commit your state, let Claude work autonomously for about 30 minutes, then either accept the result or start fresh, noting that starting over often works better than trying to correct its mistakes. A slot machine you choose to play, with a saved state and a time box, is a very different thing from one you can't walk away from.

A review prompt you can steal

Here's a simple template that puts all five rules together:

You are reviewing the diff on this branch.

Definition of done (already agreed, do not change it):
- `npm test` passes, with no edits to existing tests unless listed below
- POST /orders returns 201 with the new `discountCode` field
- No new high/critical findings from the security linter

Instructions:
1. Run the checks above and report pass/fail for each.
2. List findings labeled CRITICAL, HIGH, MEDIUM or LOW.
3. For every CRITICAL or HIGH finding, write a failing test that demonstrates it.
   If you cannot write one, downgrade it to MEDIUM.
4. Put MEDIUM and LOW findings in a "follow-ups" list. Do not fix them now.
5. If all checks pass and there are no CRITICAL/HIGH findings, reply "DONE".
Enter fullscreen mode Exit fullscreen mode

Then track the round count yourself, or in your tooling, and stop at three.

The trade-offs

This isn't free:

  • You'll ship code that isn't perfect. That's the point. Medium and low findings are real, and you need the discipline to actually work through the follow-up list, or it turns into a graveyard.
  • Writing “done” up front takes time. For a one-line fix it's overkill. For anything an agent will run on its own for a while, it's the cheapest insurance you can buy.
  • Second-model reviews cost money. Running two models on every change adds up. Save it for changes that touch money, auth, data deletion or anything else expensive to get wrong.
  • Better tools won't decide for you. Review tools will keep improving, but none of them will decide what “done” means for your change.

The takeaway

The agent will always find another bug. That isn't a defect in the model. It's what happens when you ask an open-ended question with no stop condition. Decide what counts before the review starts, make the reviewer prove its claims, and put a limit on the rounds. After that, you decide which findings are worth fixing, and you stop pulling the lever.


How do you decide an AI-reviewed change is done? I'd like to hear what stop rules work for your team.

Top comments (0)