Two separate models — one writing the code, one reviewing the diff — shipped a one-word bug to staging. Both ran local checks. Both came back green. The fix they missed was not exotic or subtle. It was written down, in plain English, in a file sitting in the same directory as the change.
That last detail is the one worth staying with. This is not a story about a model being wrong. Both models were, within the job they were given, correct. It is a story about where verification stops looking — and why stacking two reviewers that stop looking in the same place feels like safety and isn't.
What broke
While fixing a cron timeout, I had Claude Opus pull a small JSON-parsing helper into its own file so it could be unit-tested in isolation. Reasonable instinct. It named the file jsonExtract.mjs and imported it from autoPublish.js:
import { _firstJsonObject } from './jsonExtract.mjs'; // looks perfectly legal
The whole incident lives in that one letter — the m.
autoPublish.js is an ES module. On my machine, Node happily lets one ESM file import a .mjs file, so every local check passed. The deployed runtime took a different path:
Local: ESM importer → .mjs ES module → works
Deployed: CommonJS require() → .mjs ES module → ERR_REQUIRE_ESM
I want to be precise about what I actually know here, because it matters. I did not instrument Vercel's build. What I observed is that the deployed function reached the helper through a CommonJS require(), while local Node exercised a compatible ESM path. Whatever transformation produced that, the consequence is fixed by the language spec: a .mjs extension forces a file to be an ES module, and require() of an ES module is barred. The result was an invocation-time crash:
Error [ERR_REQUIRE_ESM]: require() of ES Module
/var/task/.../jsonExtract.mjs
from /var/task/.../autoPublish.js not supported.
Not a syntax error. Not a logic error. A packaging error that only becomes real once your platform rewrites the module system underneath your repository.
The seam nobody owned
Every check you run has a scope, and a green result only ever means "clean within that scope." We forget this because green is rendered the same color regardless of how much it actually covered.
Walk the checks that ran on this change and read them as scopes rather than as pass/fail:
node --check— scope: syntax. The file parsed. True, and useless here.
The test suite — scope: the code paths the tests exercise, in the local runtime. All green. Also true; the tests never invoked the module across the deploy boundary.
The AI review — scope: logic correctness, as framed by the prompt. Race conditions, variable scoping, whether the extraction logic was sound. All fine. The reviewer was asked "is this logic correct," and it answered that question well.
The deployed runtime — scope: the real module system. The only scope in which this bug exists at all.
The bug did not slip past the checks. It lived in the seam between two of them — the gap between "local ESM resolution" and "deployed CJS resolution" — and no check on the board had that seam inside its scope. ERR_REQUIRE_ESM is an invocation-level error, so the build logs stayed green by definition: nothing executes at build time to trip it.
This is where the "documented one file away" detail turns from irony into the actual lesson. In the same directory sat a sibling helper, cluePrompts.js, carrying a prominent header comment saying it was CommonJS on purpose — written that way specifically to be default-imported from ESM consumers and dodge this exact rewrite. Project docs reinforced the convention. The correct architecture was not unknown. It was passive — encoded as prose, and prose is outside every automated scope above. A human skimming the diff wouldn't see it unless they already knew to look. Neither would a model. The knowledge existed and propagated to no one.
Why two reviews is not two reviews
Here is the trap that made me write this up, because it's the part that generalizes past Node and Vercel.
Two independent green stamps — one from the author model, one from a separate reviewer model running the tests itself — feels like defense in depth. It reads like redundancy. It is not. Redundancy only buys you coverage when the reviewers fail independently. These two shared a scope: both were evaluating logic correctness in the local runtime. When two checks share a scope, they share a blind spot, and stacking them multiplies your confidence without moving your coverage an inch.
That is the quiet danger of multi-model pipelines. Adding a second model that thinks about the code the same way the first one did doesn't widen the net; it just gets you a more confident wrong answer. Real defense in depth requires checks whose scopes are uncorrelated — one that reads a completely different signal than the others.
The one check with a different scope
I run a deterministic local hook while I build, and EraPin. This one was caught the instant the cron executed on Vercel staging, and fixed forward within the hour.
SOCIAL SHARE CARD GENERATOR