← Back to all posts

Cross-Model Review: A Second Opinion Before Every Merge

AI writes code faster and faster, but a human’s review bandwidth is a constant. In a day of a dozen-plus commits and several PRs, I can’t read every line.

My rule now: every merge needs a second opinion. Another model, or at least an independent fresh session, reviews the change first. The rule is written into my pre-PR checklist; it doesn’t depend on remembering.

But this is more involved than “have another AI take a look.” Here is the method I arrived at the hard way.

1. Review fails in two ways

Failure Looks like Cost
False positive (hallucination) Reports a problem that doesn’t exist A wasted round; worse, correct code gets “fixed” into broken code
False negative (miss) A real problem goes unreported The defect lands on main

Intuition only guards against the first, because it’s visible. But the second is more expensive. I once shipped a page that crashed entirely: type checks, unit tests, and the build were all green, and not one of them checked whether the copy had translations.

So the protocol has to block both. Guarding only against hallucination guards only the cheap half.

2. Who reviews: participating is not reviewing

Setup Independence
Cross-model: A writes and B reviews, B writes and A reviews Strong — two sets of priors
Same model, fresh session Weak — they miss the same kinds of things
Self-review in the same session None — doesn’t count

With only one model available, fall back to a fresh session of the same model, but never feed it the implementation context, only the diff and the checklist. Feed it context, and it will just retrace the implementer’s reasoning.

One rule that sounds obvious but has bitten me: this round’s executor cannot be this round’s reviewer. In one batch, another model spent the whole time writing code as the executor, and at wrap-up “it was involved in this batch” got casually read as “independent review was done.” A model that wrote the code has a stake in it; having it check its own work is self-review.

Independence comes from two sets of priors, not from a new process, a new session, or a new prompt.

3. Not every change needs review

Reviewing everything is mathematically a failure: AI output keeps speeding up, human verification bandwidth doesn’t. The budget should go to the small fraction where failure is irreversible. My trigger is any one of:

  • many files or many lines changed;
  • touching money, permissions, data integrity, or external actions that can’t be undone;
  • changing a public contract: external routes, shared components, type definitions, the copy catalog;
  • spanning two or more modules.

Small changes just go through the normal gates.

4. Writing the prompt: give it the complement, don’t ask “any problems?”

Ask “does this code have problems?” and you get a pile of style opinions. A useful prompt has five parts:

  1. Scope. Which files are in and which are out, plus an explicit “review only, don’t modify anything” — the reviewer has write tools and will use them unless told not to.
  2. What the change is meant to do. Write intent, don’t restate the diff. It can read the diff; it can’t read your reasoning.
  3. Hard rules it must verify. The project’s invariants, e.g. “this kind of data only comes from the backend; the front end must never hard-code it.” This is where a second model earns its keep.
  4. What I deliberately didn’t do, and why. Ask it to attack these decisions. Reviewers default to praising what’s there; they won’t question what’s absent unless told to.
  5. Specific questions. Numbered, each answerable with file:line.

Two more:

  • Tell it what the main gates already covered, so it skips them. Have it look only at what the gates can’t catch: copy coverage across all languages, state across refreshes, consistency under concurrency.
  • End with a mandatory question: “What didn’t you check? What did you look at but aren’t sure about?” This one targets false negatives. Its answer becomes the next round’s work, and is often worth more than the problems it reported.

One tooling trap: the built-in review subcommand of command-line tools usually reviews only uncommitted changes. If the whole batch is already committed, the working tree is clean, it answers “no changes to review,” and exits normally — yet another failure that looks like success. I switched to a plain one-shot run and pin the comparison range in the prompt, e.g. origin/main...HEAD.

5. After the verdict: verify each finding, don’t read the argument

A review report is also a self-report. How I handle it:

Don’t read its argument; read the code it points to. If it says “file X, line Y has problem Z,” I open those lines and judge for myself. Reading the argument lets the narrative lead you — a self-consistent wrong argument reads more convincingly than a correct but dull fact. That is exactly how hallucinations spread.

The hard test: can it be written as a failing test? If it can become a red test, it’s real, and once written it doubles as a regression guard. If it can’t, it’s most likely a hallucination or just a style opinion.

Three verdicts for every finding:

Verdict Requirement
Confirmed Has repro steps or a red test; goes into the backlog
Rejected Must cite counter-evidence: code lines, test output, the contract text. “I don’t think so” doesn’t count
Uncertain Goes into the backlog, not fixed on the spot. Changing something uncertain is a gamble

Leave a record of rejections. Without one, the next review reports the same thing, you think it’s new, and you verify it all over again.

Don’t fix confirmed findings on the spot during wrap-up. They are new work items and go through the normal flow. Fixing them “while you’re at it” at the end bypasses every gate.

6. Two red flags

  • “The review said it’s fine, so it passes.” — The review report is a self-report too.
  • “It reported three things and I fixed all of them.” — Did you verify each one before fixing? A wrong fix costs more than no fix.

Closing

The value of a second opinion isn’t that the other model is smarter. It’s that it brings a different set of priors.

Using it well takes three things: pick a truly independent reviewer; give it the complement, not an open question; and once it answers, read the code, not the argument. The merge button still belongs to a human. The second opinion helps direct that human’s limited attention to the right places.