Keep the defect rate falling as throughput rises.
Every system fails in some way, under some condition. The question isn't how to reach zero defects. It's how to keep the defect rate flat, or falling, while throughput goes up. Going slow isn't the safe option: it's the other way to lose.
There are no flaky tests isn't a preference we balance against speed. Every loop climbs on its checks, so a check that lies breaks everything built on it.
But a perfect signal doesn't mean a perfect product. Tests only check the conditions someone thought of. The product will still fail under some conditions nobody has tested yet. Where we look for those failures, how hard, and how early: those are the trade-offs.
We had bugs. Every team, every decade, with careful engineers reading every line and approving every PR.
So the comparison isn't “agents vs. perfection”. It's agents vs. a process that already had a defect rate, and a throughput capped by how fast humans can read.
Human review catches real things. It just doesn't scale, and it was never a guarantee.
At ten times the changes, ten times the absolute defects at the same rate is the honest starting point. The goal is to keep defects per change flat, and ideally make it fall.
What you can't do is reach that goal with a method that limits velocity. A human approval gate holds the rate by capping throughput, so the extra agent capacity just turns into a queue.
Illustrative model, not measured data.
A human reading a diff checks one change, once, slowly. A type system or an architecture rule checks every change, every time, in seconds, and the agent learns about the failure before it has finished the task.
Encode the reasoning once as structure: types that make illegal states unrepresentable, module boundaries enforced in the build, rules that enforce themselves. A whole class of defect stops being something anyone has to notice.
Types and rules remove whole classes of defect, but not all of them. Behaviour that only appears when components meet, under load, across versions or after a restart is invisible to the compiler.
So we scaffold defense in depth: unit tests, integration tests and scenario tests on top of the types and rules, each catching what the layers before it let through. No single layer has to be perfect. The stack does.
Illustrative catch rates.
Integration and scenario tests aren't there to re-check the code line by line. Their job is to find the conditions the product breaks under, deliberately, before a user does.
Agents make these suites cheap to build and to grow. That's where the extra capacity should go: not into more code that nobody tests, but into more ways of trying to break it.
A scenario test that finds a failure has done half its job. The other half is asking: what's the earliest, fastest layer that could have caught this class of defect? Then move it there.
Over time, defect classes migrate inward: from production to scenario tests, from scenario tests to unit tests, from tests into the type system. The outer layers keep exploring new failure conditions, and the inner loops get faster and stricter. That's how the rate goes down while throughput goes up. (More on this in Agentic Loop Engineering.)
Human speed was never defect-free, and it can't scale. Keep the signal honest, move reasoning to compiler speed, stack integration and scenario tests to expose the conditions the product fails under, and feed every finding back into the inner loops. Then throughput goes up and the defect rate goes down.