Why AI-generated code fails code review in a different way

We have watched a lot of pull requests go through review in the past two years, and the ones that cause trouble later almost never look troublesome at the time. They are tidy. They are consistently named. They have docstrings. They get approved in four minutes with a thumbs up.
That is the problem, and it is worth being precise about why.
Code review rests on an assumption nobody writes down: that careless work looks careless. For most of the history of the practice this was true. A function doing four things, a variable called data2, a comment arguing with the code beneath it, three styles in one file because two people disagreed. These are signals. A good reviewer follows them to the defect, and the reason experienced reviewers are fast is that they recognise these warning signs rather than reading every line.
Generated code shows none of those signals. It applies the same clean style to the part that was carefully specified and the part that was invented from a plausible guess. Consistency stops being evidence of care.
What actually gets past review
Which defects appear, and how often, is the useful part, and it is measurable.
Veracode's Spring 2026 research tested more than 150 models across 80 coding tasks in four languages. Generated code compiled and ran correctly over 95 percent of the time. It passed security checks in roughly 55 percent. The average matters less than the difference between types of vulnerability. SQL injection passed at 82 percent, insecure cryptography at 86 percent, cross-site scripting at 15 percent, and log injection at 13 percent.
Look at which classes did well. SQL injection is the one every developer has been trained on, the one with an obvious pattern, the one a reviewer spots because the string concatenation is right there. Cross-site scripting and log injection are the opposite: the defect is spread across a few lines that each look completely ordinary, and identifying it requires tracking where a value came from and where it is eventually used. That is exactly the analysis a human reviewer does worst, especially as the tenth review of the afternoon.
So the failures are concentrated in the types of defect review was already weakest at, and generation produces more of them.
The second measurable thing is code that is almost right. Stack Overflow's 2025 survey found the single biggest developer frustration with AI tools was output that is "almost right, but not quite", named by 66 percent, with 45.2 percent reporting that debugging generated code takes longer than writing it themselves. Obviously wrong code costs nothing: it is deleted in seconds. Almost-right code is read three times, discussed, approved, and then turns out to be the cause of an incident five weeks later.
The three assumptions that stopped being true
That the author understood the change. Review has always been a conversation with someone who made decisions and can explain them. When a model produced the diff, nobody knows the reasoning. The reviewer ends up working out the requirement backwards from the implementation, which is the opposite of what review is for.
That effort limits volume. Writing code used to be slow enough to limit how much arrived for review. That limit is gone on the production side and unchanged on the review side. Attention cannot grow with volume: a reviewer facing four hundred lines reads the last hundred materially worse than the first, and everyone knows this and approves anyway.
That style shows quality. Discussed above, and it is the one that quietly removes an experienced reviewer's best tool.
What to do about it
Four changes, in the order they give results.
Move everything mechanical to a machine
A human should never be checking formatting, obvious null handling, or whether an error is silently ignored. Those are machine jobs and a machine does them perfectly at any volume. Every minute a reviewer spends acting as a linter is a minute not spent on the question of whether the change should exist.
This is the cheapest change and most teams have already done half of it.
Verify against the specification, not the implementation
The mistake is generating tests from the code. A suite written by reading the implementation asserts that the code does what it does, passes automatically, and proves nothing. It is worse than no suite, because it passes.
Checks have to come from what the software must guarantee, written before or independently of the code. The method is in writing specs an agent can verify, and the failure modes are catalogued in when evals give false confidence. The direct test: break something deliberately and confirm the suite notices. If it does not, the passing checks mean nothing, and it is much better to learn that today.
Make the change state its own intent
If an agent opens the pull request, the description has to supply what the absent author would have: what was asked for, what approach was chosen, what was deliberately not done, and what the reviewer should look at most carefully. A diff with no stated intent is not reviewable, only readable.
We treat a missing rationale as a review blocker in the same way a failing test is. It sounds bureaucratic and it takes about ninety seconds.
Limit the size automatically
Reject changes that are too large for a reviewer to understand all at once. Not as a guideline: as a rule that a bot enforces.
This is unpopular and it is the most effective thing on the list, because every other improvement is defeated by a two thousand line diff. If the work genuinely cannot be split, that is worth knowing before it is written, not after.
What the reviewer is for now
Narrow the human job deliberately, and it gets better rather than worse.
Should this change exist at all. Does it match what was actually asked for. How much breaks when it fails. What did somebody decide here that no test could express. What is missing that nobody would notice was missing.
That last question is the one only a person can ask, and it is the whole argument for keeping humans involved. A check verifies a rule someone thought of. It cannot notice a rule nobody thought of. Related reading is in what good code review looks like when nobody wrote the code and how to review AI-generated code.
The uncomfortable part
Some of this is a volume problem with no clever solution. If a team produces three times the change it did last year and has the same number of reviewers, something has to be reduced. Usually it is how carefully each change is read, and nobody says so, while the approval rate stays reassuringly high.
The honest options are to slow production, add review capacity, or build verification good enough that a reviewer can accept work without reading every line. The third is the only one that keeps working as volume grows, and it is engineering work that has to happen before the volume arrives rather than after.
Thanks to the reviewers who told us which approvals they regretted and why. In every case the code had looked fine, and looking fine had stopped telling them anything.
Review used to ask whether the code was written carefully. Now it has to ask whether it is correct, and those were never the same question.
Related guide: Enterprise AI coding governance.
Sources
- Veracode, Spring 2026 GenAI Code Security update: 150+ models, 80 tasks across four languages; over 95 percent syntactic correctness against roughly 55 percent security pass rate, with SQL injection at 82 percent, cross-site scripting at 15 percent, and log injection at 13 percent.
- Stack Overflow 2025 Developer Survey, AI section: 66 percent name "almost right, but not quite" as their biggest frustration; 45.2 percent report debugging generated code takes longer than writing it.


