I once sat in a Pune conference room while a founder argued for a full rewrite of an AI copilot that was already taking real card payments. The embarrassing part was not the code. The embarrassing part was that we found the payments, the prompts, and the users in one afternoon, and none of those facts had been written into the rewrite brief.
A prototype is not a moral failing. It is a bet that shipped. The question in 2026 is not whether the folder names please a visiting engineer. The question is whether you can put a ceiling on risk without throwing away the only evidence you have that customers care.

The origin of a rewrite that should not have started
The copilot had been generated on a weekend. A Bolt export had become a Next.js app. A freelancer had pasted an OpenAI key into a file named secrets.local.js and later into a client bundle. The database was one Postgres table with a single jsonb column called data. Tests did not exist. Users did.
The founder had been told this could not be production. So he paused outbound sales, hired a second team, and commissioned a clean architecture. Eleven weeks later the clean architecture still had no checkout. The original app still had customers asking why login failed after a password reset.
That is the pattern I keep seeing. The rewrite is sold as courage. It is often avoidance. I do not romanticise vibe-coded apps, and I do not burn a working checkout because the routes live in one file. You score the repo. Then you choose. The unglamorous version of that work lives on the IndiaNIC blog.
When should you rescue an AI prototype instead of rebuilding it?
You should rescue an AI prototype when it already has users, the core flows can be named, and the damage is local. Rescue keeps the running system, freezes behaviour in a spec, and repairs the riskiest layers first. Rebuild is for when nobody can tell the truth about what the code does.
Local damage looks like this. The model key is in the browser. One table holds users and invoices as JSON. There is no test on the pay wall. A contractor still owns the GitHub organisation. Each of those is a repair. None of them, alone, is a reason to throw away the product. Taste is not a score.
The five-line scorecard founders skip
Meetings produce opinions. Scorecards produce decisions. I use five lines: modularity, schema, tests, secrets, and IP. If three or more lines say rebuild, I stop arguing for rescue. If three or more say rescue, I stop the theatre of a greenfield rewrite.
Modularity is whether you can change the chat UI without breaking billing, and whether the model call lives behind a server route. According to the Next.js composition guidance, server code and client code are not the same privilege. A Client Component that calls OpenAI is a secret on the public internet.
Schema is whether PostgreSQL can say what a row is. Data from the PostgreSQL constraints documentation is blunt: a table without keys and checks will not survive a second engineer. Test coverage, for a prototype, means a machine can prove login, pay, and the one AI action that costs money. I would rather have three Playwright journeys than eighty unit tests on a prompt formatter. According to the OWASP Web Security Testing Guide, session handling is testable. If you cannot test it, you do not have it.
| Score in writing, in one sitting. Open the repo, the database, the cloud accounts, and the legal folder. Mark each line rescue or rebuild. Do not debate a line that you have not opened. The scorecard is a record of what you saw, not a mood. |
How IndiaNIC runs a spec-driven rebuild
When the scorecard says rebuild, we still do not start from a blank Figma file. IndiaNIC’s spec-driven rebuild starts from the running prototype. We click through the live product and write down the click path, the data written, and the error the user already lives with. That record becomes acceptance tests before anyone opens a new app router.
The rebuild then happens in bounded modules: identity, billing, the model boundary, then the screens. We dual-write. Old rows keep working. New tables gain constraints. When the new path matches the spec, we cut traffic. The old URL can stay.
What does a spec-driven rebuild actually change?
A spec-driven rebuild starts from the running prototype, not from a blank design file. We record what the product does today, turn that recording into acceptance tests, then rebuild one bounded module at a time against those tests. Data moves with dual writes. Cutover happens when the new path matches the spec, not when someone feels proud.
The change is that the team stops arguing about frameworks and starts arguing about behaviour. “Does the failed payment retry?” is a better fight than “should this be Remix.”
| A rewrite without a spec is just a second prototype with a higher burn rate. |
A worked example: the Ahmedabad copilot
Here is how the five lines landed after that Pune meeting, once we opened the repo in an Ahmedabad war room the next morning.
Modularity scored rescue. The generated Next.js app was messy, but API routes existed and chat was separate from billing. Schema scored “rebuild the data layer, not the company.” One jsonb table is a smell, not a death certificate. We lifted users, threads, and charges into ordinary tables. The blob told us what customers had actually stored.
Tests scored rescue-with-urgency. There were none, so we wrapped login, the Stripe checkout session, and one paid completion in Playwright the same week. Secrets scored “repair now.” The OpenAI key had been prefixed for the client. We rotated it and moved the call to the server. IP scored rebuild of ownership, not of code. The freelancer still owned the GitHub org and the Stripe account sat on a personal email. We transferred both before we wrote another feature.
Final tally: four rescue, one ownership repair. We stood the rewrite team down. The original URL kept the customers. Two weeks later the keys were rotated, the webhook verified, and the fat table had been split.
What you should do this week
Do not schedule a rewrite workshop. Schedule a scoring morning. This is the order I use.
- Open production, not Figma. Write the five money paths on paper: sign up, login, pay, the AI action, refund or cancel.
- Clone the repo and mark modularity. Can you name the server file that talks to the model? If the answer is “the page,” that line is in trouble.
- Open the database. List tables. If you have one blob, dump ten real rows and name the fields you would promote tomorrow.
- Add one Playwright test around checkout, even if it is slow and ugly. A red test is a spec. A slide deck is not.
- Rotate every key that ever sat in a
NEXT_PUBLIC_variable. Then search git history. Assume it is public. - Confirm who owns GitHub, Vercel, Stripe, and the OpenAI org. Transfer anything that is still personal.
- If three or more lines say rebuild, write the spec from the live product before anyone opens a new repo.
If the scorecard is mixed, rescue the money path and rebuild the unsafe boundary. That is not indecision. That is how grown systems are made. The market does not pay you for a tidy lib folder. It pays you for a product that still works on Monday.
Frequently asked questions
Is a messy generated Next.js app automatically a rebuild?
A messy generated Next.js app is not automatically a rebuild. Generated folders are a style problem until they hide billing, secrets, or identity. If you can isolate the model call and name the payment path, rescue it. Rebuild only when the generated file is the product and cannot be split without inventing behaviour.
How long should a rescue take before I admit I need a rebuild?
A focused rescue should prove itself in two weeks: keys rotated, money path tested, worst table lifted, ownership transferred. If after that you still cannot describe a user or a charge, stop. That is a rebuild. Do not stretch a rescue into a quiet six-month rewrite with no spec.
Do I pause sales while we score or rebuild?
Do not pause sales while you score. Scoring is a morning, not a quarter. If you must rebuild, keep the old URL live and cut over one path at a time. A silent market is a more expensive bug than an ugly repository. Customers can live with a plain UI. They cannot live with a vanished product.
