Unit 16 · lesson
Know When to Stop the Generator
Core path: 30 minutes
One of the easiest ways to lose control of AI-assisted development is to keep asking for one more improvement after the system already satisfies the requirement.
The code gets longer.
The architecture gets wider.
The tool sounds productive.
And somehow the project becomes harder to explain than it was thirty minutes ago.
This lesson is about stop conditions.
A finished requirement is allowed to stay finished
Suppose the specification says:
console application
local JSON storage
search by name
summary report
pytest tests
The current project satisfies all of it.
Then the AI suggests:
SQLite database
REST API
web dashboard
user accounts
Docker deployment
plugin architecture
Those ideas are not automatically bad.
They are outside the current project.
The correct response can simply be:
No. The specification is satisfied.
That is engineering judgment, not lack of ambition.
Define a change budget
Before a generated slice, state what may change.
Example:
Goal:
Add JSON persistence.
Allowed files:
storage.py
tests/test_storage.py
Must not change:
system.py public behavior
report formatting
CLI menu
Definition of done:
save/load round trip passes
missing file returns empty collection
existing suite remains green
Now the diff has a boundary to compare against.
Without a change budget, "while I was here" becomes architecture drift.
Detect scope creep in the diff
Imagine the task was to fix one threshold bug.
Expected diff:
system.py
one test
Actual generated diff:
system.py
storage.py
main.py
reports.py
requirements.txt
README.md
Do not start reading six files hoping it is fine.
First ask why the blast radius expanded.
The candidate should justify the extra changes or be narrowed.
Clever code can violate the project even when tests pass
Your course specification includes:
beginner-readable code you can explain.
So this is a legitimate failure:
all tests pass
but student cannot explain the abstraction
Maybe the generated implementation introduced:
- metaclasses;
- decorators that hide important behavior;
- a framework the project did not need;
- dense comprehensions nobody can trace;
- unnecessary inheritance;
- a generic plugin system for four functions.
Technically working is only one acceptance criterion.
Maintainability and explainability can be requirements too.
Do not let tests move the goalposts
A dangerous generated change looks like this:
implementation fails test
↓
AI changes the test
↓
suite becomes green
Sometimes the test really was wrong.
But you must compare the test change to the original requirement.
If the requirement says battery 20 is low and the AI changes the test to expect False, the suite is now green because the contract was weakened.
Green is not magic.
Build a rejection record
For one generated or supplied proposal, identify something you did not accept.
Record:
proposal:
why it looked reasonable:
which requirement/constraint it violated:
what evidence showed the mismatch:
what narrower alternative you kept:
A rejection is part of the engineering record.
If your AI log contains only accepted suggestions, I would be suspicious that you were reviewing the tool politely instead of reviewing the code.
Use the rollback test
Before accepting a slice, ask:
If this slice turns out to be bad, can I return to the previous known-good state without guessing?
That is why focused Git commits matter.
A giant generated change that mixes model, storage, tests, documentation, and formatting into one checkpoint is harder to recover from.
Small slices reduce the blast radius of a bad idea.
Stop conditions for the System Status Console
The build should stop when:
- every required behavior exists;
- boundary tests pass;
- persistence round trip works;
- the architecture still matches the approved plan or documented revision;
- the final diff contains no unexplained scope expansion;
- the student can explain the modules;
- known limitations are recorded.
At that point, "make it more advanced" is not automatically progress.
Sometimes the professional move is to stop touching the damn thing.
Student-facing version: do not confuse movement with progress.
That rule will save you from both AI tools and yourself.
Reader workbench
Hold implementation against acceptance boundaries
This is the Unit's one-file practice surface. Read the code, predict one result, run it, then change a value, input, condition, or boundary and explain why the evidence changed. Multi-file projects, Git, terminals, packages, and live services still belong in the full development workspace.
Run the code to see output.
This runs in an isolated Python worker in your browser. Your edits stay in this browser until you reset them.