Invariants
Properties that must always remain true — an order total is never negative, a payment never happens twice — found from examples and turned into tests.
A feature list says what the store does. An invariant says what it must never do — an order total is never negative, a payment never happens twice — whatever feature, bug or concurrent user is involved. Finding them is a different question from finding requirements, and it is asked before the data model.
Abstract state is hard to reason about; a concrete case is not. Construct a small example — three units, two buyers, one price change — walk it step by step, and the property that must hold falls out of the moment the example goes wrong. Counterexamples find invariants faster than definitions do.
The running example, worked fully: an order total is never negative, every order item references a product, a payment never happens twice, inventory is never negative. For each — who can violate it, where it is held, and what happens when it is not. The invariants decide the schema and the transaction boundaries before either exists.
Product A has three units. Alice buys two; Bob buys two at the same moment. Every line of both checkouts is correct and the store has promised four units of three. The example reveals the concurrency problem that no single-user test can see, and the thinking move is to name it as a question before choosing a mechanism.
An invariant on a page protects nothing after the person who wrote it leaves. Turned into a test that asserts the property after every sequence of actions — including the interleaving that found it — it becomes the only form of the rule that survives refactors, new endpoints and new engineers.