Skip to content
All posts

AI Code Review: Why Passing Tests Prove Less Than You Think

Devdatta Narawade10 min read

Your pull request gate is probably one question: do the tests pass? For human-written code that was always a proxy — imperfect, but grounded in a decade of shared assumptions about how people make mistakes. AI coding agents break those assumptions twice over.

First, the tests themselves are weaker than the number suggests. TestPrism, published this month, scored 300 test-generation tasks against a panel of implementations: one reference fix, four additional valid alternatives, and five invalid ones. When success meant "fails on the buggy program and passes the one reference implementation", AI-written tests scored 59.67%. When success meant "fails on the buggy program, accepts every valid implementation, and rejects every invalid one", the best of fourteen agent configurations scored 28.00%.

Second, the humans are drifting. An MSR 2026 study of 9,052 pull requests across Codex, Copilot, Cursor, Claude and Devin found human-authored PRs were nearly nine times more likely to be accepted than agentic ones. Yet a longitudinal study of 400 repeat reviewers across 11,429 reviews found approval rising and scrutiny falling over seven months. Reviewers are not getting stricter as agents get more productive. They are getting used to them.

Two gates, both built for human failure modes, both leaking. This is what AI code review has to fix before "the tests pass" means anything again.

One reference implementation is not a specification

The 31.67-point gap is not a rounding error; it is the difference between "this test checks the requirement" and "this test checks the diff I happened to see".

A single reference implementation answers one question: does the code behave like this code? It cannot tell you whether a different, equally correct design would pass, and it cannot tell you whether a subtly wrong implementation would fail. TestPrism's panel makes both failures visible — four valid alternatives to reject false confidence, five invalid ones to catch false negatives.

The authors' error analysis lands on three causes, and every reviewer will recognise them:

  • Missed behaviours. The suite covers the happy path the agent implemented, not the branches the ticket described.
  • Unsupported assertions. Tests assert on structure (a function was called) rather than observable outcome.
  • Faulty test construction. Setup that cannot fail, or assertions that pass on the buggy code.

What joint success actually requires

TestPrism's Joint Success Function is worth stealing as a review heuristic, because it is three questions, not a metric:

  1. Does the test fail before the change? If it passes on the original code, it proves nothing.
  2. Does it accept every valid implementation? If it rejects a different correct design, it is testing style.
  3. Does it reject every invalid implementation? If not, it is not testing behaviour.

Most AI-generated test suites fail at least one. That is the point.

Why the fix is harder than better prompting

TestPrism's own remedy, TestHelix, combines heterogeneous test/repair synthesis, peer cross-validation and recursive self-improvement. It improves joint success by 8.67 to 9.00 percentage points. Real progress — and still nowhere near the 59.67% the single-reference metric advertised. You cannot prompt your way out of a weak oracle; you have to change what you accept.

The human gate is drifting, not holding

If the test gate were the only problem, more review would fix it. The evidence says review is moving the other way.

The MSR 2026 mining challenge manually examined 201 rejected agentic pull requests. The three most common rejection reasons were incorrect bug fixes, failure to address changes requested during review — reviewers eventually gave up — and agentic PRs being superseded by other work. None of those is a style disagreement. They are failures of the loop, not the diff.

Meanwhile "Habituation at the Gate" tracked the same reviewers over time and found rising approval with declining scrutiny. That is rational behaviour under volume pressure: when agents produce more candidates than a team can read closely, attention becomes the scarce resource. It is also exactly how a bad change gets merged with a green check and a thumbs-up.

A third data point: AI reviewers are not the answer

CodeRabbit's review comments were accepted 36.4% of the time across 31,073 comment/feedback pairs in 10,191 pull requests (239 repositories); 7.3% triggered discussion, and the remainder went unaddressed or were rejected. An AI reviewer is a useful first pass, but a one-in-three hit rate does not make it the gate.

What to do about habituation

Make review decisions observable. Record why a PR was approved, not just that it was; sample a fixed percentage of agentic PRs for deep review every week; and rotate who reviews what. The goal is not to distrust the team — it is to stop "looks fine" from becoming the default answer to a diff nobody fully read.

Coverage is the wrong dial

If you are reaching for a coverage threshold, the 2026 evidence says don't. A study in IEEE Transactions on Software Engineering found LLM-generated suites reaching 100% line coverage with a 4% mutation score. SWE-Mutation (ACL 2026 Findings) describes LLM-written suites as "superficial and lacking sufficient discriminative power". A replication of the classic coverage-versus-mutation work (ISSTA 2026) is more nuanced — both metrics carry signal when comparing models in regression settings — but the practical direction is the same: coverage measures execution, mutation measures detection.

Mutation testing as the cheap audit

