Skip to content

What a declarative tool refuses to do

You have spent ten courses watching SchemaSmith converge things. Declare the shape, quench, and the database becomes what the file says. That is the pitch, and it has been true every time.

So here is the question this course exists to answer. If converging is good, why doesn’t it converge everything?

Point a partitioned table at a package that declares a different layout and it stops. Ask it to move a table to another tablespace and it stops. Change a domain’s base type and it stops — after telling you exactly which two types disagree. Ten courses of “the model is the truth”, and now the model is the truth and the tool won’t act on it.

That looks like a limitation. It is the opposite, and by the end of this course you will be able to say why in one sentence.

Every disagreement between what your package declares and what the database has gets exactly one of three responses.

Converge. The change can be delivered without destroying anything the package does not describe. This is the default and most of what you have seen: add the column, widen the type, create the index, update the procedure. It just happens.

Refuse by name. Delivering the change would move or destroy data, or the engine has no operation for it at all. The run stops at exit 2 and names the object, both values, and the reason. Nothing is attempted — you are not left halfway.

Degrade and report. The engine in front of it cannot do this at this version. The rest deploys, and a downgraded row names what was dropped. You met this in Course 10, and this course does not re-teach it — it just names it as the third member of the set.

SchemaSmith will rebuild what it declares, and will not destroy what it does not.

Read it twice, because everything else follows.

Your model is a complete recipe for everything in it. Drop a table SchemaSmith declares and it can build it back from the file — the shape is written down. That is why converging is safe: the worst case is reconstructible.

Anything not in your model has no recipe. Change Data Capture configuration, a DBA’s hand-placed tablespace, the rows themselves, an index somebody added at 2am — none of that is in your package, so if a deploy discarded it there would be nothing to rebuild it from. A tool willing to destroy what it cannot reconstruct is not a tool you can run unattended.

So the question SchemaSmith asks of every change is not “can I do this?” It is “if I do this, is everything I am about to disturb written down somewhere I can get it back from?”

Before the first module, notice how much of this you have run:

  • Course 4 Recipe 11 — a domain’s base type change refused, naming both types. And an enum value removal reported, never performed, because removing it would drop every column using it.
  • Course 4 Recipe 12 — drop-by-absence reaching only events SchemaSmith created, leaving a hand-made one alone.
  • Course 8 Module 2 — a table rebuild refused because CDC was enabled: that state lives outside the schema package, and no re-deploy can put it back.
  • Course 10 — a feature dropped and reported because the server was too old for it.

Four courses, four refusals, one rule — and no lesson ever named it. That is what this course is for. The behaviour is not new; the frame is.

  • Module 1 — applied at CREATE, refused on change. Placement: partitioning, tablespaces, filegroups. The sharpest answer to “why not converge everything?”
  • Module 2 — state your package never described. The rebuild guards — and DropSchemaBoundDependents, which is where SchemaSmith does force a hard change through, so you can see that refusal is a policy rather than timidity.
  • Module 3 — the refusal you did not ask for. The one case where the engine would happily have complied and SchemaSmith declines anyway.
  • Module 4 — unset means unmanaged. The doctrine that makes the other three coherent, and why it is what lets you point this tool at a database you did not build.

Run course11-setup before Module 1. It creates the four vault_* databases — and, deliberately, the partition function, partition schemes, and tablespace that Module 1 declares.

That is worth pausing on, because it is the first module’s lesson arriving early. SchemaSmith names a partition scheme and a tablespace. It never creates them. They are server-side objects a DBA owns, sized and placed for reasons no schema package can see. Your model says put this table there; it does not get to say what there is. The setup script does that job precisely because the tool will not.

Check yourself: A colleague argues the refusals are a maturity gap — that a more capable tool would just do the rebuild, move the data, and save everyone the manual migration. What is the strongest version of their case, and where does it actually break down?

Their strongest case: the operations really are possible. Moving a table between tablespaces, repartitioning, rebuilding a CDC-enabled table — a DBA can do all of it by hand, so a tool could script it. Refusing is a choice, not an incapacity, and choices can be wrong.

Where it breaks down: these operations are possible for a human who knows the intent. The tool only has two states and a diff between them. Given an old partition layout and a new one it cannot tell whether you meant a SPLIT or a MERGE — the same diff describes both, and they do different things to your data. Given a CDC-enabled table it cannot reconstruct the capture configuration afterward, because that was never in the package to begin with.

So the real objection isn’t “a better tool would do it.” It’s “a better tool would need information the model does not contain” — and a tool that acts on a guess about your data, unattended, on the strength of an edited file, is not more capable. It’s just harder to trust.


There is a version of this tool that never says no. It converges everything, always, and it is a much easier product to describe. It is also one you would never point at production without watching it, which means it would save you nothing at all.

The refusals are what make the rest of it safe to automate. Four modules to show you why.

— Forge