The Failed Migration — Rescuing a $180K Classic ASP Project
The Challenge
A healthcare services company engaged a development agency to migrate their Classic ASP system — built in 2003, handling client intake, scheduling, billing, and regulatory reporting — to modern ASP.NET Core. The contract was $180,000. The timeline was nine months. Eighteen months later, the project had delivered a partial system with a structurally broken billing module, a skeleton reporting module with no working code, and 12 months of accumulated business data living in spreadsheets because the old system had been frozen at the agency's instruction. The agency was unresponsive. The client had no working new system and a frozen old system. Regulatory reporting had stopped. Legal action was being discussed.
Our Solution
SOLUTION:
We were engaged to assess the situation before any decisions about litigation were made. What follows is what we found, what we built, and what we learned — because this case illustrates something important about why legacy migrations fail and what it takes to rescue them.
The assessment
The assessment took five days and produced a 34-page written report. Our findings were direct.
The agency's ASP.NET Core codebase was not worthless. The intake and scheduling modules were structurally sound and approximately 80% complete. The billing module was approximately 60% built — but it had a fundamental problem: the data model the agency had designed did not correctly represent the billing rules the healthcare client actually used. It was built on the agency's interpretation of conversations with the client, rather than on the actual business logic embedded in the Classic ASP system. Billing rules in healthcare are complex, specific, and unforgiving. The misalignment was not a bug that could be patched. It was a structural error that required the module to be rebuilt.
The regulatory reporting module was a shell — route definitions, placeholder controllers, no functional code.
The Classic ASP system as the real specification
The decision we made early was the one that made everything else possible: we treated the Classic ASP system as the authoritative specification for the new build.
The agency had tried to infer the business rules from client conversations. We read them directly from the code — 20 years of precise logic in VBScript, describing exactly how billing had to work, what the edge cases were, what the exceptions meant, how regulatory reports were structured. The old system was not a liability. It was the most accurate specification available, and it was sitting right there.
Rebuilding the billing module
We rebuilt the billing module from scratch, using the Classic ASP system as the source of truth for every business rule. We worked through the VBScript systematically: every billing calculation, every exception condition, every edge case documented and replicated in the new C# codebase. The data model was revised to correctly reflect the billing structure. The module went through parallel testing against the Classic ASP system — real transactions run through both systems, outputs compared line by line — before a single line of it was considered done.
Building the reporting module
The regulatory reporting module was built new, using the SSRS report definitions from the Classic ASP system as templates for the required output formats. The regulatory body's format specifications were mapped against the existing reports to confirm compliance before build began.
The data migration
The data migration was the most complex component — and the most sensitive. Twenty years of operational data sat in an Access database behind the Classic ASP system. We extracted it, cleaned and normalised it for the new SQL Server schema, and validated it against the source records at every stage of the process.
The 12 months of spreadsheet-based workarounds — records created outside the frozen system during the period the agency had kept the project stalled — required manual reconciliation. We worked through them with the operations team over two weeks, record by record, incorporating everything into the migration before cutover.
Parallel running and cutover
The new system ran in parallel with the Classic ASP system for four weeks before cutover. Every transaction processed in the new system was verified against the old. The cutover was planned for a weekend. It ran on schedule.
The outcome
The project went live four months after we were engaged — delivering in four months what the previous agency had failed to deliver in eighteen. Every critical feature was present and working. The billing module processed its first production billing cycle without a single error. The regulatory reporting module produced its first required report on schedule and was accepted by the regulatory body without question.
The client avoided the lawsuit they had been preparing. Business operations returned to normal.
What this case illustrates
Failed migrations follow a pattern. A new team inherits the scope of the old system from conversations rather than from the code itself. The business logic gets reinterpreted rather than replicated. Edge cases go undiscovered until production. The timeline slips. Confidence collapses.
The working code in an old system is not a problem to be escaped. It is a precise record of every business rule the organisation has developed over years of real-world operation. Reading it carefully — and treating it as the specification rather than the obstacle — is the difference between a migration that works and one that doesn't.
That's the approach we bring to every engagement, whether it starts as a new project or as someone else's failure.