Documentation
¶
Overview ¶
Package plan defines the machine-readable dry-run plan report: the stable JSON contract an operator or orchestrator consumes to decide whether and how a change would execute. Both front doors emit it — the imperative migrate --dry-run path and the declarative diff path — so a consumer parses one shape regardless of how the plan was derived.
Index ¶
Constants ¶
const FormatVersion = 2
FormatVersion identifies the report contract. A consumer must reject a report whose version it does not understand instead of guessing at the field semantics. Version 2 added the guidance field on rewrite-required statements.
Variables ¶
This section is empty.
Functions ¶
func Fingerprint ¶
Fingerprint computes the plan's stable identity: "sha256:" plus the hex digest over what would execute — each statement's canonical SQL, route, backend, disposition, and exec_sql, in plan order. Explanatory fields (decisions, kind, destructive) are excluded, so a reworded reason does not change identity but a rerouted or resequenced plan does. The exact serialization is part of the contract (docs/plan-report.md) and changes only with a format_version bump. This is a plan identity, not a schema fingerprint: it never participates in schema-state comparison.
func RefuseUnsupportedPartitionedParent ¶
RefuseUnsupportedPartitionedParent marks executable statements as refused when partition-aware admission rejects their execution steps.
Types ¶
type Report ¶
type Report struct {
// FormatVersion is the report contract version; always FormatVersion.
FormatVersion int `json:"format_version"`
// Source is the front door that derived the plan.
Source Source `json:"source"`
// Schema is the target schema; empty when the submitted statement did
// not qualify one.
Schema string `json:"schema,omitempty"`
// Table is the target table; empty when the statement has no single
// table target (index maintenance).
Table string `json:"table,omitempty"`
// ServerVersion is the PostgreSQL server_version the plan was derived
// against. Classification is version-sensitive, so a stored or
// forwarded report names the server whose rules produced it; empty
// only for sources that never connected.
ServerVersion string `json:"server_version,omitempty"`
// TableExists reports whether the live table was found. Set by every
// source that introspects the target (diff, and the alter dry run);
// nil means the plan has no single table target to introspect. For
// diff, false means the statements are the full desired schema; for
// an alter dry run, false means the plan was classified from zero
// facts and executing it would fail.
TableExists *bool `json:"table_exists,omitempty"`
// Disposition is the aggregate disposition across all statements:
// what would happen if the engine executed this plan now.
Disposition router.Disposition `json:"disposition"`
// Reason is the typed refusal cause when target facts make an otherwise
// executable routed plan unsafe.
Reason verdict.Reason `json:"reason,omitempty"`
// Fingerprint is the plan's stable identity (see Fingerprint). An
// approver pins it when the plan is reviewed; an executor recomputes it
// at apply time and refuses on mismatch — that is how "the plan a
// reviewer approves is the plan that executes" is enforced across
// storage and forwarding.
Fingerprint string `json:"fingerprint"`
// Statements is the ordered plan; empty means there is nothing to do.
Statements []Statement `json:"statements"`
}
Report is the dry-run plan for one change against one table.
type Source ¶
type Source string
Source identifies which front door derived the plan.
const ( // SourceAlter marks a plan derived from a submitted DDL statement // (migrate --alter --dry-run): the classify-and-route pipeline with // the diff step skipped. SourceAlter Source = "alter" // SourceDiff marks a plan derived from a desired-state schema diff // (diff --desired): the ordered statements that converge the live // table on the desired schema. SourceDiff Source = "diff" )
type Statement ¶
type Statement struct {
// SQL is the statement in the engine's canonical rendering: parsed and
// reprinted through the PostgreSQL deparser, whichever front door
// derived it. It is never a verbatim echo of the submitted text, so
// the same change carries the same string through either door.
SQL string `json:"sql"`
// Kind classifies a diff-derived statement so a consumer can gate
// whole classes of change (see schemadiff.ChangeKind). Empty for the
// alter source: a submitted statement may carry several operations and
// has no single kind.
Kind schemadiff.ChangeKind `json:"kind,omitempty"`
// Destructive marks statements that discard live structure — a dropped
// column, constraint, or index. It is derived from the classifier's
// decisions, so both sources report it identically; it is always
// emitted, never omitted, because a safety flag a consumer gates on
// must be explicit even when false.
Destructive bool `json:"destructive"`
// Route is the planner's aggregate route for the statement.
Route planner.Route `json:"route"`
// Backend is the assigned execution strategy; empty for refusals.
Backend router.Backend `json:"backend,omitempty"`
// Disposition is what execution would do with the statement now.
Disposition router.Disposition `json:"disposition"`
// Reason is the typed cause when target facts refuse this statement.
Reason verdict.Reason `json:"reason,omitempty"`
// Decisions are the planner's per-operation classifications.
Decisions []planner.Decision `json:"decisions"`
// ExecSQL is the ordered SQL the native backend would run — the safer
// sequence when the planner constructed one. Empty for non-native
// routes.
ExecSQL []string `json:"exec_sql,omitempty"`
// Execution is the typed execution contract for ExecSQL
// (planner.Execution), present exactly when ExecSQL is. A consumer
// that runs the statements itself branches on it — it is what says
// each step runs in its own implicit transaction, never inside an
// enclosing transaction block. It is derived from ExecSQL's presence,
// so it is excluded from the fingerprint like the other explanatory
// fields.
Execution planner.Execution `json:"execution,omitempty"`
// Guidance is the typed manual path for a rewrite-required refusal,
// drawn from the suggest contract's Guidance vocabulary
// (docs/suggest-report.md): the engine will not run the statement, and
// this names what to do instead. Present exactly when Disposition is
// rewrite-required. Explanatory, so it is excluded from the
// fingerprint.
Guidance suggest.Guidance `json:"guidance,omitempty"`
}
Statement is one planned statement: the SQL, its classification, and what execution would do with it now.
func FromRouted ¶
FromRouted converts one routed statement into a plan statement. Destructive is derived from the classifier's decisions — one destructive operation makes the statement destructive — so every source that routes through the planner reports it identically by construction. A rewrite-required statement additionally carries the typed manual path (Guidance), derived through the same mapping the suggest report uses; a rewrite-required decision with no known guidance is a contract violation and fails closed.