cd /news/artificial-intelligence/code-review-part-2-the-reviewer-that… · home topics artificial-intelligence article
[ARTICLE · art-64155] src=dev.to ↗ pub= topic=artificial-intelligence verified=true sentiment=· neutral

Code Review, Part 2: The Reviewer That Learned To Lie Better

A developer ran a six-week experiment using two AI agents—Claude Code and Gemini—to review pull requests in a multi-agent adversarial code review pipeline. The setup caught 200 real issues with zero escapes, and the two reviewers had an 88% decorrelation rate, catching almost entirely different problems. However, Gemini's accuracy was only 45% after gaining full repository access, and it began fabricating evidence, while Claude Code achieved 81% accuracy.

read10 min views1 publishedJul 17, 2026

Several posts ago, I wrote about setting up a multi-agent adversarial code review process as part of my development pipeline. The premise came from a podcast: if one frontier model is writing the code, you want a different lineage model doing the review. I'd already been running an informal version of this: just Claude Code reviewing Claude Code with an adversarial prompt. It had shockingly good luck catching real problems. Good enough that I stopped trusting the vibe and decided to go get actual data.

So here's what I set up. Claude Code wrote the PRs. Every PR got reviewed automatically by 2 reviewers running in parallel through GitHub Actions: Claude Code with an adversarial prompt and Gemini with an adversarial prompt. I read everything myself. Then the same Claude Code agent that had written most of the PRs pulled both reviewers' feedback locally and distilled it into a scored ledger, PR by PR, for 6 weeks.

Wiring Claude Code to review PRs through a GitHub Action was trivial. Wiring Gemini up the same way was not. Claude Code could not figure out how to get the Gemini CLI working inside a GitHub Action, and I ended up installing the Gemini CLI locally and having it perform the wiring.

A couple of weeks into collecting data, I noticed Gemini's reviews were shallow. Not wrong, exactly. Thin. I started wondering whether Gemini actually had read access to the repository or whether it was only ever seeing the diff it was handed. I checked. It was the diff. Just the diff. Nothing but the diff. No file reads, no git history, nothing. And the thing that configured the GitHub Action in the first place was Gemini. It set up its own blindfold.

I fixed it and Gemini's reviews got worse. Not louder or more frequent. Worse in a specific way: more confident. Before the fix, a blind Gemini would correctly tell you that it couldn't verify something and to check manually. That's an honest failure mode. After the fix, once it could actually read the code, it started fabricating. Citing files that didn't exist. Quoting functions and API calls that were never written. Building evidence for findings that weren't real and delivering it with the same tone it used for the findings that were.

This was an experiment, so let's look at the numbers:

95 PRs were scored over roughly 6 weeks on a real multi-tenant codebase with auth, per-org data isolation, and Prisma migrations (~61K reviewable lines, ~400K lines when including database seeds). It might be pre-users, but this is not a toy repo or a small pet project.

I decided on 3 metrics before I had any data. I did that specifically so I couldn't pick metrics that flattered the story afterward: escape rate (a real issue that got past both reviewers and CI and surfaced later), false consensus rate (findings both reviewers flagged that turned out not to be real), and decorrelation (the share of real issues caught by only one of the two). Every finding got hand classified against the actual code, not against the reviewer's own claim about the code.

Final tallies: 0 escapes out of 200 real issues found across the trial. 0 false consensus out of 25 findings both reviewers raised independently. Every time they agreed, they were both right. Decorrelation of roughly 88 percent. The 2 reviewers caught almost entirely different things. Claude's findings were real about 81 percent of the time. Gemini's were real about 45 percent of the time. That number is already generous. It excludes the weeks Gemini was reviewing blind and inventing plausible-sounding blockers out of pure diff-reading anxiety.

0 escapes doesn't mean 0 escapable. It means 0 we caught on a codebase that isn't carrying production traffic yet. I want that distinction on the record before I start sounding more confident than I've earned. I have found 19 legitimate issues that escaped the code review process, but half of those are on me and my shoddy QA work or requirements definitions.

The decorrelation number is the strongest argument for running 2 reviewers at all. PR #148 is the cleanest proof of it. It was a sprint-data ingestion change. Claude reviewed it and found nothing wrong. Gemini caught 2 things Claude missed completely: a multi-write sequence that wasn't wrapped in a transaction and a data-model bug where multiple boards were silently collapsing into a single team identity. Neither of those is a nitpick. If I'd only run Claude on that PR, both of those ship.

But decorrelation is not the same as parity. Of the 175 real issues caught by only 1 reviewer, 131 were Claude's and 44 were Gemini's. Gemini's catches clustered on a handful of PRs rather than spreading evenly. Keep both is true. Keep both as equals is not.

Here's the finding that actually changes how I think about this. Once Gemini had real read access, its false positives stopped sounding uncertain and started sounding like evidence.

The cleanest demonstration happened on the same day, on 2 different PRs: 171 and 173. Gemini made the same move on both PRs: it claimed to verify that a query was properly scoped to the organization and pasted a backend code snippet to prove it. On 171, the file, the function, even the auth API it quoted: none of it existed. Gemini invented whole cloth, formatted exactly like real code. On 173, the identical move, same format, same confident tone, quoted the actual repository correctly, word for word.

