Reading all AI-generated code is theater

It's 16:50. The agent has finished the ticket, and the diff is 1,400 lines long. You open it and start at the top, because that's what a responsible engineer does.

By line 400 you're skimming like it's a terms-and-conditions page. By line 900 you're looking for anything that smells wrong. At line 1,400 you approve. You feel like you checked something, and you can't say what.

Teams that can't stop reading agent-written code mostly have an architecture problem. Verifiability is an architecture property, and whatever can't be checked at a block's edge ends up being read.

That's a different diagnosis from the two you usually hear. One camp says to read everything, because the agent can't be trusted. The other says to stop reading and trust the tests. Both treat the urge to read as a question of discipline. I think it's a measurement. How much you read tells you how much of your system has no edge you can check from outside.

Reading every line is the feeling of control, not control

The numbers behind the pile-up are public, if you take them with a grain of salt. Octopus Deploy's "Code review is theater now" cites the 2026 DORA report: 90% of developers use AI tools, and they merge 98% more pull requests. Bugs per developer rose 54%. Faros AI, looking at more than 10,000 developers, reports incidents per pull request up 242.7%. Octopus's own survey found that AI cut task hours at every stage of the delivery pipeline except code review.

Octopus sells deployment software, and the bug figure comes without a named source. Read the numbers as direction, not measurement. Output went up a lot. Reviewer attention didn't.

So the review gets thinner. I'd bet a reviewer with 1,400 lines of plausible code and ten minutes checks what is cheap to check: naming, structure, the obvious. Whether replaying the same event twice corrupts a balance is not on that list, because nothing in the diff points at it.

That's why I call it theater: the reading happens, the approval happens, and the control doesn't.

Verification replaces reading, but only for what you can check from outside

The alternative isn't trust. Stuart Jeff, who wrote about how he stopped reading his agent's code, describes it as layers arranged so no single one has to be right. His project has 2,640 tests and 88.1% line coverage, enforced in CI. In the project he describes, the primary session read 16 of 487 source files before they were committed (3.3%), and he notes that the figure measures attention, not quality.

Which 16 matters. Smoke tests, configs, the architecture doc, a few helpers, some test harnesses. He did not read the 439-line auth plugin or the secret-scan workflow. Security-critical code shipped unread. He says so himself, and he adds that the test and CI infrastructure was also written by the AI. He doesn't know yet whether his checks catch what a human reader would have caught.

I find that honest, and it shows where the idea has limits. A check can replace reading when it meets three conditions, which the pattern write-up "Oracle-Gated Delegation" lays out. The check must be decisive: passing it confirms the property you care about, not a stand-in. It must run independently of the agent that produced the code, because a verifier the agent can edit is not evidence. And it must cost far less than producing the code.

When one condition fails, the expertise requirement doesn't disappear. It moves to the end of the job, where it costs more. In practice, that means a human reads the diff at 16:50.

Each condition has a different owner. Independence is a process rule: the agent must not write or edit the check that judges its own work. Decisiveness and cost depend on the shape of the code, and the shape is something you design.

Same requirement, two architectures: only one can be checked

Here is a constructed example, not a war story. A ledger service. Bookings can be corrected retroactively, so a change dated last Tuesday has to land in the right place in the history. The balance view must reflect any accepted change within 2 seconds.

Version one is the shape you get when nobody decides the structure up front. One module takes the change, writes it to the bookings table, recalculates the balance inline, updates a cache, and shares state with two other handlers. It works. The tests pass.

Now ask the question a reviewer should ask: what happens if the same change arrives twice? In version one, the answer lives somewhere in those 1,400 lines. You can test it end to end, but you have to know to ask, and the test needs a full system to run. Or you read.

Version two splits the same requirement into two blocks and one agreement between them. The write block accepts changes and emits a change list. The projection block consumes that list and builds the balance. The agreement at the seam fits in a sentence: every change carries an ID, and applying the same change twice leaves the change list unchanged.

Now each block has an edge. You feed the write block commands and check the list that comes out. You feed the projection block a change list, twice, in shuffled order, and check the balance. Nobody has to open either implementation to know whether the seam holds.

Same requirement, same agent. On the left the replay question can only be answered by reading. On the right it is a test at the seam, and a failing test names the block that broke it.

What makes a block checkable from outside

None of this is new. Parnas described information hiding in 1972, and "build testable architectures" is advice older than most of your team. I wouldn't write a post about it.

What changed is the price of ignoring it. Before agents, a hard-to-test module cost you tests. Now it costs you reading, because the reading is what you fall back on when the check isn't available, and the agent produces far more to read than you ever wrote yourself.

I look for three properties, and the example above has all of them:

  • The interface is small enough to write down. If the contract needs a page, the block is two blocks.
  • State is visible at the edge. A block that keeps decisions in private fields gives a test nothing to observe.
  • The agreement between blocks is a sentence you can turn into a test. "Applying the same change twice leaves the list unchanged" is one. "The modules should work together well" is not.

Go back to the oracle conditions. Two of them are decisions about architecture, taken before the agent writes a line. A check is only cheap if you can run the block without the rest of the system. It only decides the property you care about if that property shows up at the edge. The third, independence, is a process rule, and architecture can't give you that one. A committed spec can, and I come back to it at the end.

The urge to read, in this light, is information. It points at the block where cost or decisiveness fails.

What you still read

Verifiability doesn't end reading. It tells you where to spend it.

You read the seams: the contract sentences and the tests that pin them. You read the places where no oracle exists, because there the expertise requirement is back and you pay it either now or later. You read anything where a failure is expensive and a gap in the tests is likely. Jeff's unread auth plugin is the case study for what happens when you skip that last one.

Sometimes the urge to read is plain good judgment. Osmani and threedots.tech argue that AI-written code needs full review, and where no oracle exists they are right. I disagree with the blanket version: it spends scarce attention on blocks a check could have covered.

A score isn't proof either. One 2026 replication study of LLM-generated test suites found that coverage and mutation score correlate only weakly with real fault detection within a single model (the coverage coefficients mostly sit below 0.2). Across 13 model settings the correlation was strong, which may say more about which model wrote the suite than about the suite in front of you. The study covers Java only, 318 methods and one prompt workflow, so it proves little in either direction. I read it as a warning label: don't put a coverage number on a dashboard and call it trust.

Black-box testing from a stated contract is an established method. The evidence that it works at agent volume is thin. That's one more reason the reading budget goes to edges and contracts, and not to interiors.

Tests only confirm what someone decided first

You'd think the tests create the confidence, but a test only confirms a decision. If nobody made the decision, the test confirms whatever the agent guessed.

Give an agent a vague story and ask it for tests. It writes tests that match the code it just wrote. They pass, and they say nothing about the question nobody asked: what should happen when the same change arrives twice, or when the correction lands in the middle of last month?

The decisions come first and get committed: scenarios for behavior, invariants for the seams, numbers for the non-functional requirements ("95th percentile under 300 ms" instead of "fast"). The tests derive from those. Only then does the agent build.

Writing those decisions down is the hard part, and it doesn't need a specific tool. A Markdown file in the repo works. So does a ticket template in Linear or Notion, or an interview in ChatPRD or Speclr. What matters is that the answers exist before the agent starts, in a form a test can be derived from. The full walkthrough shows how that looks for the ledger example, step by step.

How much your team reads is a design decision. Make it on purpose, before the agent starts, or it gets made for you in every diff.

Start your next refinement as an interview in Speclr.

Tags

ai-coding-agentsai-code-reviewcode-reviewsoftware-architectureverifiabilityblack-box-testingspec-driven-development