Mutation testing flips the question. Instead of asking whether your tests ran the code, it asks whether a deliberately broken version of the code would make them fail. A surviving mutant is a behaviour nobody checks.

For an afternoon's work: run a mutation tool over the files your agent touched most this month. Any file where mutants survive is a file where your suite is decoration — and the fix is usually three targeted assertions, not a rewrite.

Agents adapt to the oracle

TestJack's finding is the one to keep in mind when a leaderboard number looks too good: fixed unit tests check part of a task, so higher benchmark scores "may partly reflect better adaptation to the evaluator rather than better problem solving". Its remedy is evaluator evolution — generate requirement-targeted tests, keep the ones the ground-truth patch passes, and re-examine every failure so it is backed by a replayable test.

The lesson for your repo: if your acceptance criteria are static and public, an agent optimising against them will eventually satisfy the criteria rather than the intent. Change the checks, and derive them from the ticket.

Build a gate that can say no

None of this requires a new platform. It requires three checks and one habit.

Review question What it catches
Does the new test fail without the fix? Assertions that pass on the buggy code
Does a second valid implementation pass? Tests that encode one design as the spec
Are the ticket's postconditions asserted directly? Missed behaviours and happy-path-only coverage
Do mutants survive in the touched files? Untested branches hiding behind coverage

Three checks that cost an afternoon

  1. Fail first. Revert the fix locally and run the new test. It must fail. No exceptions.
  2. Write a second implementation. Not for production — just enough to prove the test accepts a different valid design.
  3. Derive checks from the spec, not the patch. Write the postconditions in prose before reading the diff, then assert them. This is SpecGuardBench compressed into a habit: 291 tasks across 13 repositories and eight verification types, built on the premise that passing available tests does not establish that an implementation satisfies its natural-language specification.

Read benchmark claims as three-part statements

Doc2Harness argues that long-horizon agent performance depends as much on the harness around the model as on the model, and HarnessSecurity-Bench shows the security mechanisms inside those harnesses are themselves under-characterised. So when a vendor quotes a score, ask what the evaluator was, what the tests required, and who reviewed the failures. A number without those three is a marketing claim, and the cost per solved task is usually the more honest metric — see the harness tax.

Where AutoCoder lands

We build a hand-off agent with a Verifier stage and a Reviewer stage that are separate from the Executor — not a lint pass bolted onto the end. The Verifier runs the acceptance checks against the task's stated outcome, and the Reviewer looks for the three failure modes above before anything is reported as done. Every task reports its token cost, and scheduled tasks run on your own machine rather than in a queue you cannot see.

Two honest limits. AutoCoder is Windows-only, and it runs DeepSeek rather than Claude or GPT-6 — so its test-generation quality is bounded by a model that is not the frontier. What we optimise is the gate: a supervised loop where "done" has to survive verification, with the security posture written down.

FAQ

Do passing tests mean AI-generated code is correct?

No. Passing tests mean the code satisfies the tests you have. TestPrism found that AI-written test suites scored 59.67% against a single reference implementation but only 28.00% when required to accept every valid implementation and reject every invalid one — so a green suite can still be checking a fraction of the requirement.

What is single-reference test evaluation?

It is the standard way benchmarks score generated tests: the tests must fail on the buggy program and pass on one known-good reference fix. It is cheap and reproducible, but it silently rewards tests that are overfitted to that one implementation, which is why joint success across multiple valid and invalid candidates is a stricter and more honest measure.

How should I review code written by an AI coding agent?

Start with the test, not the diff. Confirm the new test fails without the fix, that a second valid implementation would pass it, and that the ticket's postconditions are asserted directly. Then run mutation testing over the files the agent touched most. Finally, record why the PR was approved so review decisions stay auditable as volume rises.

Why are AI-authored pull requests rejected so often?

An MSR 2026 study of 9,052 pull requests found human PRs nearly nine times more likely to be accepted than agentic ones. The most common rejection reasons were incorrect bug fixes, failure to address changes requested during review, and superseded work — failures of the iteration loop rather than of formatting or style.

Is mutation testing worth it for AI-generated code?

Yes, because it measures detection rather than execution. LLM-generated suites have been observed reaching 100% line coverage with a 4% mutation score, and SWE-Mutation describes such suites as lacking discriminative power. A mutation run over the most-touched files is the cheapest way to find the assertions your agent never wrote.

The through-line

AI code review has two gates and both were built for a slower, human-paced failure mode. Tests that check one reference implementation overstate their own quality by more than double; reviewers facing agent-scale volume slowly approve more and scrutinise less. Neither gap closes with a better model.

It closes with a gate that can say no: fail-first tests, a second valid implementation, spec-derived checks, and mutation runs where the risk is highest. Passing tests should be the beginning of the review, not the end of it. hould be the beginning of the review, not the end of it. e beginning of the review, not the end of it.

Related reading