Migrations
A3S ORM migrations form a forward-only version sequence. Each migration has a version, name, and up_sql. The runner sorts, validates, and computes a SHA-256 checksum before execution.
Define and run migrations
MigrationReport::is_up_to_date() returns true when nothing new was applied.
Version rules
- A version cannot be empty.
- Versions only allow ASCII letters, digits, dots, underscores, and hyphens.
- One run cannot contain duplicate versions.
- Names and SQL cannot be blank after trimming.
- Versions sort as strings, so use fixed-width identifiers such as
001and002.
History and drift detection
Built-in backends maintain a3s_orm_migrations. Each applied version records its SHA-256 checksum.
On every run:
- A version stored in the database must still exist in source.
- Applied SQL checksums must remain unchanged.
- Only unapplied versions execute.
- Schema changes and history rows commit in one transaction.
Changing or removing applied migrations returns ChecksumMismatch or MissingSourceMigration. Add a new forward migration instead of rewriting history.
Read-only serving admission
Serving processes can verify their required schema without DDL authority. verify_required reads the existing ledger without creating tables, taking migration locks, or writing rows. Every required migration must exist with the same checksum. Later applied migrations are admitted so an older binary can remain active during an explicitly compatible rolling upgrade.
Give the deployment migrator DDL authority and keep serving roles read-only. The application still owns the decision that later schema versions are expand-compatible with the running binary.
Concurrent locks
SQLite uses the executor gate with BEGIN IMMEDIATE. PostgreSQL acquires a transaction-scoped advisory lock in the same transaction and uses a bounded wait.
Use distinct lock ids when independent application schemas share one database. Lock deadlines classify as LockContention.
Rolling deployment
- Expand: add nullable columns, compatible defaults, tables, or indexes.
- Migrate: deploy code that reads both shapes and backfill in bounded batches outside schema migration.
- Verify: prove old and new application versions can read and write while observing errors and backfill metrics.
- Contract: remove compatibility structures in a later migration after old versions are fully drained.
Do not combine expansion with an incompatible contract step.