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

V06 of the package DDL: the conditional, in-place rename of the durable
noun (ADR-0011 decision 3).

`0.12.0` renames the thing this package stores from a *run* to an
*execution*, everywhere: the modules, the adapter callbacks, the tables
and the columns. V01-V05 are rewritten to the new noun, so a database
built at `0.12.0` or later holds `statifier_executions` with an
`execution_id` column and has never held anything else. A database this
package built before `0.12.0` holds `statifier_runs` with a `run_id`
column. This version is what brings the second kind of database to the
first.

## Two databases, one version

`up/1` asks the repo whether the resolved **old** table name is there.

- **It is not** - the fresh install. Nothing is renamed; `up/1` is a
  no-op. V01 already created the execution names directly.
- **It is** - the upgraded install. The table, both columns, the two
  unique indexes over them and (on Postgres) the `metadata` GIN index
  are renamed **in place**.

Either way V06 is the version this package now expects
(`StatifierPersistence.Ecto.Migrations.expected_version/0` answers `6`);
the package writes no versions table and no marker row, so the map entry
and the host's own `schema_migrations` timestamp are the whole of the
record that it ran.

**No data is copied.** Every statement here is a catalog operation - a
table, column or index rename - and not one of them reads or writes a
row. An upgraded install's stored ids are therefore untouched: rows
written before `0.12.0` keep their `run_`-prefixed surrogate keys while
new rows get `exec_`-prefixed ones, and both are valid opaque strings
that coexist permanently (ADR-0011 decision 2).

## Each object is asked about separately

The record's question - does the resolved old table name exist - is what
tells the two installs apart, and it is asked first. Each individual
rename is then guarded by the existence of the object it renames, which
is what makes the version correct on the two shapes the question alone
does not separate:

- A host that gave a `tables:` override for this table has the same name
  on both sides of the rename, so the table rename is skipped and the
  column rename is what moves it forward.
- A host that capped its migrations below V05 has no input log yet, so
  there is no `run_id` column there to rename; a host that capped below
  V03 has no GIN index.

## The probe runs late

The existence check goes through `Ecto.Migration.execute/1`'s function
form rather than running in the body of `up/1`, for the reason V04
records: Ecto's migration runner queues a migration's commands and runs
them at the end, so asking the database anything from the body of `up/1`
reaches it before V01 has created the tables, on every fresh database. A
queued function runs in order, after the DDL ahead of it.

## Adapters other than Postgres

Renaming a table and renaming a column are ordinary SQL on both
backends this package tests (ADR-0005's Postgres harness and the SQLite
repo of sp-11w). Two things differ:

- The `metadata` GIN index is Postgres-only - V03 creates it only there
  - so its rename is skipped off Postgres, under the same exact-match
  adapter check V03 and V04 use.
- SQLite has no `ALTER INDEX ... RENAME TO`. Off Postgres the two unique
  indexes are therefore dropped and recreated under their new names,
  which is still no data copy: an index is derived structure, this
  package reads and writes no row to rebuild it, and the end state is
  the index V01 and V05 declare.

## What V06 does not rename: stored child linkage

A durable subchart child carries its linkage to its parent in the
`metadata` column, under the reserved key `"parent_run_id"` before
`0.12.0` and `"parent_execution_id"` from `0.12.0` on
(`StatifierPersistence.Execution.Linkage`). V06 renames **no stored
value**, by decision: it is a catalog operation and nothing here reads
or writes a row (ADR-0011 decision 3; the consequence below is item 1
of that record's acceptance Note of 2026-09-13).

The consequence, stated plainly rather than left to be discovered: a
child that was **in flight** when the host upgraded still carries the
old key, so `Linkage.from_metadata/1` answers `:no_linkage` for it and
its completion no longer settles its parent's fan-out. A host therefore
**drains its in-flight children before upgrading to `0.12.0`** - let
every durable subchart child reach a terminal status under `0.11.x`,
then upgrade. Children created at `0.12.0` or later carry the new key
and are unaffected, and a completed child's stored metadata is history
that nothing reads for linkage again.

## Rolling back

`down/1` is a **no-op**, and that is a decision rather than an omission
(item 2 of ADR-0011's acceptance Note of 2026-09-13). ADR-0011 decision 3
describes the earlier design, in which `down/1` renamed back and a
rollback below V06 on an upgraded install was therefore unsupported;
that Note supersedes both halves of that bullet: the down is a no-op,
and only a rollback to pre-`0.12.0` code stays unsupported.

Under the full cutover there is nothing for it to restore. V01-V05 are
rewritten to the execution names, so on `0.12.0` code every database
this package can reach - fresh or upgraded - is on those names, and
they are the names V01-V05 drop. Renaming back would only be
meaningful under a *downgrade to pre-`0.12.0` code*, and that is
exactly what the record declares unsupported: an install that must
return to the retired names restores from a backup, or migrates with
`0.11.x`'s own migrations.

Making it a no-op is also the only shape that survives the host
migration pattern this package recommends. A host that writes one
migration per package version rolls back one version per
`Ecto.Migrator` step, so a rename back would run in its own step and
the V05, V04, V03 and V01 steps behind it would then name objects that
are no longer there. A condition inside a single
`StatifierPersistence.Ecto.Migrations.down/1` call cannot see across
those steps, which is the defect this ruling removes.

So `down(for: Host, version: 6)` leaves the database exactly as it is,
and a full `down(for: Host)` drops everything this package owns - on a
fresh install and on an upgraded one alike, under one call or one call
per version. The way down past V06 is a drop, not a downgrade.

# `down`

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

Does nothing. Rolling back below `0.12.0` code is unsupported, and
V01-V05 drop the tables under the execution names either way - see the
moduledoc.

# `up`

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

Renames the pre-`0.12.0` names to the execution names, in place, when
this database still carries them; a no-op when it does not.

---

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