A spec that stops at success is not finished.
Name the states around the happy path:
- loading
- empty
- disabled
- permission denied
- stale
- partial
- conflicted
- retrying
- rollback
Loading should say what is happening, whether the user can cancel, whether input is preserved, and whether a refresh keeps the operation alive.
Empty needs a reason and a next step. No records yet, no search results, no access, and data still syncing are different states.
Disabled controls need an explanation. Missing fields, permission, locked records, quotas, and background saves require different recovery.
Errors should preserve work. Keep form input, preserve an attached file when possible, and make optimistic rollback visible. “Show toast” is not a recovery plan.
Stale data should be labeled when freshness affects a decision. A cached page, delayed sync, and eventually consistent result are different truths.
If the unhappy path is absent from the spec, the pull request will invent it. The product will own that accidental decision afterward.
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.