How should you review AI-generated code? Quality rules and acceptance criteria
Short answer: reviewing AI-generated code has to shift from hunting for mistakes to verifying intent. The output almost always compiles, the formatting is clean, and it reads plausibly. The failures collect somewhere else: a near-copy of a helper you already have three folders away, an error block that silently swallows unexpected input, logic that skips the edge cases, and an import line pointing at a package that does not exist. A compiler catches none of that. The only thing that does is a review process with written acceptance criteria and a delivery pipeline where tests actually act as a gate.
Throughput went up, stability went down
Google's DORA team reported in 2025 that 90% of technology professionals now use AI at work, and more than 80% believe it has made them more productive. Two findings sit side by side in that same report: rising AI adoption correlates positively with delivery throughput and negatively with delivery stability. More changes ship faster, and more changes come back. Change failure rate and rework both move in the wrong direction.
DORA's own framing is that AI is an amplifier. It does not repair a team, it enlarges whatever is already there. On a team with thin test automation, messy version control and review as a formality, AI produces defects faster than before. The same report notes that 30% of developers have little or no trust in AI-generated code. That distrust is reasonable, and it is not slowing anyone down. Put the two together and you get code nobody quite owns.
Where the quality signals are heading
GitClear examined 623 million code changes between 2023 and 2026, tracking eight quality signals. Every one of them points the same way. Duplicated blocks of five or more consecutive meaningful lines are up 81%. Moved lines, the signature of real refactoring, are down 70%. How often new commits call existing functions is down 35%. The density of error-masking constructs is up 47%, which covers empty catch blocks, safe-navigation operators and stubbed-out methods. Changes that touch code untouched for more than a year, the ordinary maintenance work, are down 74%.
That is a correlation, not proof of cause. The mechanism is still easy to predict. A model works from the open files and a few hundred lines of context, not from your repository. It does not know your formatCurrency helper exists, so it writes another one. It does not know how your error classes get logged, so it catches the exception and moves on. The result is not wrong. It runs. It just dissolves a little more of the shared structure in your codebase each time. The accumulation has a name, technical debt, and the interest is compounding faster than it used to.
The expensive failure mode is "almost right"
In Stack Overflow's 2025 developer survey, 84% of respondents use AI tools or plan to, while only 29% say they trust the accuracy of the output and 46% say they distrust it. The single largest complaint, cited by 66%, is the same one: solutions that are almost right but not quite. And 45% report that debugging AI-generated code takes longer than debugging their own.
That distinction matters for review. Obviously wrong code is cheap; it dies on the first test or the first read. Expensive code is the code that looks correct. It carries a bad assumption wrapped in valid syntax, sensible naming and a convincing comment. The reviewer checks the surface, the surface is clean, the approval goes through. METR's controlled experiment published in July 2025 measured that blind spot directly: experienced open-source developers took 19% longer on tasks where they were allowed to use AI, yet afterward estimated they had been about 20% faster. METR now labels the result historical, since the tools have changed. The part that has not changed is the gap between perception and measurement. A feeling of speed is not a metric.
What a reviewer should actually look at
Write the acceptance criteria down and put them in the review template. These are the spots that most often slip through on an AI-assisted change:
- Reuse. Does something equivalent already exist in the repo? No approval without checking. This one question is the only real answer to rising duplication.
- The error path. Is the caught exception handled, or just muted? Empty catch blocks and stubbed methods get rejected.
- Edge cases. Empty list, null, zero, negative values, oversized input, a second concurrent request. The model writes the happy path; the reviewer asks about the edges.
- The tests themselves. AI-written tests often mirror the implementation or assert only against a mock. Break the code and run them. If nothing turns red, there is no test.
- Data access. Queries inside loops, missing indexes, needless full scans. These patterns surface under load and are cheap to catch at review time.
- Secrets and configuration. Example keys, inline connection strings, hardcoded endpoints. Our note on secrets management goes deeper here.
- Dependencies. If a new package appeared: does it exist, is it maintained, is the license acceptable, is it needed at all?
That last item is a bigger problem than it looks.
The package that does not exist
An academic study across 576,000 code samples generated by sixteen different language models found that 19.7% of the packages suggested did not exist. Roughly one suggestion in five is a name that sounds right and has nothing behind it in the registry. Attackers noticed, and started registering the names that models invent repeatedly. The technique is called slopsquatting. The developer who copies the install command gets the attacker's package instead of an empty name.
The defense is not complicated, but it has to be automatic. No installs without a lockfile. Adding a dependency is a decision that goes through review. If you run an internal registry proxy, define an allowlist. Put dependency review and known-vulnerability scanning in the CI pipeline. Install a package because you confirmed it exists and is maintained, not because a model mentioned it. The wider subject lives under software supply chain security.
Put the rules in the repo, not in the prompt
One trait DORA found among teams getting more out of AI: their internal codebase and internal data are reachable by the tools. In practice that means writing the rules into the repository. Whatever tool you use, and most of them now read an instruction file at the repo root, state the things a newcomer would need: which shared modules exist and where they live, how errors are logged, which test framework is in use, which patterns are banned, what the rule is for adding a dependency. When the model does not have to guess from scratch every time, its habit of rewriting your helper drops noticeably.
There is a second distinction worth making. Describing a rule in prose is not the same as enforcing it by machine. A paragraph on a wiki page gets followed by humans and tools at about the same rate, which is to say rarely. A lint rule, a formatter, a type check and an architectural boundary check are not up for debate. Try to turn every pattern you want banned into a lint rule first; whatever resists that stays in the review template. As those two lists shorten, the reviewer stops arguing about style and gets to look at the logic.
Big diffs make review theater
The most concrete thing AI changed is the cost of producing code. An 800-line change is now an afternoon. Reviewer attention did not scale with it. On a large diff, human reading slides to the surface fast: naming, formatting, obvious copies. The logic goes unchecked, because it cannot be checked at that size.
The rule is simple. One intent per pull request, ideally under 300 lines. Whoever submits generated code should be able to explain what it does; if they cannot, it does not merge. That sounds strict and it is the only filter that works. Small changes are also a prerequisite for zero-downtime deployment, since the smaller the revertible unit, the smaller the risk.
Tests are the gate, not the decoration
The practical consequence of DORA's finding is that automated verification is the only mechanism that keeps a throughput gain from turning into a stability loss. If output doubles while verification capacity stays flat, the difference leaks into production. So the first investment for a team deciding to lean harder on AI is not a tool license, it is test automation.
Watch out for coverage becoming misleading here. AI writes tests quickly, and those tests inflate the coverage number without much effort. Coverage shows that a line executed, not that it behaved correctly. On critical modules, something like mutation testing tells you whether the tests actually catch faults, which is more informative than tracking a percentage. One more habit worth keeping: when a bug appears, write the test that catches it first, then fix it. The same bug does not come back twice.
Who signs off
This stopped being a technical question and became a governance one, and large projects have started publishing answers. The Linux kernel merged Documentation/process/coding-assistants.rst on December 23, 2025. The rules are explicit: AI agents must not add a Signed-off-by line, because only a human can certify the Developer Certificate of Origin. AI involvement is disclosed with an Assisted-by tag naming the agent and model version. The human submitter reviews the generated code, verifies license compliance and takes full responsibility for the contribution.
QEMU landed somewhere stricter and declines contributions believed to include or derive from AI-generated content. The reasoning is copyright: because the licensing status of training material is unclear, a contributor cannot honestly certify the DCO clauses. Using AI for research, static analysis or debugging is fine; putting its output in the patch is not. At the other end of the spectrum sits curl, which shut down its seven-year bug bounty on January 31, 2026 after fake security reports overwhelmed the team. Around a fifth of submissions were AI-generated, and the confirmed vulnerability rate had fallen below 5%.
Your company is neither the kernel nor QEMU. It still has to answer the same three questions: which kinds of work may use AI, where that use gets disclosed, and who owns the merged code. That is a one-page policy and an afternoon of writing. Skip it and what you end up with is a codebase nobody read and nobody owns.
Measure it instead of sensing it
Four signals are enough to start. Change failure rate: what share of releases needs a rollback or a hotfix? Two-week rework: how much of what you wrote this month was changed or deleted within two weeks? Duplication trend: is the count of repeated blocks rising quarter over quarter? Review latency and diff size: how many lines is the average pull request, and how long does it wait?
Those four tell you whether your team is using AI to move faster or to accumulate debt. If none of it is instrumented, start with observability and error budgets, because arguing about the direction of something you do not measure is just an exchange of opinions.
A concrete first step: pick one repository, record those four signals for a month, add the reuse and error-path items to your review template, and put dependency review in CI. You do not need to use AI less. You need the acceptance bar to rise along with the rate of production. If you are not sure where your codebase sits on any of these signals, get in touch and we will take a look.
Need help with this topic?