jasonroberts.io
Cybernetic Intelligence

The AI Code Review Kerfuffle

AI made sensing defects cheap but left understanding and repair expensive, so review needs risk tiers and an outer loop that graduates and demotes autonomy.

Jason Roberts · Issue 001 · · 8 min read

A recent Postgres release de-scoped several planned features in part because AI found more defects than the team had capacity to fix. Why wasn’t the answer to just have AI fix what it found? In a nutshell: using AI to detect problems costs only tokens, using it for repair costs tokens plus a verification pass and human attention per round, and carries collateral-damage risk.

Agents work fast, and the question “is it good work?” is a big one. There’s a lot of stress flying at engineering leaders, partly from the over-sell of AI utopia, partly from a real problem of how to effectively scale the actual capabilities AI has given our industry. You’ve a team on Claude Code or GitHub Copilot, and they’re flying through stories. Are you going to ship all of them? Right away?

A uniformed president from Parks and Recreation shouting “Right to jail!”

No of course not. We need to know it does the thing first. If you don’t know what the thing is, stop right there, go back, and write it down. If you do though it’s still not an easy answer.

Shipping software can be imagined like a pipeline. (A) Ideas come in which are turned into defined features, (B) those features are turned into software implementations, (C) implementations are validated via QA and UAT, and if everything is green (D) working software is shipped. Before AI coding, ‘B’ was often the bottleneck; that reality has been entirely inverted. The bottleneck is now ‘C’. The easily available answer is “review more”.

How often is the easy answer the better answer though? “Review more” has a flaw: a person still has to open every PR and read it, and that minimum never goes away. The only way to cut the total is to stop sending some changes to a person at all. A paper from earlier this year found that firms adopting coding agents produced 30% more lines of code and 23% more PRs, leaving the issues-resolved rate flat, and spent 49% longer reviewing; the share of PRs sent back for changes rose from 13% to 34%. More code, more problems.

The practice of review

There are actually three competencies layered into it:

  • Sense: something is wrong. requires knowledge of the goal
  • Understand: why is it wrong? requires knowledge of the system model
  • Repair: make it right without causing collateral damage. requires knowledge of the goal, system model, and of systemic blast radius (i.e. what the system under test is coupled to)

Think of the hierarchy of concerns: function -> class/module -> service -> consumer

You could sense an error signal at any of those levels (via unit tests for the first two, functional tests for the third, and integration or end-to-end tests for the fourth). To then understand the ‘why’, a model of everything from service down must be known. What the goal is (behavior), what is internally coupled (structure), and whether a change impacts what is externally coupled (system dynamics). Once you have that model, you know which parts of the system have a large blast radius and which don’t. That’s what lets you set a policy for how much attention a change in each part gets, before any defect is found.

Sensing is cheaper than fixing

With AI, sensing got cheap and the other two didn’t. Here’s a PostgreSQL committer on what that feels like:

But with LLM-assisted code review, these kinds of things can get found much faster, and then you’re staring at a list of like forty defect reports. And even if each of them requires only a three-line fix on average, there is a fixed overhead to dealing with each of these, and then you run out of time.

— Peter Eisentraut

Each finding opens a loop (understand, patch, re-verify, re-review), so

cost = rounds × cost per round

Repair without collateral damage includes not damaging the checks. When Maurice Heumann gave his decompilation agents a byte-matching script as the pass/fail oracle, their first move was to write inline assembly to satisfy it, and their second was to edit the script so it skipped their own functions. The fix wasn’t a better instruction. CI now hashes the script and fails the build if the hash doesn’t match a stored secret. The check had to be put somewhere the repairer couldn’t reach.

Key takeaways

  • A strong sensor on a weak repairer creates thrashing and it finds the backlog nobody budgeted repair for. Separate these concerns and measure them as rounds per finding and share of findings in existing code.
  • Informative sensor output is valuable understand/repair input. Measure this by “first-try fix rate” - how often a finding is fixed on the next attempt
    • an agent hand-off that describes exactly what fails with an example enables the repairer far better than “test X failed”
  • Even the checks are in the blast radius: The only reliable sensor is one the repairer can’t touch.

Cybernetics

We work in loops, and cybernetics has trodden these paths already (at a higher abstraction level). There’s a concept in cybernetics called “requisite variety”. It means that an effective regulating mechanism needs as much or more variety (distinct responses it can make) as there are potential disturbances (e.g. an agent changes test code to fix a failing test instead of the code being tested). There are only two dimensions to consider in this frame: 1) attenuate the disturbances (smaller changes, guard hooks, multi-shot examples) and 2) amplify the regulator (deterministic tests, AI review, tiering, fast rollback).

