Run report schema

SyncReport.to_dict() projects a whole run as plain, JSON-serialisable data — dict, list, str, int, bool, and None only, so json.dumps(report.to_dict()) works directly. It is the machine-readable view of a run, for CI gates, run-history persistence, and structured logging. The human-readable views are render_report and render_diff.

TableRunReport.to_dict() projects a single table’s record, the same object that appears in the run-level tables list.

Stability

The fields and enumerated values below are a public contract, versioned by schema_version. Adding a field is backwards-compatible; renaming or removing one, or renaming an enumerated value, is a breaking change and increments schema_version. The projection is deterministic: tables appear in run order, and changes and statements in action-plan order, so two projections of the same report compare equal — successive dry-run outputs can be diffed.

Version 2 renamed the planning-phase status from VALIDATION_FAILED to PLANNING_FAILED and the corresponding failure phase from VALIDATION to PLANNING.

Run-level fields

SyncReport.to_dict() returns:

Field

Type

Meaning

schema_version

int

Version of this payload schema; currently 2

started_at

str

ISO 8601 timestamp when the run began

ended_at

str

ISO 8601 timestamp when the run ended

dry_run

bool

Whether execution was skipped

has_changes

bool

True if any table has a planned change

has_failures

bool

True if any table failed a phase

tables

list[dict]

Per-table records, in run order (see below)

Table-level fields

Each entry in tables, and the whole of TableRunReport.to_dict():

Field

Type

Meaning

name

str

Dotted, unquoted qualified name, e.g. cat.schema.orders

status

str

A TableRunStatus value (SUCCESS, PLANNING_FAILED, …)

has_changes

bool

True if this table has a planned change

has_failures

bool

True if this table failed a phase

changes

list[dict]

Summaries of the planned changes, in plan order (see below)

planned_sql_statements

list[str]

Full compiled DDL the plan lowers to, in order

failures

list[dict]

Failure records, in phase order (see below)

execution

dict | None

Execution counts, or None on a dry run or a skipped table

Change records

Each entry in changes summarises part of a planned change, derived from the same interpretation the text renderers use. They are human-oriented summaries, not one record per plan action (a table creation expands into several), and not a complete description of the change — the authoritative, complete description is planned_sql_statements:

Field

Type

Meaning

kind

str

Change category: columns, keys, clustering, properties, tags, comments

operation

str

add, remove, or change

subject

str

What the change targets, e.g. a column name or table: '...'

detail

str

Extra detail, e.g. Integer Long; empty when there is none

Failure records

Each entry in failures:

Field

Type

Meaning

phase

str

The phase that produced it: READ, PLANNING, FOREIGN_KEY, EXECUTION

type

str

The concrete failure class name, e.g. ValidationFailure

message

str

The rendered failure message

Execution record

When a table executed, execution is:

Field

Type

Meaning

applied

int

Statements that ran successfully

total

int

Statements planned (planned_sql_statements)

It is None for a dry run and for any table skipped by an earlier-phase failure. Execution runs statement by statement and stops at the first failure, so applied < total means the trailing statements were never attempted.

The planned SQL property

Alongside the projection, SyncReport.planned_sql_statements is a dict[str, tuple[str, ...]] mapping each table’s dotted name to its compiled statements, omitting tables with no planned change. It is the same statement text that appears per table under planned_sql_statements in to_dict().

Planned is not executed: a table blocked after planning (for example by a foreign-key dependency failure) still reports the SQL its plan compiles to. Whether the statements ran is answered by execution and has_failures.

See how to gate schema changes in CI for the projection in use.