Executor Model, Reviewer Model: Why Cross-Vendor Code Review Actually Works

I thought one of my projects was in reasonable shape. I had been working in it for months, it was on version 4.24.3, and Claude had been through most of it more than once. Then I pointed Codex GPT-5.6 Sol at it with Ultra High reasoning, asked it to evaluate the codebase and file issues for anything it found, and it came back with 42 new issues in about ten minutes. Some of them were release blocking. I had Claude Opus 4.8 go through all 42 looking for false positives, and it confirmed zero. Every issue was real.
That result is what convinced me to stop having one vendor's model check its own family's work.
The Setup: One Model Writes, a Different Vendor Reviews
The workflow is simple to state. Implement with one model, working from the most critical issues to the least critical and matching model strength to issue criticality: the highest-confidence model takes the most critical work, and the cheaper, faster models take the routine fixes further down the list. Then validate the pull request with a competing but equivalent model from a different vendor, rather than asking the same model to check its own output. Claude Code's built-in PR review command is the mechanism on that side, which is what made the second half of the loop practical rather than a nice idea.
On the round that produced the 42 issues, the executor was Codex 5.6 Terra/Sol and the reviewer was Claude Opus 4.8.
What It Actually Found
"Some were release blocking" is easy to say and hard to believe without examples, so here are three of them. The project is Zone 2 Trainer, my Android heart-rate training app.
The first is a silent data-corruption bug. The History screen loads workouts through a query that only populates part of each row for performance, and then the edit and relink paths hand those same partial objects to a full-row database update. Anything the summary query left out gets written back as a default or a null. Health Connect identity, GPS, intervals, RR data, cycling power and cadence were all in range. Nothing crashes. You just quietly lose columns.
The second is in the same family. Import and manual-entry paths were using Room's REPLACE conflict strategy against an existing workout ID. SQLite implements replace as delete plus insert, so with foreign keys turned on it can cascade-delete the heart-rate samples belonging to that workout before the replacement row lands.
The third was in Bluetooth scanning: a new caller could attach to an already-running scan and complete unexpectedly, scan failures never came back through the normal result path, and one code path read a device address after the Bluetooth permission could have been revoked.
None of these are style nits, and none would show up as a failing test.
What I found convincing was not just the list but the specificity. Each issue came with file-and-line evidence, a statement of expected behavior, and the commands to prove it. That is what made them cheap to act on: the fixes for all three landed in git over the following two days.
Why This Was Not Getting Caught
The obvious question is why none of this surfaced earlier, given how much model attention the code had already had.
I think it is structural. A model reviewing output from the same family shares the training data, the architectural instincts, and the blind spots. If a model does not think to check for a class of bug when it writes code, it tends not to think to check for it when it reviews code, because it is applying the same judgment both times. The review adds a second pass, not a second perspective. Claude had been through this codebase repeatedly and had not flagged the partial-row update problem once.
Codex Sol does not share that lineage, and the gap between the two vendors' failure modes is where the missed issues were sitting.
I should be honest about the flip side, because I have written about it before. Pointing an unfamiliar model at your code does not automatically produce good findings. When I ran GLM 5.2 findings through Claude a few weeks earlier, roughly 40% were not real problems. Same cross-vendor shape, very different result. Which is the whole reason the next step is not optional.
The Validation Step Is What Makes the Number Trustworthy
Forty-two issues from a model I had not used this way before is not automatically good news. A model that is simply more aggressive about flagging things produces a long list too, and a long list of false positives is noise with extra steps. Given the 40% I had just seen from GLM, I had no reason to assume this list was better.
So the number that matters here is not 42. It is zero. Opus 4.8 went through the issues looking for false positives and did not find any, and that is what turned a pile of flagged issues into a list I could work through with confidence.
Fable would have been my first choice for that validation pass, but it was unavailable, having hit its weekly limit. Opus 4.8 did the job instead, and did it well enough that the result held up.
Where This Is Headed
The plan was always to flip the roles: let Claude implement and Codex review the next round, so the review is never coming from the same vendor that wrote the code twice running. That round has not happened yet as of this writing, so I have no results to report on it, only that it is the obvious next step and the point of treating this as a loop rather than a one-time audit.
The workflow has also kept evolving past the two-model version. Fable and Sol are now doing reasoning and planning, with Terra and Opus handling implementation from the higher-reasoning models' comments, which pushes the same cross-vendor principle earlier in the process instead of confining it to the review stage.
What I Would Tell Someone Setting This Up
- Do not trust a model to review its own family's output. The shared training is exactly what produces the shared blind spots.
- Route the review through something durable, like GitHub issues or a pull request, so the findings are a reviewable artifact instead of a conversation that evaporates.
- Validate the reviewer's findings before acting on them, especially the first time you use a new model this way. A long issue list is worth nothing until you know its false positive rate, and 0% and 40% both happened to me inside a month.
- Demand file-and-line evidence in the findings. It is what separates an issue you can act on from an opinion you have to go verify yourself.
- Match model strength to issue criticality when implementing the fixes. The most expensive model you have does not need to touch every line.
- Plan to flip executor and reviewer roles. A model that only ever reviews and never writes will not show you where its own review blind spots are.
The pair of numbers I keep coming back to is 42 and zero: forty-two issues that months of same-vendor attention had not surfaced, and zero of them noise once a different vendor's model checked the work. That gap is the case for cross-vendor review, and it was wider than I expected.
Comments