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/1is 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
metadataGIN 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_idcolumn 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
metadataGIN 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 (RQ-SF041-22, ruled 2026-09-12).
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
(RQ-SF041-25, ruled 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; the ruling supersedes
both halves of that bullet, and the record's own dated Note is what
records it.
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.
Summary
Functions
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.
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.
Functions
@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.
@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.