verdict

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 19, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package verdict is the engine's structured outcome contract: every migrate invocation ends in exactly one verdict — executed natively, refused with a typed reason and, where one exists, a safer native idiom, or failed during execution with the executor's stable outcome code and a disclosure of what committed before the failure. Refusals use a distinct exit code from operational errors. This type is the seam a future orchestrator adapter maps onto SchemaBot's ExecutionModeBlocked.

Index

Constants

View Source
const ExitCodeRefused = 2

ExitCodeRefused is the process exit code for a refusal verdict — distinct from 1, which means an operational error (could not connect, bad flag, SQL error). Automation branches on the difference.

Variables

View Source
var ErrRefused = errors.New("refused")

ErrRefused is the sentinel the CLI returns after printing a refusal verdict, so the entry point can map it to ExitCodeRefused.

Functions

This section is empty.

Types

type Cause

type Cause string

Cause narrows ReasonBudgetExceeded to the budget that was exceeded, so automation can branch on which limit fired without parsing prose.

const (
	// CauseNone is the zero cause for verdicts that are not budget refusals.
	CauseNone Cause = ""
	// CauseLockBudget: the lock was not granted within lock_timeout; nothing
	// was executed.
	CauseLockBudget Cause = "lock-budget"
	// CauseStatementBudget: the statement ran past statement_timeout and was
	// cancelled; the change needs a rewrite.
	CauseStatementBudget Cause = "statement-budget"
)

The budget causes a refusal can carry.

type Outcome

type Outcome string

Outcome is what happened to the submitted change.

const (
	// OutcomeExecuted means the change ran and committed natively within
	// its budgets.
	OutcomeExecuted Outcome = "executed-natively"
	// OutcomeRefused means the change was not executed; Reason says why.
	OutcomeRefused Outcome = "refused"
	// OutcomeFailed means execution was attempted and failed: an
	// operational error, not a refusal — the process still exits 1. Code
	// carries the executor's stable outcome code, and for a mid-sequence
	// failure FailedStep and ExecutedSQL disclose the failed step and the
	// committed prefix whose state remains, so automation can distinguish
	// "nothing happened" from "partial state left behind".
	OutcomeFailed Outcome = "failed"
)

The outcomes a migrate run can end in.

type Reason

type Reason string

Reason is the typed cause of a refusal. Reasons are flat kebab-case tokens — they are what automation switches on; prose belongs in Detail.

const (
	// ReasonNone is the zero reason carried by an executed verdict.
	ReasonNone Reason = ""
	// ReasonUnsupportedStatement: only ALTER TABLE is supported.
	ReasonUnsupportedStatement Reason = "unsupported-statement"
	// ReasonIndexStatement: index maintenance has a native safe idiom
	// (CONCURRENTLY) and is never attempted here.
	ReasonIndexStatement Reason = "index-statement"
	// ReasonTableTooLarge: the size guard skipped the optimistic attempt.
	ReasonTableTooLarge Reason = "not-native-safe-table-too-large"
	// ReasonInsufficientPrivileges: the connected role lacks the access
	// the change needs; Detail names the exact missing GRANT (see
	// docs/engine-role.md).
	ReasonInsufficientPrivileges Reason = "insufficient-privileges"
	// ReasonUnsupportedPartitionedParent: the routed plan builds an index
	// on a partitioned parent, for which the required partition-aware
	// online sequence is not implemented.
	ReasonUnsupportedPartitionedParent Reason = "unsupported-partitioned-parent"
	// ReasonBudgetExceeded: the optimistic attempt exceeded its lock or
	// statement budget and was cancelled.
	ReasonBudgetExceeded Reason = "not-native-safe-budget-exceeded"
	// ReasonRewriteRequired: the submitted form blocks and must run as a
	// safer native sequence, but the planner could not construct one (a
	// multi-operation statement, or a pattern it cannot build). Running
	// the submitted form would falsify the plan's own reason, so the
	// engine refuses instead.
	ReasonRewriteRequired Reason = "not-native-safe-rewrite-required"
	// ReasonBackendUnavailable: the change routes to an execution strategy
	// this build does not implement (copy-and-swap).
	ReasonBackendUnavailable Reason = "backend-unavailable"
)

The refusal reasons Phase 1 can emit.

type Verdict

type Verdict struct {
	// Outcome is what happened.
	Outcome Outcome `json:"outcome"`
	// Reason is the typed refusal cause; empty when executed.
	Reason Reason `json:"reason,omitempty"`
	// Cause narrows a budget refusal to the budget that fired; empty
	// otherwise.
	Cause Cause `json:"cause,omitempty"`
	// Code is the executor's stable outcome code (executor.OutcomeCode)
	// carried by a failed verdict — flat kebab-case, part of the executor's
	// report contract. It stays a plain string here so this contract
	// package does not depend on the executor. Empty unless Outcome is
	// OutcomeFailed.
	Code string `json:"code,omitempty"`
	// FailedStep is the 1-based position of the sequence step that failed,
	// matching the numbering the planner's partial-failure contracts use;
	// zero when the failure was not a mid-sequence one (a single-statement
	// attempt rolls back and commits nothing).
	FailedStep int `json:"failed_step,omitempty"`
	// FailedStepSQL is the failed step's statement — the step the planner's
	// partial-failure contract says a retry resumes from.
	FailedStepSQL string `json:"failed_step_sql,omitempty"`
	// Attempts is how many bounded attempts ran before a lock-budget
	// refusal, so automation can tell an exhausted bounded retry from a
	// single cancelled attempt; zero for every other verdict.
	Attempts int `json:"attempts,omitempty"`
	// Statement is the submitted SQL.
	Statement string `json:"statement"`
	// Table is the target table (schema-qualified when the statement was),
	// when the statement has one.
	Table string `json:"table,omitempty"`
	// Detail is the human explanation: why refused, or what committed.
	Detail string `json:"detail,omitempty"`
	// SaferIdiom is a native alternative to the refused statement, when one
	// exists (e.g. CREATE INDEX CONCURRENTLY, ADD CONSTRAINT ... NOT VALID).
	SaferIdiom string `json:"safer_idiom,omitempty"`
	// ExecutedSQL is the ordered SQL the engine actually ran and committed.
	// On an executed verdict it is the substituted safer native sequence
	// (empty when the submitted form ran as-is — a non-empty value is what
	// tells automation a substitution happened). On a failed verdict it is
	// the committed prefix that remains: empty means nothing committed.
	ExecutedSQL []string `json:"executed_sql,omitempty"`
	// Forced reports that --force overrode the engine's routing: the
	// submitted form ran as-is instead of a safer substitution or a
	// strategy refusal. It is the machine-readable audit record of the
	// override.
	Forced bool `json:"forced,omitempty"`
}

Verdict is the structured outcome of one migrate invocation.

func (Verdict) JSON

func (v Verdict) JSON() (string, error)

JSON renders the verdict as a single JSON object.

func (Verdict) String

func (v Verdict) String() string

String renders the verdict for humans.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL