StatifierPersistence.Ecto (StatifierPersistence v0.21.0)

Copy Markdown View Source

Compile-time Ecto configuration on the host's own module (ADR-0002).

A host declares its persistence module once:

defmodule MyApp.Persistence do
  use StatifierPersistence.Ecto, repo: MyApp.Repo
end

and gets, with zero further options: the resolved configuration readable via MyApp.Persistence.__statifier_persistence__/1, and four Ecto schema modules - MyApp.Persistence.Chart, MyApp.Persistence.Position, MyApp.Persistence.Execution, MyApp.Persistence.Input - over the statifier_charts / statifier_positions / statifier_executions / statifier_inputs tables with UXID string primary keys (chart_ / pos_ / exec_ / input_ prefixes).

Every knob is compile-time, on this use, never in application env (ADR-0002 decision 3), and the migrations helper consumes the same resolved configuration so schemas and DDL cannot disagree. See StatifierPersistence.Ecto.Config for the options (:key, :table_prefix, :tables, :prefix, :blob_type, :leading_columns).

The engine identity columns (content_hash, session_id, execution_id) are stored verbatim as strings and are never touched by the configured key scheme - ADR-0002 decision 1.

The chart schema also carries retired_at and retired_by, the two tombstone columns V07 adds (ADR-0012 decision 6). Both are nil on every chart that has not been retired, which is every chart until a host asks for one to be; a row carrying a retired_at has had its identity_blob and chart_blob nulled, and both chart doors answer for it with the retired arm rather than with its bytes.

The execution schema also carries ended_at, the column V08 adds: NULL until the row takes its first terminal write with the column in place, then that write's time, never moved or cleared afterwards (StatifierPersistence.Executions.ended?/1 names where that and the status can disagree).

The execution schema also carries metadata, the optional opaque map of host identities ADR-0006 grants, as a jsonb column (V02 of the migrations helper). It holds identities only, never personal data: :blob_type does not reach it, so anything filed there is at rest in the clear no matter how the blob columns are configured.

:blob_type reaches the payload columns and nothing else: identity_blob, chart_blob, position_blob, outcome_blob, and input_blob on the inputs table (ADR-0010 decision 4). A host wanting encryption at rest for those columns passes a custom Ecto.Type or Ecto.ParameterizedType there and gets it applied with zero further wiring. The identity and lookup columns (content_hash, session_id, execution_id, status, failure, and the input log's seq and door) stay plain regardless - the identity guard and the unique indexes depend on reading them back verbatim, and metadata stays jsonb regardless for the same reason: it is the column a host queries (ADR-0006 decision 3).

The inputs table is ADR-0010's per-execution input log: one row per input the interpreter saw, carrying the execution it belongs to, its dense zero-based seq, the public door it entered by, and the opaque input_blob. A nil input_blob is decision 6's closed marker. The log holds document payload - an event's data is the host's own values - which is why :blob_type reaches input_blob and why turning the log on is a data-retention decision rather than a debugging switch (StatifierPersistence.Storage.Adapter's moduledoc).