AI Is Writing All the Code. Who's Reviewing It? (Please Don't Say Another AI) A developer warns that AI-generated code is outpacing human review, leading to a 'review bottleneck' where code is merged without being understood. Citing industry data showing 20-75% of code at major companies is AI-generated, the developer argues that while AI review tools help, they fail to catch semantic errors that require understanding the real-world context, such as a retry loop that double-charged 1,100 customers. The post calls for a shift from 'human in the loop' to 'human understands the loop'. At 2:47 AM, a payment service starts retrying charges. Not because someone wrote a bug. Because someone wrote a retry loop , and the retry loop was correct in every way a code reviewer checks: it had backoff, it had a max attempt count, it had a context timeout, it had a nice comment explaining the exponential backoff strategy. It had test coverage . Two humans approved it in under four minutes with the industry-standard incantation: LGTM 🚀 By 6 AM, 1,100 customers had been charged twice. The AI didn't write a bug. The AI wrote correct-looking code for the wrong world — one where HTTP timeouts mean "nothing happened" instead of "I have no idea what happened." And nobody caught it, because catching it required knowing something that wasn't in the diff. That's the whole essay, really. But let's do it properly. The version of this argument you hear on Twitter is: "nobody writes code anymore, it's all AI, zero human involvement." That's not true, and I want to be honest about the numbers instead of scaring you with a made-up one. Here's what's actually on the record: | Claim | Source | When | |---|---|---| | 20–30% of code in Microsoft's repos is "written by software" | Satya Nadella, LlamaCon | Apr 2025 | | 25% of new code at Google is AI-generated, then engineer-reviewed | Sundar Pichai, earnings call | Late 2024 | | ~75% of new code at Google is AI-generated and engineer-approved | Reported figure | Apr 2026 | | 84% of devs use or plan to use AI tools; ~51% use them daily | Stack Overflow Dev Survey | 2025 | | 95% of all code AI-generated | Kevin Scott's prediction | by 2030 | Notice the load-bearing words in the Google framing: "and approved by engineers." Humans are still in the loop. Which is worse , actually. Because "human in the loop" has quietly stopped meaning "a human understood this" and started meaning "a human was present when this happened." Being present is not the same as reviewing. I have been present at many meetings. Here is the thing that broke: Generating code got roughly 10x cheaper. Reviewing code got 0x cheaper. Reading code is bounded by one resource that has not improved since 1970: a human paying attention for a bounded number of minutes per day. You cannot 10x that. You cannot parallelize it. You cannot hire it away, because the bottleneck isn't headcount, it's comprehension per engineer per hour . So what happens when you 10x the input to a fixed-throughput system? The queue grows, and then the queue gets managed — not by working faster, but by lowering the standard until the queue fits. This isn't a hypothesis. The data has been pointing at it for two years: catch {} , ?? fallback , except: pass up Read that last bullet again. Refactoring didn't slow down a bit. It functionally stopped . From one line in five to one line in twenty-six. That's the signature of a codebase nobody is reading. You cannot refactor what you have not read. You can only append to it. And duplicated blocks aren't a style complaint — cloned code correlates with 15–50% more defects , because every clone is a landmine that only detonates when someone fixes one copy and misses four. So: the code is being written. The code is being merged. The code is not being understood. The review step still exists as a UI element. This is the obvious move, and it's the one the industry made. CodeRabbit, Bugbot, Copilot review, claude review , agent-on-agent PR bots. The pitch writes itself: AI generates faster than humans can review, so use AI to review. And I want to be fair here, because AI review is genuinely good at a real class of problems : snake case here and camelCase there If your baseline is "no review," AI review is a massive upgrade. Use it. Genuinely. But it fails at exactly the class of problem that causes incidents, and it fails for four structural reasons. The reviewer and the author were trained on overlapping data, share a similar prior about what "good code" looks like, and often are literally the same model family . When your author and your reviewer draw from the same distribution, the reviewer doesn't catch the author's mistakes — it agrees with them , confidently, in well-formatted markdown. Two humans disagreeing is a feature of code review. Two instances of the same model agreeing is not review. It's an echo with a checkmark. Logic behind the fix: if you're going to use AI review, use a different model than the one that wrote it. Decorrelate the errors. It's the same reason you don't have the author approve their own PR. A reviewer bot sees a diff. Incidents live in the space between files: an invariant held in a different service, a lock ordering established in a module nobody touched, a queue that's at-least-once, a downstream system that doesn't do idempotency. The 2:47 AM retry loop was flawless within the diff . The bug lived in a sentence in a payment provider's docs. Models are tuned to be helpful and pleasant. Ask one "is this code good?" and you are, statistically, asking it to say yes with reasons. Ask it "find three ways this breaks in production" and you get a different, much better answer — same model, same diff. You are not querying a truth oracle. You are sampling from a distribution conditioned on your prompt. Prompt for the failure, not for the verdict. This is the deep one. A probabilistic generator feeding a probabilistic reviewer is a pipeline with no deterministic quality gate anywhere in it . Stacking a second stochastic layer on a stochastic layer doesn't give you certainty; it gives you two opinions and a false sense of process. The only things in your pipeline that cannot be sweet-talked are: the type checker, the test suite, the linter, the race detector, the migration checker, the fuzzer, and production. Those are your ground truth. Everything else is a vibe. Enough theory. Here's what this looks like in a PR. Every one of these is a pattern I've seen ship, in a shape an agent will happily produce, and every one gets approved by a reviewer — human or bot — who is reading the diff instead of the system. func c Client ChargeCard ctx context.Context, req ChargeRequest Charge, error { var lastErr error for attempt := 0; attempt < 3; attempt++ { charge, err := c.post ctx, "/v1/charges", req if err = nil { lastErr = err time.Sleep backoff attempt continue } return charge, nil } return nil, fmt.Errorf "charge failed after 3 attempts: %w", lastErr } Why it looks fine: bounded attempts, exponential backoff, error wrapping, context threaded through. This is textbook. It would pass a Go style review at most companies. Why it's a landmine: a network timeout is not a "no." It's a "don't know." The request may have reached the provider, created the charge, and had the response die on the way back. Retrying is not retrying — it's charging again. Why AI review misses it: the correctness depends on a property of the remote system does /v1/charges deduplicate? which appears nowhere in the diff, nowhere in the repo, and possibly nowhere except a paragraph in a vendor doc. The fix: // Idempotency key is derived from the logical charge, NOT the attempt — // all 3 attempts must carry the same key so the provider dedupes them. req.IdempotencyKey = idempotencyKeyFor order.ID, order.Version for attempt := 0; attempt < 3; attempt++ { charge, err := c.post ctx, "/v1/charges", req if err == nil { return charge, nil } // Only retry errors we KNOW left no side effect. if errors.Is err, ErrConnRefused && errors.Is err, ErrDNS { return nil, err // timeouts included: outcome unknown, do not retry blind } lastErr = err time.Sleep backoff attempt } What actually catches it: a checklist rule — "any retry on a mutating call requires an idempotency key or an explicit comment justifying why not." Deterministic. Greppable. Not a judgment call. js // Before const orders = await db.order.findMany { where: { buyerId }, include: { lines: true }, } ; // After — "cleaner separation of concerns", said the agent const orders = await db.order.findMany { where: { buyerId } } ; const ordersWithLines = await Promise.all orders.map async order = { ...order, lines: await db.orderLine.findMany { where: { orderId: order.id } } , } ; Why it looks fine: it's more explicit, it's not doing magic ORM joins, and Promise.all makes it look concurrent and fast. Genuinely reads nicer. Why it's a landmine: one query became 1 + N . On your seed data, N is 5. On your biggest buyer, N is 4,000, and Promise.all fires all 4,000 at once, drains the connection pool, and takes down every other request on the box. The refactor is now a self-inflicted DDoS with good variable names. Why AI review misses it: N+1 is invisible without knowing the cardinality of your data. The diff contains no numbers. The model has no idea if orders has 3 rows or 3 million. What actually catches it: a test that asserts query count, not a reviewer's intuition. js test "buyer order list stays O 1 in queries", async = { await seedOrders { buyerId: "b1", count: 50 } ; const { queryCount } = await withQueryCounter = getBuyerOrders "b1" ; expect queryCount .toBeLessThanOrEqual 2 ; // fails loudly at 51 } ; Note what happened: I converted "a senior engineer must notice this" into "CI is red." That's the whole game. Future