Back to blog
Business & Decisions

Six Months Late and No End in Sight: Rescue the Project or Start Over?

How to audit a stalled project in two weeks: codebase health, team composition, and the sunk-cost trap. Clear criteria for when a rewrite is cheaper than a rescue.

A project that is six months late almost never fails for the reason printed on the status report. "We underestimated the API integration" is what gets said in the meeting. The real cause is usually structural, and it has been sitting there since month two. The missed date is the alarm, not the fire.

So "rescue or restart" is a premature question. You can't answer it from a gut feeling or a slick demo. You need a diagnosis you'd defend in front of a board, and you need it fast, because every week you deliberate, the team keeps shipping toward whichever direction is wrong. Here is how to run that diagnosis in two weeks, and the criteria that actually decide it.

The delay is a symptom, not the diagnosis

Late projects cluster around four root causes: scope that never stopped moving, an architecture that fights every new feature, a team that can't hold velocity, or stakeholders who keep changing the target. From the outside they look identical, a date that slips, but they call for opposite responses.

This matters because a rewrite cures only one of them. If your architecture is sound and the real problem is a spec that mutates every sprint, starting over just buys you a clean codebase that rots the same way by month four. Name the root cause before you pick the treatment.

Timebox the audit to two weeks

The audit is a decision-support exercise, not a project. Two weeks, hard stop. Longer than that and you've quietly started a second stalled effort. Split it cleanly:

  • Week one, the code: clone it fresh, build it, run it, read the hot paths, run static analysis. Can you even reach a working local environment?
  • Week two, the humans: interview the team, read the git history and the ticket tracker, reconstruct why it stalled. The commit log tells a more honest story than the standup.
  • Output: a one-page memo, root cause, future cost of rescue, future cost of restart, recommendation. Not a 40-page report nobody reads.

Codebase health: what actually predicts survival

Global test coverage and line counts are vanity metrics. What predicts whether a codebase can be revived is more specific:

  • Clean-checkout build: does it build and run from a fresh clone in under an hour, following only the README? If setup is tribal knowledge, everything else is too.
  • Change hotspots: run git log analysis (or CodeScene / Code Maat). A handful of files with 50+ changes and high complexity is where your bugs and your slowdown actually live.
  • Tests on the money paths: not a global percentage, but whether payment, auth, and core-domain flows have any coverage at all.
  • Bus factor: how many people understand each critical module. When the answer is zero, you don't have a codebase, you have an archaeology site.
  • Dependency age and end-of-life: a framework two majors behind, or a runtime past EOL, is a cost you pay whether you rescue or not.

Team composition beats code quality

Most rescues that fail, fail on people, not on code. Before you judge the codebase, judge who's standing around it:

  • Seniority mix: a project built entirely by juniors with no architect keeps producing the same structural problems, on any codebase, old or new.
  • Continuity: are the people who wrote the core still here? If they've all churned out, both rescue and rewrite start from near-zero context.
  • Ownership: is one person accountable for the architecture, or is it design-by-committee? Nobody's project is everybody's problem.
  • Brooks's law still holds: throwing bodies at a late project makes it later. The fix is rarely more people.

The sunk-cost trap runs both ways

The money already spent is gone. Every dollar of it, whether you continue or scrap. Decide purely on cost-to-production from today forward. "We've already put in $400k" is not an argument; it's grief. The only honest question is which path is cheaper and more credible starting now.

The trap runs the other way too. Restart fever is just sunk-cost bias in a lab coat, the belief that a clean slate will stay clean this time. It usually won't. The second-system effect is real: teams rebuilding a system they resent tend to over-engineer the replacement and rediscover, one by one, the edge cases the old code already handled.

When a rewrite is genuinely cheaper

Sometimes the numbers really do favor starting over. The pattern looks like this:

  • The codebase is small, under roughly 20-30k lines, so rebuilding is weeks, not quarters.
  • Bus factor is zero and there are no tests: the cost to understand the old code exceeds the cost to rewrite it.
  • The architecture physically can't meet a core requirement, built single-tenant and now needs multi-tenant, built synchronous and now needs event-driven.
  • The runtime or framework is end-of-life, so a migration is coming regardless.
  • The domain is now well understood. The original code was the team learning the problem; this time you know what to build.

When rescue wins

More often, the boring choice is the right one. Keep it when:

  • The business logic is large, correct, and encodes years of edge cases, knowledge that is expensive to re-derive and easy to lose.
  • There are tests, or enough structure to add them and refactor behind a stable interface.
  • The real problem is process, scope, or people, none of which a rewrite fixes.
  • You can ship incrementally: strangle the bad parts module by module (the strangler-fig pattern) instead of a two-year big-bang rebuild with no releases.

The one-line test

Before you decide, ask one question: is the pain coming from the code, or from everything around it? If the codebase is small, understood, and architecturally stuck, rewriting is honest. If the pain is scope, process, or people, a rewrite just relocates the problem into a newer repo and resets your calendar to zero. Most failed rescues weren't unsalvageable code, they were unsalvaged reasons the project stalled. Fix the reason first, and the rescue-or-restart question usually answers itself.

Want help applying this to your system?

Book a call