Emergency patches: carve and deploy safely
Production needs one column added to one table, right now. You can’t wait for the next full release — but you also can’t hand-carve a package with just that table, because the deploy will read every table you left out as deleted and drop it. So you’re stuck: deploy the whole product, or risk nuking three tables to ship one column.
Hey folks. I’m Forge Barrett, master of the Content Forge here at SchemaSmith. Last time we hardened the deploy with runtime gates. Today we close out Course 6 with the emergency patch — packaging a change down to only the objects that changed, and carrying it to a target safely. This is the schema-side twin of the datafix from Module 1: that fixed bad data with a scoped account; this ships a schema fix without touching anything it shouldn’t.
First, the disaster — why you can’t just carve by hand
Section titled “First, the disaster — why you can’t just carve by hand”Here’s the incident fix: a nullable PriceReviewBatch column on OrderItem. The tempting move is to copy just OrderItem into a little package and deploy that. Let’s watch what that costs. The lab’s naive-subset/ is exactly that — OrderItem and nothing else — deployed to a throwaway tenant:
schemaquench --ConfigFile:quench.settings.scratch.json Drop tables removed from the product Dropping table [dbo].Customer Dropping table [dbo].Product Dropping table [dbo].SalesOrderFAILED to quench:Could not create constraint or index. See previous errors.Three tables gone. SchemaSmith did exactly what a full deploy is supposed to do — reconcile the database to the product — and your product only mentioned OrderItem, so the rest are “removed.” Then the run fails outright, because OrderItem’s foreign keys now point at tables that don’t exist. That’s the trap: a subset that’s honest about being partial reads as a product that’s had everything else deleted. (PostgreSQL and MySQL drop the same three tables — only the wording differs.)
The fix: SchemaShears carves and stamps
Section titled “The fix: SchemaShears carves and stamps”SchemaShears builds the same object-level patch, but it does the one thing the hand-carve can’t: it tells the deploy “this is a subset — don’t treat the missing objects as deleted.” Point it at the full product and a manifest of what changed:
schemashears --Source:Package --Manifest:patch-manifest.txt --Output:patchSchemaShears: 3 files into 'patch' (1 from manifest).The manifest is just the changed files — the natural way to produce it is git diff --name-only <before> <after> -- Package/. SchemaShears pulls in that file plus the scaffolding it needs (Product.json, the touched Template.json), and writes a report telling you why each file is in:
SchemaShears patch build report================================Scaffolding Product.jsonManifest Templates\Main\Tables\dbo.OrderItem.jsonScaffolding Templates\Main\Template.jsonAnd here’s the safety — it stamps the emitted Product.json so every drop-by-absence category is turned off:
"DropTablesRemovedFromProduct": false,"DropColumnsRemovedFromProduct": false,"DropUnknownIndexes": false,"DropForeignKeysRemovedFromProduct": false,"DropCheckConstraintsRemovedFromProduct": false,"DropExcludeConstraintsRemovedFromProduct": false,"DropStatisticsRemovedFromProduct": falseThat stamp is the whole game. The deploy honors it with sticky semantics — once a flag is false, nothing downstream can turn it back on — so this patch can only add and alter. It physically cannot drop the objects it didn’t carry.
Deploy it — one column, no collateral
Section titled “Deploy it — one column, no collateral”schemaquench --ConfigFile:quench.settings.canary.jsonPriceReviewBatch lands on OrderItem. Customer, Product, and SalesOrder are untouched — still there, still full of data. Same carve, opposite outcome: where the hand-carved subset dropped three tables and died, the stamped patch adds one column and leaves everything else exactly where it was. Re-run it and nothing changes — the patch is idempotent. That’s a schema fix delivered to one tenant fast, with nothing else disturbed.
Who runs this? The patch is DDL, so it deploys as a schema-capable account — not the least-privilege
datafix_userfrom Module 1. Data hotfix usesdatafix_user; schema hotfix uses the schema-deploy principal. Two halves of an incident response, two different grants.
The override — because sometimes you do mean it
Section titled “The override — because sometimes you do mean it”The suppression is a default, not a cage. When you genuinely want a subset to drop what it omits, --AllowDrops names the categories to leave enabled:
schemashears --Source:Package --Manifest:patch-manifest.txt --Output:patch-allowdrops --AllowDrops:TablesNow patch-allowdrops/Product.json leaves DropTablesRemovedFromProduct alone — the other six stay false — and deploying it drops the omitted tables, because you said so. Safe by default; out of your way when you mean it.
Check yourself: You carve a patch with SchemaShears containing only a changed OrderItem table (default AllowDrops — empty). You deploy it to a database that also has Customer, Product, and SalesOrder. What happens to those three tables?
Nothing — they’re untouched. With an empty --AllowDrops, SchemaShears stamps every drop-by-absence flag (including DropTablesRemovedFromProduct) to false in the emitted Product.json, and the deploy honors that with sticky semantics. So even though the patch’s product only defines OrderItem, the deploy can’t read Customer/Product/SalesOrder as “removed” and drop them — the way a naive hand-carved subset would. The patch can only add and alter what it carries. (Deploy the same subset without the stamp — or with --AllowDrops:Tables — and those three tables drop.)
A good smith doesn’t reforge the whole blade to fix one nick. He works the spot that needs it and leaves the rest of the temper alone — and he never grinds away steel he didn’t mean to touch. That’s an object-level patch: carry only the object that changed, stamp it so it can’t bite the objects it left behind, and strike it into production in one pass. Fast, minimal, and safe by construction.
That’s every gate in the operator’s kit now — least privilege, datafix, pre-flight, CI validation, runtime gates, and the emergency patch. Got an incident-patch story, or a subset that dropped something it shouldn’t have? Email me at forgebarrett@schemasmith.com — I read every one.
That’s a wrap on Course 6. You can run SchemaSmith like an operator, end to end.
Until then, may your patches carry only what changed, and drop nothing you didn’t name.
— Forge