Test-driven development spent twenty years being argued about as a discipline question - whether writing the test first genuinely produced better design, or whether disciplined developers would have got there anyway. That argument is now mostly irrelevant, because the economics changed. When a large share of code is generated rather than typed, the test suite stops being a quality practice and becomes the specification.
The old cost model made writing the test first a real trade-off. Producing code was slow, so producing it twice - once as a test, once as an implementation - was a meaningful tax, and reasonable people disagreed about whether it paid back.
Generated code inverts that. Implementation is now cheap and fast. What is not cheap is knowing whether it is right. Generated code is fluent, idiomatic and confident regardless of correctness, which removes the weak signal experienced reviewers used to rely on: code that looks wrong usually was wrong.
Reviewing code you did not write, that looks exactly like code you would have written, is a fundamentally harder job than reviewing code that looks rushed.
The test suite is the only mechanism that does not care how plausible something looks.
This is no longer a prediction. Industry telemetry through 2026 shows the same shape from several independent directions.
That last finding is the whole problem in one line. The code most likely to contain a defect is the code most likely to be waved through, because it reads well.
Higher adoption correlates with higher throughput and higher instability at the same time. The time saved generating is being re-spent auditing, and in teams without a strong verification loop it is being re-spent later, by someone else, on an incident.
Practically, the workflow that works is the one TDD always described, for a different reason.
You write the test - or you write the behaviour precisely enough that a test can be written from it - and that becomes the specification the implementation is judged against. Not a description of intent in a ticket, which is ambiguous, but an executable statement of what must be true.
This is the difference between "add rate limiting to the login endpoint", which can be satisfied a dozen ways with a dozen different edge-case behaviours, and a test that asserts the sixth attempt within a minute returns 429 and the counter resets on success. The second one cannot be satisfied incorrectly while appearing satisfied.
The BDD framing matters more than it used to, and for a new reason.
Tests coupled to implementation - asserting a particular method was called, mocking internals, checking structure rather than outcome - were always brittle. Now they are worse than brittle: they constrain the implementation to a shape you happened to imagine, which discards most of the value of generating it in the first place, and they pass while the behaviour is wrong.
Tests written at the level of observable behaviour - given this state, when this happens, this is true - leave the implementation free and still catch the failure. That was good advice before. It is now the difference between a suite that verifies and a suite that merely agrees with itself.
A slow suite used to be an annoyance. It is now a correctness issue, because the loop only works if it can run constantly.
If verifying a change takes twenty minutes, nobody verifies intermediate steps. Work accumulates unverified, and the failure - when it arrives - is somewhere inside a large batch of changes rather than attributable to one of them. The whole benefit of fast generation is lost to slow verification.
This is why the mechanical things matter more than they did: deterministic data rather than per-test construction, parallel execution, no retried flakes, and layers you can run independently so a focused change runs a focused suite. Speed is what makes the loop tight enough to catch errors while they are still small.
An untested path used to mean risk you had accepted. Now it means a path where nothing at all is checking the generated implementation - no test, and a reviewer whose main heuristic has been neutralised by fluent output.
Which is why per-layer enforcement is worth the friction. An aggregate number lets a well-tested model layer hide an untested controller. In a workflow where code arrives faster than review capacity, that gap is where the defects live.
Codebases with strong test discipline get faster with generated code, because the verification loop already exists and the constraint was always implementation speed.
Codebases without it get faster at producing unverified change, which feels like acceleration for roughly a quarter.
The gap between those two outcomes is widening, and it is not a question of tooling or of which model you use. It is whether the suite can tell you the answer is wrong.
We build to this standard and we retrofit it into codebases that need it. If your team is generating more code than it can confidently review, the suite is usually the bottleneck.