The easiest way to ship a half-finished product is to stop the spec at success.
The happy path is usually the first thing everyone can describe. The user clicks a button, the system does the thing, and the screen changes. The product quality shows up everywhere around that moment.
I want specs to name the boring states explicitly:
- loading
- empty
- disabled
- permission denied
- stale
- partial
- conflicted
- retrying
- rollback
Those are not edge decorations. They are the states that decide whether the feature feels trustworthy.
loading is a promise
A spinner is not enough. The spec should say what kind of wait this is. Is the app fetching data, saving changes, running a model, uploading a file, or waiting for a background job? Can the user cancel? Does input stay preserved? Does refresh keep the pending work alive?
empty needs a next step
An empty state is not the same as a no-results state. Sometimes the user has not created anything yet. Sometimes the filter is too narrow. Sometimes the account lacks access. Sometimes data is still syncing. The spec should say why the page is empty and what the user should do next.
disabled controls need a reason
If a button is disabled, the user should not have to guess why. Missing fields, permission problems, locked records, quotas, and background saves all need different copy and different recovery.
errors should keep work intact
If a submission fails, the user’s input should still be there. If a file upload fails, the file should still be attached if possible. If the server rejects an optimistic change, the rollback should be obvious. “Show toast” is not a recovery plan.
stale data should be labeled
Cached pages, sync-delayed records, and eventually consistent results are normal. The spec should say when freshness matters enough to surface a timestamp or a cached label.
If the unhappy path is not in the spec, somebody will invent it in the pull request and the product will end up owning that decision by accident.
Related posts

About Jeremy London
Engineering leader and builder in Denver. I write about AI platforms, agents, security, reliability, homelab infrastructure, and the parts of engineering work that have to survive production.