Published in openvibe-contracts v0.53.0 (docs/adr/ADR-028-expand-migrate-contract.md), rendered as is.

ADR-028: Expand, migrate, contract — schema changes that survive a rollback

Status: Accepted 2026-09-25; enforced first in OpenVibe.Live (test/destructive-migrations.test.js, test/rollback-newer-writes.test.js). Roadmap WS-P tasks 12 and 13.

Context and current evidence

Every service keeps its state in SQLite and changes its schema at boot (CREATE … IF NOT EXISTS, ADD COLUMN, and ledgered data migrations such as Live's server/db/migrations.js). Production rolls back by switching the release (Live's release layout, ovhost deploy), never by restoring the database: the older release starts on the database the newer one migrated and wrote to. A change that removes or renames a table or column, or rewrites a value into a shape the older code cannot read, therefore makes the rollback fail exactly when it is needed. Live's history has five one-time table rebuilds (copy every column into <table>_new, drop, rename) that were safe because they kept every column, but nothing checked that.

Decision

A schema change is made in up to three releases, each deployable and each rollback-safe on its own:

  1. Expand — add only: new tables, new nullable or defaulted columns, new indexes. Old and new code both work on the result.
  2. Migrate — write both shapes and backfill (a ledgered migration: transactional, idempotent, adopt/DEFER where needed). Reads move to the new shape. Still nothing is removed.
  3. Contract — remove or rename (DROP TABLE, DROP COLUMN, RENAME COLUMN, RENAME TO), and stop writing the old shape, only after a release in which nothing reads it, with a backup taken first. A contract step is a dated entry in the plan's calendar (section 10), and it is listed with that entry where the service's check requires it.

The supported rollback window is 7 days: any release of the last week must boot and work on today's database.

Checks. Each service with a schema adds, as it adopts this ADR:

Alternatives considered

Migration consequences

Existing destructive statements are recorded, not rewritten. Upcoming contract steps already in the calendar (Live's users.email/password_hash columns in WS-B task 2, C-73's table drop, C-75's boot backfill) follow this ADR: each runs after a release with no reads, with a backup.

Rollback

The checks are tests; removing a test file reverts them. The rule itself costs one extra release per destructive change.

Acceptance tests