I used to sit down and write the code myself, keeping dozens of “obvious” things in my head: where the contract must not change, what must stay idempotent, which errors must not be swallowed.
AI doesn’t see this context. It can do the task formally correctly — and quietly break a property of the system that didn’t make it into the spec.
So before the code I write down the invariants: what must remain true after the changes.
— the public API doesn’t change;
— a repeated request doesn’t create a duplicate;
— an external service error doesn’t lead to data loss;
— existing tests pass without rewriting their expectations.
The prompt looks like this:
Implement the task. Don’t change public interfaces. Invariants: a repeated call is idempotent; data isn’t lost on error; backward compatibility is mandatory. Before the code, list which parts of the system you will touch.
This works because AI is good at finding a path to the goal but doesn’t guess unspoken boundaries. Invariants are the bumpers on the bowling lane.
You don’t need this for a one-off script or a prototype you’ll throw away tomorrow. In anything that will outlive its first week, it saves hours of debugging.
