The migration version bump lands in the core dbversions table while
the DDL lands in ext_libra — the two writes are not atomic. A failed
bump re-runs the whole migration on next boot; bare
CREATE/ALTER/INSERT then crashes the extension until manual
dbversions surgery.
- CREATE TABLE / CREATE INDEX -> IF NOT EXISTS
- ALTER TABLE ADD COLUMN -> _alter_add_column_safe (same swallow
pattern as the events/withdraw fork migrations)
- seed INSERTs (default accounts, virtual parents, default roles) ->
ON CONFLICT (name) DO NOTHING
Tests run the chain twice against a fresh SQLite DB (full-chain rerun
and per-migration rerun); both fail against the previous migrations.
Addresses CODE-REVIEW-2026-06 findings #3 and #12.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>