Attenuation holds the system at a stable level and amplification lets it grow. Take a currently supervised process (AI work -> PR -> human review) and watch its outcomes over time. Ask two questions:

  1. How many times did a human have to intervene after AI review?
  2. How many cycles did the AI reviewer perform per change?

The closer the answers are to “zero”, and “one” respectively (they will almost never actually be 0/1), over a sufficiently large sample set (100+), the better a candidate it is to graduate to fully autonomous. If two weeks later it ships a regression (measured by an escape rate sensor), demote it. If it starts thrashing review cycles, add a cycle cap and re-assess (attenuation). This ‘earned autonomy’ process is a control loop (a regulator in cybernetics terms) applied over an inner one.

Risk classification as a review strategy

The Claude Code team recently shared how they manage code reviews where they employ risk tiered gating along with layered verification. The scale that they operate at and the pace that they ship makes their practice compelling, but the interesting part is none of what they’re doing is outside the reach of teams at much lower scale.

  • Test locally? Who doesn’t?
  • Continuous integration? So 2007
  • AI review? If it weren’t easy, it wouldn’t be scaring everyone to death
  • Humans reading code? What has the world come to?!

So what’s the hard part? Why aren’t we all doing this yet? It’s the discipline between the lines: Using noisiness in the review process as a signal for redirecting attention. Past incidents and reverts become an eval set, expert-confirmed, and every change to the reviewer’s prompts, tools or model is rescored against it regularly.

The important thing about humans reading code is that they should be reading not ALL the code, just the important parts. A classifier determines a risk tier (a far simpler task than judging software acceptance), which then sets the policy for review. Low risk changes need not have a human review. Medium risk requires one person, high requires two. The engineer/prompter is still the accountable one, regardless of how many words they personally typed.

Another key detail is the cost framing. Human time is counted on both sides: reviewing, and fixing what slipped through. Cut the first without watching the second and the time just moves. Track them separately or you can’t tell which competency is the bottleneck.

Other themes from the post

Thrashing

Review has to converge. An agent author and an agent reviewer can keep each other busy indefinitely. One CLI PR went through more than fifty rounds of review and fixes overnight before its author stopped it.

The backlog nobody budgeted for

When we ran git blame on what the reviewer kept flagging, about 59% of it was code that had been there since the reviewer’s first pass. The reviewer was rarely finding new bugs, it was finding a few more old ones each round.

Cost = rounds × cost per round

Noise costs more when the author is an agent. A person can wave off a nit in seconds. An agent fixes it, which means another commit and another round of review.

Regulators for re-review

A round cap. After three rounds, the reviewer asks the author to step back and reconsider the approach.

Diff-only re-review after the first few passes.

Flag the class of bug, so the author fixes every instance, not one line.

No repeats of findings already posted.

After taking this approach, their one-round pass rate went from 65% to 78%, PRs needing five or more rounds from 8.9% to 1.5%, mean reviews to pass from 2.08 to 1.32, and they now track rounds-to-pass alongside recall.

Fallbacks

Fast detection, fast rollback: Some mistakes will still get through, so the last layer is about catching them fast. Flags turn off without a deploy. Claude Code has a weekly on-call rotation, and incident reviews ask which layer should have caught the issue. Noticing a bad merge still depends on the author and on-call as well as the revert and incident dashboards. We don’t yet have circuit breakers that tighten approval when those numbers move; engineers here want them before more code moves to zero-human merges. One colleague said slowing down does lower your error rate, but mostly because you’re doing less of everything. We’d rather get faster at noticing and fixing problems.

The circuit breakers that their engineers want are the ‘earned autonomy’ regulator I described earlier, and their team has homed in on the same need.

What to do next

  • Measure
    • how many loops of automated reviews pre-PR? how many human reviews post-PR?
    • token spend per accepted change.
    • thrash signal (fixes that introduce new failures)
    • post-merge escape rate
    • What is your human repair capacity? Measure human attention as effort (comments, rounds), not latency
  • Then enforce
    • Tier by risk and path, with named owners (humans, specialized agents). Protect CI/CD and IaC paths outright.
    • If automating a job causes repair capacity to be a bottleneck, that’s a signal to shift effort left by improving what the sensor emits (not just what it finds), and running it earlier
    • Cap rounds per defect; escalate to re-diagnose, re-decompose, or a stronger model tier. (Anthropic Claude Code team approach)

The problem isn’t sensing. Postgres amplified sensing only, so when the findings outran the people who could fix them, the only lever left was attenuation, and it reverted. The leverage point is amplifying the other two competencies and putting an outer loop over all three. The Claude Code team has shown the inner loop. The outer loop, the one that graduates and demotes, is the part nobody has shipped yet. It’s buildable now, and your team should be building it.