← all posts

Verification Is the New Bottleneck

When code is free, checking it is the job.

AI made code generation cheap.

It did not make verification cheap.

That gap is the bottleneck, and most teams haven't noticed it yet.

The old bottleneck was production. The new one is verification.

AI changed the bottleneck. The old constraint was producing code: typing it, wiring it, translating intent into syntax. AI compressed that. What used to take a week now takes an afternoon.

But the bottleneck didn't disappear. It moved to the thing that was always there but was never the constraint: checking whether the code is right.

Verification used to be proportional to production. You wrote a function, you tested it. You wrote a service, you ran it locally. The ratio was roughly one to one: one hour of checking per hour of writing. The process was slow, but balanced enough because production was the ceiling.

AI broke that ratio. Production is now nearly free. Verification is still expensive because verification requires understanding, and understanding is the thing AI does not provide.

The model can generate a thousand lines in seconds. Checking those thousand lines for correctness, fit, and failure modes takes exactly as long as it always did. Maybe longer, because the code is unfamiliar and the volume is higher.

The ratio inverted. You're now spending five hours verifying for every hour of production. The bottleneck didn't move. It concentrated.

The verification layer is where the bugs moved

The most expensive bugs never reach production. They're decisions. AI didn't change that. It made it worse.

When a human writes code, the decision and the implementation are coupled. The human decides to use a certain approach, then types it. If the decision is wrong, the implementation is wrong, but at least the same person made both mistakes. You can catch the decision by reviewing the code, because the code is a trace of the decision.

When AI writes code, the decision and the implementation are decoupled. The human writes a prompt. The model makes hundreds of micro-decisions in producing the code. The human reviews the code, but the code does not show the decisions. It shows the output.

The decisions are invisible. They are encoded in the implementation, but they are not traceable.

You can't prove the bug isn't there becomes more important when the code is generated to look correct. The old verification model assumed inspection would expose many of the mistakes. AI output often passes that first read. The mistakes are more likely to live in assumptions: consistency, failure handling, concurrency, ownership.

What verification actually means now

Verification is no longer "does the code work." It's three separate questions, and conflating them is the mistake.

Does it do what was asked? This is the easy one. Run it. Write a test. The model can even help. This is the layer most teams focus on because it feels concrete and it got easier.

Does it do what should have been asked? This is harder. The prompt specified a feature. The code implements the feature. But the feature might still be wrong, or the prompt might encode the wrong assumptions. The review moved up the stack because the review has to include the decision the code encodes.

What does it do that wasn't asked? This is the hardest. AI-generated code carries assumptions the prompt did not specify. Error handling patterns. Concurrency models. Consistency assumptions. These choices can look reasonable in isolation while conflicting with the real system. You find them by knowing what the system assumes and checking whether the code agrees.

The third question is the bottleneck. It requires context the code does not contain. It requires the senior engineer's compressed experience: the pattern recognition that catches a caching assumption before load turns it into an incident.

The verification tooling gap

The tooling hasn't caught up. We have linters, type checkers, test runners. All of them verify the first question: does it do what was asked. None of them verify the second or third.

Verification tooling for the AI era needs to make hidden decisions visible. It should help surface what the code does, what assumptions it encodes, which consistency model it assumes, and which failure modes it handles.

It also needs to test assumptions against real system conditions. Does the code handle the message ordering the broker guarantees? Does it survive the partition the network will eventually have? Does it do work the spec did not ask for? That is the layer current tooling barely touches.

None of this exists in a mature form. The teams building it will have an advantage because they will be the ones who can safely use AI-generated code at volume.

The teams that do not will hit the verification wall: unlimited production capacity, bottlenecked by a verification layer that was not designed for this volume.

The bottleneck moves to the work that still requires context. Tests help. Static analysis helps. Better prompts help. The scarce part is still knowing what the system actually needs and checking the generated work against that reality.

The one-line version

AI makes code cheaper, so engineering time shifts toward checking assumptions against reality.