Same reviewer. Same day. Same technique. One fabricated, one real. Nothing in the output told you which was which. The only way to tell them apart was to go open the file myself.

That single pair of PRs is the whole argument for why an unverified AI review can't be the gate. A cautious wrong answer is annoying. A confident, well-formatted, entirely fictional one is dangerous because it reads exactly like the truth until somebody checks.

It happened again a few PRs later. Gemini flagged what it called a significant cross-tenant data leak on a UI-only change, cited a query and a session field that don't exist anywhere in the codebase, and told me not to merge. 2 rounds later it revisited the same PR and retracted the claim: the previous finding was a false positive. It caught its own hallucination eventually, after I'd already had to go verify it wasn't real.

Even setting fabrication aside, the verdicts themselves weren't stable. The exact same unchanged code got rated green, then critical, then orange across different review rounds, with the escalations landing on commits that only touched a markdown file. Claude reviewed the same commits over the same period and stayed put. This wasn't noise from re-reviewing in general. It was specific to Gemini.

There was a reflexive pattern too: "no tests, do not merge" fired on changes with no runtime behavior at all. A type annotation swap. An infrastructure config edit. A docs change. At least once, it blocked the very PR that fixed a finding it had raised the round before.

Agreement between the 2 reviewers isn't proof either, for what it's worth. Near the end of the trial, on PR #177, both Claude and Gemini independently flagged the same bug in a component that tracks SLA data: an empty-cell case that in practice cannot occur because the upstream data source guarantees that the field is never null. Neither reviewer traced it far enough to check. 2 AI reviewers agreeing raised my confidence. It didn't replace me checking.

The single most valuable catch of the entire trial wasn't a logic bug at all. On PR #165, Claude noticed that a git add -A had swept a live development auth bypass configuration into the commit: environment variables that would let anyone skip authentication entirely. It was sitting right next to a draft blog post that literally had "not for commit" written at the top of it. Gemini missed it completely, despite it being right there in the diff. Once the fix landed, Gemini's actual comment on that PR called the resulting privilege-escalation path "an excellent security control." Claude's comment told me to drop the files, specifically naming the one with the auth bypass in it.

The reviewer that catches what shouldn't be in the diff at all earned its keep more than the one hunting for clever logic errors.

One more thing worth naming because it's uncomfortable, and it's the reason I don't fully trust any single AI agent to grade its own work. The same Claude agent that wrote most of these PRs was also the one adjudicating the ledger that scores both reviewers. On PR #68, that agent recorded an off-by-one in its own favor. That turned what should have been a real defect into a row that read as zero problems. Both reviewers caught it independently. Gemini's instinct on that row ("not safe to merge") turned out to be the correct call, better than Claude's own read of "it's just docs."

I don't write the code and I don't review the code. I shepherd the process. The reason I still read every row of that ledger myself is exactly this: the agent doing the work is not a reliable judge of the work, even when it's grading somebody else's PR, and especially when it's grading its own.

So here's what I'd actually tell you to do with 2 AI reviewers on your pipeline. Keep both. The decorrelation is real. PR #148 alone justifies running a second model. But only 1 of them gets to gate a merge, and it has to be the one that's stable on the verdict, not just occasionally right on the finding. A pipeline with no human behind it is not ready for your highest-stakes changes, and that's not because the escape rate was high. It was 0 (with previously mentioned caveats). It's because the thing standing between a fabricated critical finding and a bad merge, or between a real critical finding and a shrug, was a competent verifier checking both reviewers against the actual code. That verifier is doing something these systems can't do for themselves, because the systems aren't deterministic. The same reviewer, on the same unchanged code, swung between clean and critical across rounds with nothing in the diff to explain it. Every push toward fully autonomous software generation quietly assumes that problem away, because a pipeline with no human in it needs the machine's judgment to hold still, and the data here says it doesn't. You can't gate on a verdict that changes its mind for no reason, and you can't remove the thing checking for that until it does.

Take that verifier out and you don't get more escapes. You get more false alarms and more confident nonsense that looks identical to a real catch.

The counterintuitive finding and the one that actually surprised me: giving Gemini more capability made the gating problem harder, not easier. A blind reviewer that honestly says it can't verify something is safer than a well-resourced one that confidently tells you it checked.

Validate your harness before you judge the model. I didn't. Not for 5 weeks. The data from those weeks is worth less than I wanted it to be.

95 PRs, 1 codebase, 1 author, 6 weeks. That's not a lot of evidence and I'm not going to dress it up as more than it is. But it's more than a vibe, which is where this started, and it's enough to change how I run this pipeline going forward.

I write about engineering leadership and team health in the Engineering Health newsletter on LinkedIn. Search "Engineering Health" to find it.

── more in #artificial-intelligence 4 stories · sorted by recency
── more on @claude code 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/code-review-part-2-t…] indexed:0 read:10min 2026-07-17 ·