Do not begin with a rewrite. First identify the product's critical workflow, reproduce its failures, establish who owns the data and deployment, and create a narrow release boundary that can be verified. Replace code only where the existing path cannot be made dependable at a reasonable cost.
Freeze the critical path
Name the first user, the one result that must work, and the states required to reach it. Pause speculative features until that path is reproducible in a controlled environment.
Turn symptoms into evidence
Record exact inputs, environment, logs, data state, expected behavior, and actual behavior for each failure. Separate product gaps from code defects, configuration problems, integration failures, and missing operational ownership.
Repair boundaries before polish
Prioritize authentication, authorization, data integrity, API contracts, error recovery, deployment, and monitoring. Visual cleanup cannot compensate for an unreliable state transition or an unknown source of truth.
Release with explicit proof
Define acceptance checks for the critical path, run them against the release build, document known limitations, and keep a rollback path. The next scope should come from observed failure and user friction, not code aesthetics.
Symptom, cause, test, response
| Symptom | Likely cause | Test that confirms it | Response |
|---|---|---|---|
| Works locally, fails in production | Missing environment variables or different config | Deploy a preview with the production config | Document every variable; one release path |
| Users see each other’s data | Authorization only in the interface | Request another user’s record directly | Enforce ownership in every query |
| Random duplicate records | Retries without idempotency | Submit the same action twice quickly | Unique constraints and idempotency keys |
| Integration silently stops | Unhandled provider errors | Replay a failed provider response in the sandbox | Visible failure state, retries, alerts |
| Every fix breaks something else | No tests on the critical path | Write one failing browser check for the path | Tests first, then narrow fixes |
| Nobody can deploy but one person | Undocumented release steps | Ask a second person to deploy a preview | Written release and rollback steps |
Confirm the cause with the test before changing code.
Decision checklist
- Name the first user and the one result that must work.
- Reproduce each failure with exact inputs and environment.
- Separate product gaps, code defects, config problems, and integration failures.
- Fix authentication, authorization, data integrity, and recovery before polish.
- Release with acceptance checks, documented limits, and a rollback path.
Common mistakes
- Starting with a rewrite before reproducing failures.
- Polishing the interface while data integrity is unknown.
- Letting new features continue during stabilization.
- Choosing next scope by code aesthetics instead of user friction.

