An Additive Migration Plan and BlockedBy
Quick answer: The Proposed layer turns the reconciliation into an ordered, additive migration plan. Each step declares a blockedBy dependency, so a table or foreign key cannot be created before the thing it depends on, a
Quick answer: The Proposed layer turns the reconciliation into an ordered, additive migration plan. Each step declares a blockedBy dependency, so a table or foreign key cannot be created before the thing it depends on, and the plan adds rather than destroys. The deployment script is idempotent and forward-only, and the generated SQL is never executed by the modeling package.
Why the plan is additive
A destructive rebuild would drop and recreate tables, which risks data and makes a migration hard to run safely. An additive plan keeps the existing matched tables in place and adds only the missing pieces, the new columns, keys, and link tables the reconciliation identified.
That keeps the change narrow and reversible in practice, and it means the matched tables are not touched at all.
What ordering and blockedBy do
The steps have real dependencies. A foreign key cannot be created before the table it references, and a link table cannot be created before its two entities exist.
| Element | Dependency |
|---|---|
| Foreign key | Blocked by the referenced table |
| Link table | Blocked by both related tables |
| Index | Blocked by its table |
| Column | Blocked by the table that holds it |
The blockedBy field carries these dependencies, so the plan cannot run a step out of order even when the steps are listed together.
How the plan is built
- Read the missing and drift tables from the Modeled layer.
- Turn each needed change into an additive step.
- Declare blockedBy for every step with a prerequisite.
- Order the steps so dependencies precede their dependents.
- Keep the inferred items and open questions attached.
- Review the generated SQL before it runs.
The plan stays forward-only, so it moves the schema ahead and does not reverse earlier migrations, and it is idempotent, so running it more than once does not produce duplicate changes.
Walk a concrete plan to see the ordering. The first step creates the missing preferences table, and nothing that references it is allowed to run yet. The foreign key from orders to preferences is blocked until the table exists, and the link table that joins preferences to products is blocked until both are present. The indexes come last, because each is blocked by its own table. If the steps were listed without blockedBy, a run could attempt the foreign key first and fail against a table that does not exist, and the failure would surface halfway through rather than at the planning stage. The dependency field moves that check up front, so the reviewed script runs in an order the database can accept, and the idempotent script can be re-run safely if a later step is interrupted. The matched tables sit outside the whole sequence and keep their data untouched. That is how a forward-only plan stays both narrow and safe to retry.
Why open questions stay out of the plan
A step that depends on unresolved logic should not be emitted as a confident migration. An inferred link table or an ambiguous cardinality stays in the Inferred layer with its open question until a reviewer confirms it, rather than being forced into the ordered plan.
This is the same boundary that keeps a static signal from being treated as a guarantee. The plan is a precise proposal grounded in the observed baseline, and it does not execute itself, so a wrong assumption cannot reach the storage without a review.
Powerduck keeps the ordering, blockedBy, and the forward-only rules in the desktop so the migration is both safe and readable.
Frequently asked questions
What does blockedBy prevent? It stops a step from running before its prerequisite, such as a foreign key created before its referenced table.
Why is the plan additive? To keep matched tables and their data in place, adding only the missing pieces rather than rebuilding.
What happens to unresolved inferred items? They stay in the Inferred layer with open questions and do not enter the plan until confirmed.
The bottom line
The migration is an ordered, additive plan where blockedBy enforces the real dependencies between steps, so keys and link tables are never created before their prerequisites. It is idempotent and forward-only, and inferred items stay out until confirmed. The generated SQL is reviewed rather than executed, which keeps a hard-to-reverse change from reaching the storage unconfirmed. The ordering is what makes the plan safe to run. Read more in the API data model guide.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.