Capstone: a careless rename, and the net that catches it
You renamed a table. One JSON edit — OrderHeader becomes SalesOrder — and the deploy went green in dev, green in staging, green in prod. Then support calls: the orders screen is empty. Every order your customers placed, gone from where the app looks.
That’s not a hypothetical. It’s the exact run you’ll do in this lab. And it ends fine — because the tools you’ve spent this whole course building are the net that catches it.
This is the capstone. You’ve forged every piece of this already — promote one artifact across environments, roll back by re-deploying the version that worked, wire a recyclebin so a drop is recoverable. Here they all meet, on one product, in one continuous story: build it, ship it to prod, break it on purpose, and bring the data home.
One product, all the way to prod
Section titled “One product, all the way to prod”Start with OrdersService — a Customer table, an OrderHeader table with a foreign key between them, and the recyclebin riding along in the package. Quench it to ordersservice_dev, then promote that same artifact to staging and to prod, one script token apart. You did this in the last module; the metal’s the same, you’re just swapping the dye:
[localhost,11433].[ordersservice_dev] Successfully Quenched[localhost,11433].[ordersservice_staging] Successfully Quenched[localhost,11433].[ordersservice_prod] Successfully QuenchedNow the part that matters for this story: prod has real data. Seed it — three customers, four orders — the rows your business actually runs on. Dev and staging stay empty. That difference is the whole lesson, and it’s exactly the difference you have in real life: your lower environments are clean, and prod is where the data lives.
The change that looks clean everywhere it’s safe
Section titled “The change that looks clean everywhere it’s safe”Someone decides OrderHeader should be called SalesOrder. So they do the obvious thing — rename the table file, change "Name" to SalesOrder, and quench. But here’s what SchemaQuench actually sees: a table named OrderHeader that’s no longer in the product, and a new table named SalesOrder that isn’t in the database yet. It doesn’t read your mind. It reads the desired state. To close that gap it drops one table and creates the other.
Ship it to dev. Clean. Ship it to staging. Clean. No errors, no warnings, nothing to sign off against — because there were no orders in those environments to lose. This is the trap, and it’s a quiet one: a change can be green everywhere it’s safe and still be a landmine where it isn’t.
The break lands where the data lives
Section titled “The break lands where the data lives”Promote that same package to prod. It succeeds — no error, Successfully Quenched, the deploy looks identical to the others. But OrderHeader held four real orders, and the change dropped it. Check prod and the damage is plain:
SalesOrder rowcount: 0Four orders in, zero out. The new table’s there; it’s just empty. Promotion caught the problem late — prod is the first environment with data to lose, so prod is where you find out. This is the failure mode Course 8 trains you to read: the run said success, but success means “the database matches the package,” not “your data survived.”
Except it did survive. Because this package ships a recyclebin, the drop didn’t go to the void — it went to the bin:
OriginalSchema OriginalName RecycledNamedbo OrderHeader dbo_OrderHeaderThe table’s set aside, data and all, waiting. A careless rename is a drop-and-recreate — but a drop through the recyclebin is a drop you can take back.
Roll it back, bring the data home
Section titled “Roll it back, bring the data home”You know the move: rolling back is just deploying the version that worked. But this drop was destructive, so you WhatIf first — dry strike, every time. Point the old v1 package at prod with WhatIfONLY and SchemaQuench shows you the plan and applies nothing:
EXEC SchemaSmith.CustomTableRestore 'dbo', 'OrderHeader';There it is — the restore it would run. Read it, then run it for real. Quench v1 back to prod and the recyclebin closes the loop on its own:
[dbo].[OrderHeader] Restored Dropping table [dbo].SalesOrderWhen SchemaQuench goes to recreate the missing OrderHeader, the recyclebin’s restore hook gets there first — it finds the recycled copy and brings it back with every row intact. No hand-written recovery. No INSERT script reconstructed from a backup at 2 a.m. Prove it:
OrderHeader rowcount: 4Four orders out. All the way back. The empty SalesOrder goes to the bin in its place, and prod is exactly the known-good state you shipped this morning.
The one line that would’ve stopped all of it
Section titled “The one line that would’ve stopped all of it”Here’s the part that stings a little: none of that had to happen. The careless rename went wrong because it never said it was a rename — it just gave the table a new name and let SchemaQuench draw the only conclusion it could. Tell it the truth instead, and the whole drama evaporates.
The fix is one property. On the SalesOrder table, add OldName:
{ "Name": "SalesOrder", "OldName": "OrderHeader", ... }That’s the whole change — byte-for-byte the careless version plus that single line. OldName tells SchemaQuench “this is OrderHeader, just under a new name,” so it stops reading the edit as a drop-and-add and issues an in-place rename instead. Ship it dev → staging → prod and the log says plainly what it did:
Handle Table Renames Rename [dbo].[OrderHeader] to [dbo].[SalesOrder]Check prod:
SalesOrder rowcount: 4Four orders, carried straight across. This time OrderHeader wasn’t dropped — it was renamed — so its rows never left the table and there’s nothing data-bearing in the bin and nothing to restore. Same product, same rename, opposite ending. The difference was one line, and the line was just saying what you meant.
Check yourself: The v2 deploy renamed a table and finished with 'Successfully Quenched', yet prod's data vanished. Why did it succeed, and why was the data recoverable anyway?
SchemaQuench reads the rename as two separate facts — a table removed from the product and a new one added — so it drops the old table and creates the new one, and “success” means the database now matches the package, not that data survived. The data was recoverable because the package ships a recyclebin: the drop was routed into the bin instead of destroyed, and re-deploying the prior package restored it automatically.
Think of it this way. A smith who reshapes a piece without thinking can ruin it in one blow — but a smith who works over a catch tray never loses the shavings. That’s what you built across this course. Promotion carried one true artifact from forge to fire, so what broke in prod was the same thing that passed staging. The dry strike showed you the blow before it landed. And the recyclebin caught what the careless change let fall, so a rollback didn’t just revert the shape — it brought the metal back. No single tool saved you here. The system did. And the next time you reach for that rename, you won’t need saving at all — you’ll add the one line that says rename, and the smith will shape it clean the first time.
Want the deeper treatment — how the recyclebin hooks work, when a drop is recoverable and when it truly isn’t, how to tune retention? Read the Zero-downtime database migrations guide on the SchemaSmith site and the end-user guide’s CI/CD Integration chapter.
That’s Course 3, end to end. You can cast a database to files, review the change like code, gate it on WhatIf, promote one artifact across every environment, and — when a change goes wrong where the data lives — roll it back and recover. The tools don’t stop working when the deploy goes green. That’s exactly when they earn their keep. Go break something in the lab on purpose, then bring it back, so the day it happens for real your hands already know the move.
Broke prod in a way this didn’t cover, or want a second set of eyes on a recovery plan before you run it? Email me at forgebarrett@schemasmith.com — I read every one.
Until then, may your bad casts land in the bin, not the void, and every rollback bring your data home.
— Forge