Why this matters: none of the books this material comes from were written for a team where most of the code is generated in minutes. The principles still hold, but the bottleneck moved, and if you keep optimising the old bottleneck you will keep getting slower while feeling faster.
The uncomfortable observation
AI did not create our planning problems. It removed the thing that was accidentally hiding them.
Before, if a requirement was vague, it took three weeks to build the wrong thing. Somewhere in those three weeks a developer would hit a case nobody had discussed and come back to ask “what should happen if the invoice is already paid?”. The slowness of typing code was functioning as an unplanned requirements review, and it caught a surprising amount.
Now the code arrives in an afternoon. The vague requirement goes in, plausible working code comes out, and nobody was ever forced to ask the awkward question. The gap did not appear, it was always there. It just used to get filled in by accident.
So the numbers move like this:
Code output ↑↑↑ several times faster
Requirement clarity → unchanged
Test coverage → unchanged, so it falls behind relatively
Review capacity → unchanged, and this is now the real ceiling
Understanding ↓ falling, because the product grows faster than anyone reads it
The scarce resource is no longer code. It is specification, review and understanding. Everything below follows from that one sentence.
Throughput is not delivery
The feeling of “we built inventory management in one week” is real and it is measuring the wrong thing. What actually got produced that week:
- code that handles the cases the prompt happened to mention,
- no written record of what it should do,
- tests that were either not written or generated from the code rather than from the requirement,
- and edge cases that nobody has ever enumerated, not even the person who prompted it.
The feature is not finished, it is generated. Finished is defined in Definition of Done, and the gap between generated and finished is where all the future pain lives. The reason this feels like progress is that the visible part, the code, is the part that got faster, and the invisible parts are the parts that did not.
The specification is now the real work
The practical shift: the valuable engineering activity has moved earlier, into defining precisely what should happen.
This is good news, because that activity has a name and these notes already describe it. It is refinement: writing Acceptance Criteria, enumerating edge cases, splitting work properly in Work Breakdown Hierarchy. What used to feel like process overhead is now the main event, because whoever writes the clearest specification gets the best code out of the machine.
The equation is blunt:
flowchart LR
A["vague prompt"] --> B["plausible code"]
B --> C["wrong product, discovered late"]
D["clear criteria"] --> E["correct code"]
E --> F["right product, verifiable immediately"]
An AI assistant given six well written acceptance criteria produces something you can actually verify. Given “build inventory management”, it produces something that looks impressive in a demo and fails on the first backdated entry.
A team that plans badly gets worse results from AI, not better ones, because the machine will confidently build the wrong thing faster than the team can notice.
Use AI on the planning, not only the code
Most teams point AI only at implementation, which is the cheapest part now. It is at least as useful before any code exists:
- Generating edge cases. Give it a Story and the criteria and ask what cases are missing. It will suggest timezone handling, concurrency, permissions, migration of existing data. Some suggestions are noise. Some are the bug you would have shipped. Running the checklist in Test Case Strategy this way takes two minutes.
- Splitting a big Story. Ask it to split along workflow steps, business rules and data variations, then judge the result yourself. It is a decent first cut and a very fast one.
- Drafting acceptance criteria, which you then correct. Editing a draft is much faster than starting from a blank page, and the draft usually reminds you of two cases you had forgotten.
- Writing test cases from criteria. This is near mechanical translation and it is exactly what machines are good at.
- Explaining an old feature so you can write the one pager in Feature Inventory and Ownership. It reads the code faster than you do, but treat its output as a draft of what the code does, never as a statement of what the feature should do. Only a human who knows the business intent can confirm that.
The judgement stays human. The typing does not.
Two traps that are specific to AI generated tests
Tests written from the code instead of from the requirement. Ask an AI to “write tests for this function” and you get tests that assert whatever the function currently does, bugs included. They will pass forever and prove nothing. Tests must come from the acceptance criteria, which is the chain in Test Case Strategy. Write the criteria first, generate the tests from the criteria, and review that each test actually maps to one.
Volume mistaken for coverage. Two hundred generated unit tests on trivial getters is not coverage, it is noise that slows every build and gives false comfort. Ten tests that cover the real business rules and the nasty edge cases are worth more. Judge a test suite by which risks it covers, not by how many tests there are or by a coverage percentage.
Review is the new bottleneck, so treat it as one
If generating code is nearly free and reviewing it is not, then review capacity is what limits your real throughput. A few things follow:
Keep changes small. A 3,000 line generated pull request will not be reviewed, it will be skimmed and approved. That is not review, that is a ritual. Small vertical Stories, as described in Writing User Stories, are now a review strategy as much as a planning strategy.
Review against the criteria, not just the code. The first question in review is not “is this clean code”, it is “does this satisfy the acceptance criteria, including the edge cases”. Clean code that solves the wrong problem is worse than messy code that solves the right one.
Nobody merges code they cannot explain. This is the rule I would treat as non negotiable. If you cannot explain what the change does and why it is correct, you are not the author, you are a courier. Ownership as described in Feature Inventory and Ownership means nothing if the owner does not understand the code they own.
Watch the areas where confident output is most dangerous. Money calculations, tax, permissions, tenant isolation, anything touching a ledger. AI is very good at producing code that looks right in these areas and is subtly wrong, and subtly wrong money code does not crash, it just quietly produces incorrect numbers for months.
Write the documentation the machine will read
A practical side effect worth planning for: the same written material that helps a new engineer also makes AI output dramatically better, because it becomes context.
Clear acceptance criteria, a feature one pager, written architectural decisions and a documented set of conventions all measurably improve what you get back from an assistant. Which means documentation stopped being a cost you pay for future humans and became an input that improves today’s output.
That is the most genuinely new argument for writing things down that has appeared in years, and it is worth using when someone says documentation is a waste of time.
Estimation still works, with one adjustment
Story points measure size, complexity, risk and uncertainty, and that is unchanged. What changes is the mix inside the number. Implementation time shrinks. Understanding, verification, review and integration do not, and they are now the majority of the effort.
So the practical advice from Estimation and Story Points still holds, with one correction: do not let anyone estimate on the basis of “AI will write this in an hour”. The hour of generation is followed by the review, the edge cases, the tests, the integration and the fixing of what the generation got subtly wrong. The Story is not done when the code compiles, it is done when it meets Definition of Done.
And re anchor your reference Stories once, after adopting AI heavily. Your old 5 point Story may genuinely now be a 3. Recalibrate deliberately, then stop, rather than drifting.
The failure mode to watch for
The specific way an AI heavy team dies is not a dramatic outage. It is this:
flowchart TD
A["Month 1-3: we are shipping incredibly fast, this is amazing"]
B["Month 4-6: changes take longer than expected, nobody knows why"]
C["Month 7-9: every release breaks something in an unrelated area"]
D["Month 10-12: nobody will touch the older modules"]
E["estimates are pure guesses"]
F["the team asks for a rewrite"]
A --> B
B --> C
C --> D
D --> E
E --> F
Nothing in that timeline is caused by AI writing bad code. It is caused by the product growing faster than the team’s understanding of it, with no written specification, no test coverage and no ownership to slow the divergence.
The counter is not to use AI less. It is to make the understanding keep pace with the output: criteria before code, tests inside Done, one feature documented per sprint, and an owner for every feature. That is the whole of Why We Miss Deadlines applied to a team that can now type infinitely fast.
The one line version
AI made building cheap. It made defining, verifying and understanding the expensive part. So move your effort there, or you will generate a product faster than you can ever maintain it.