Quick answer: The four-layer reconciliation compares the API model against the database in four stages. Observed reads the live tables and enforced keys, Modeled assigns per-table status with field diffs and impacted operations, Proposed builds an ordered additive migration plan with blockedBy, and Inferred carries link tables, open questions, and safeguards. Each layer builds on the one before rather than jumping straight to a change.
Why reconciliation is layered
A single flat comparison cannot tell you what is real, what differs, what should change, and what is only inferred. Mixing those together makes a proposed migration look more certain than it is, and it hides the difference between a table observed in the database and a table the model merely suggests.
The four layers keep those states separate and ordered, so the reviewer always knows where a finding came from.
The four layers
| Layer | Contents |
|---|---|
| Observed | Live tables and enforced keys from the database |
| Modeled | Per-table status, field diffs, impacted operations |
| Proposed | Ordered additive migration plan with blockedBy
|
| Inferred | Link tables, open questions, safeguards |
The first two describe what is, the last two describe what could change and what cannot yet be confirmed.
How each layer feeds the next
- Observed reads the live schema, so the baseline is real rather than assumed.
- Modeled compares each table against the derived model and names its status and diffs.
- Proposed turns the differences into an ordered plan, with
blockedBysequencing the steps. - Inferred keeps the link tables, open questions, and safeguards attached rather than hiding them.
Because the plan starts from Observed, a migration is not built against a guessed baseline. The enforced keys in the live database are part of the evidence, and the impacted operations connect the table changes back to the API.
Walk the layers on a real change and the order earns its keep. The Observed layer first confirms the table and the foreign key as they exist, so the team is not arguing from a remembered schema. The Modeled layer then marks the one table that drifts and names the field that differs, while the matched tables drop out of the work. The Proposed layer orders the new column after its table and uses blockedBy to keep the key from being created early, and the Inferred layer holds the link table until a reviewer confirms the cardinality. At each step the evidence is a different layer, and a reviewer can point to the exact stage where an assumption entered.
Where open questions and safeguards sit
The Inferred layer is deliberately separate from the Proposed layer, because an inferred link table or an unresolved cardinality is not the same confidence as a table observed in the database.
- A link table inferred from the schemas stays labeled as inferred.
- An open question marks logic that could not be resolved unambiguously.
- A safeguard names a protection the plan should respect.
Keeping those in their own layer prevents an inference from being treated as a confirmed fact, and it keeps the migration honest. This is the same boundary that keeps a static signal from being written as a guarantee.
The ER diagram reflects the node state against this reconciliation, and bidirectional impact analysis connects the API operations to the tables. The generated SQL is still never executed by the modeling package.
Powerduck keeps the four layers visible in the desktop so the evidence, the comparison, the plan, and the open questions stay distinct.
Frequently asked questions
What does the Observed layer read? The live tables and enforced keys, giving the reconciliation a real baseline.
Why is the Inferred layer separate? Inferred link tables and open questions are lower confidence than observed or modeled facts, so they should not be treated as confirmed.
What does blockedBy do? It sequences the additive migration so a step that depends on another cannot run out of order.
The bottom line
The four layers move in order from the live database to a guarded proposal: Observed establishes the real tables, Modeled names the status and diffs, Proposed builds the additive plan with blockedBy, and Inferred keeps link tables, open questions, and safeguards visible. Keeping these states separate stops an inference from being mistaken for a fact and keeps the migration grounded. The plan still never executes itself. Read more in the API data model guide.
Top comments (0)