First: stop accumulating changes
If the build is already inconsistent, adding three more fixes makes diagnosis harder. Freeze feature work long enough to establish a trustworthy baseline.
Capture the deployed behavior, current branch or commit, relevant configuration names, known-working paths and the exact symptom you are trying to repair.
Reconstruct current state
Separate facts from assumptions. “Checkout is broken” is a conclusion. “Clicking the CTA produces a 500 response from the session-creation endpoint” is a useful state observation.
Find the first broken boundary
Trace the flow from the user action outward. The first confirmed break is where investigation should stop until that boundary is repaired.
This prevents a common failure mode: changing downstream code to compensate for an upstream problem. If the browser never sends the expected payload, debugging the database first is wasted motion.
Repair narrowly and preserve what works
Write the repair as a constrained decision: fix one boundary, preserve everything known to work, and define the evidence required before the fix is accepted.
Do not redesign this feature. Known working: [list verified behavior] Broken boundary: [the first confirmed failure] Required repair: [one specific correction] Preserve: [adjacent behavior that must not change] Verification: [the exact test proving the boundary and end-to-end flow work]
Advance only after the evidence is clean
A recovery is complete when the repaired boundary works and the full user story still works around it. Commit or otherwise preserve that known-good state before starting the next feature.
The goal is not merely to remove the error. It is to leave the project with a stronger source of truth than it had before the failure.