# `StatifierPersistence.Ecto.Migrations.V03`
[🔗](https://github.com/riddler/statifier_persistence/blob/v0.25.1/lib/statifier_persistence/ecto/migrations/v03.ex#L2)

V03 of the package DDL: the executions table's nullable `outcome_blob`
column, and a GIN index on `metadata`.

## `outcome_blob`

An execution's own answer, kept where a reader that has never seen
the execution live can find it. A durable subchart child's completion used to exist
only on the step that produced it - a stored record carries no
donedata - which is fine while a completion is answered immediately
and not fine once N of them have to be collected and assembled in
index order. The column is written once, at the child's completion,
by `StatifierPersistence.Storage.update_execution_status/4`.

Nullable, because almost no execution has one: an ordinary execution
answers nobody, and an execution that fails at creation never
completes.

It is a **blob** column, not a `jsonb` one, and the difference is a
disclosure decision rather than a typing convenience. `metadata` is
restricted to host identities (ADR-0006 decision 2) precisely because
`:blob_type` encryption does not reach a queryable column. A donedata
payload carries whatever the chart's author put in it, so it belongs
on the side of that line the encryption reaches: `outcome_blob` joins
the three existing blob columns and takes the configured `:blob_type`
with them.

## The `metadata` GIN index

V02 shipped no index and said why: which pairs a host queries by is
the host's call (ADR-0006 decision 4). Fan-out settlement changes the
arithmetic. Every child completion asks "are all N of my siblings
terminal?", which is the same `jsonb` containment query the cascade
already issues, so one fan-out of N children issues N of them; without
an index each is a sequential scan of the host's whole executions table.
That is not a cost a host can be left to discover in production, so
this package now ships the index the query it issues needs.

`jsonb_path_ops` rather than the default `jsonb_ops`: containment
(`@>`) is the only operator either query uses, and the path-ops
opclass serves exactly that, with a smaller index. A host that needs
the wider operator set, or an expression index on particular keys,
still adds its own - ADR-0006 decision 4's clause is narrowed by this
migration, not withdrawn, and the record carries a dated Note saying
so.

## Adapters other than Postgres

`GIN` and `jsonb_path_ops` are Postgres spellings. `up/1` therefore
creates the index **only** when the migration's repo runs on
`Ecto.Adapters.Postgres`, and `down/1` drops it under the same
condition; on any other adapter both steps are skipped and the
migration otherwise runs to completion. Before that check existed the
whole of V03 rolled back on a SQLite repo - `ecto_sqlite3` raises
`ArgumentError` from `using:` - which took the `outcome_blob` column
with it and left such a host unable to run this package's DDL at all
(sp-11w).

The column is created on every adapter, because it is a nullable
binary column and every adapter has one. That is what keeps
`StatifierPersistence.Storage.Ecto.supports_execution_outcome?/1` true
everywhere.

Skipping the index is not the same as the index not mattering. What
the index serves - the `jsonb` containment queries
`StatifierPersistence.Storage.Ecto.list_executions_by_metadata/2` and
`list_execution_states_by_metadata/2` issue - is Postgres-only SQL in its
own right, so an adapter that cannot take the index cannot run the
queries either and says so: that adapter's metadata support is
declared false, and a durable subchart or fan-out over such a store is
refused at open rather than started and left unsettleable. sp-5lm
tracks the Ecto adapter's Postgres-only surface.

# `down`

```elixir
@spec down(StatifierPersistence.Ecto.Config.t()) :: :ok
```

Drops the `metadata` GIN index and the executions table's
`outcome_blob` column.

# `up`

```elixir
@spec up(StatifierPersistence.Ecto.Config.t()) :: :ok
```

Adds the executions table's nullable `outcome_blob` column and the
`metadata` GIN index per `config`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
