From a36cae4517b68460e72da2deecc967c422c6645b Mon Sep 17 00:00:00 2001 From: dev_agent Date: Sat, 3 Oct 2026 00:51:50 -0400 Subject: [PATCH] Make the placeholder migration an immutable 0000_bootstrap The runner skips versions already recorded by filename, so replacing the contents of the applied 0001_init.sql placeholder with the real schema would leave upgraded databases without the new tables. Rename it to 0000_bootstrap.sql, document it as a permanent no-op, and leave 0001_init.sql free for the v1 schema as a brand-new version. Add a test that migrates with the embedded set, then adds a fixture 0001_init.sql and proves it applies on the existing database. Co-Authored-By: Claude Opus 5.5 --- internal/store/migrate_test.go | 31 +++++++++++++++++++++++++++++-- migrations/0000_bootstrap.sql | 4 ++++ migrations/0001_init.sql | 2 -- 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 migrations/0000_bootstrap.sql delete mode 100644 migrations/0001_init.sql diff --git a/internal/store/migrate_test.go b/internal/store/migrate_test.go index 216fc75..35a0824 100644 --- a/internal/store/migrate_test.go +++ b/internal/store/migrate_test.go @@ -2,6 +2,7 @@ package store import ( "context" + "io/fs" "strings" "testing" "testing/fstest" @@ -173,7 +174,33 @@ func TestMigrateEmbeddedMigrations(t *testing.T) { if err := Migrate(context.Background(), s.Writer, migrations.FS); err != nil { t.Fatal(err) } - if got := versions(migrationRows(t, s)); !strings.HasPrefix(got, "0001_init") { - t.Errorf("versions = %q, want 0001_init first", got) + if got := versions(migrationRows(t, s)); got != "0000_bootstrap" { + t.Errorf("versions = %q, want 0000_bootstrap", got) + } +} + +func TestMigrateEmbeddedThenNewMigrationApplies(t *testing.T) { + ctx := context.Background() + s := openTestStore(t) + if err := Migrate(ctx, s.Writer, migrations.FS); err != nil { + t.Fatal(err) + } + bootstrap, err := fs.ReadFile(migrations.FS, "0000_bootstrap.sql") + if err != nil { + t.Fatal(err) + } + // A later build adds 0001_init.sql alongside the unchanged bootstrap. + upgraded := fstest.MapFS{ + "0000_bootstrap.sql": {Data: bootstrap}, + "0001_init.sql": {Data: []byte("CREATE TABLE later (id INTEGER PRIMARY KEY);")}, + } + if err := Migrate(ctx, s.Writer, upgraded); err != nil { + t.Fatal(err) + } + if got := versions(migrationRows(t, s)); got != "0000_bootstrap,0001_init" { + t.Errorf("versions = %q, want 0000_bootstrap,0001_init", got) + } + if !tableExists(t, s, "later") { + t.Error("table from 0001_init was not created") } } diff --git a/migrations/0000_bootstrap.sql b/migrations/0000_bootstrap.sql new file mode 100644 index 0000000..a21b38f --- /dev/null +++ b/migrations/0000_bootstrap.sql @@ -0,0 +1,4 @@ +-- 0000_bootstrap: immutable no-op bootstrap migration. It lets the migrations +-- embed compile and proves the runner end to end. Never edit or remove it: +-- applied versions are recorded by filename and never re-run. The initial v1 +-- schema arrives as a new migration, 0001_init.sql (Feature 02 task 3). diff --git a/migrations/0001_init.sql b/migrations/0001_init.sql deleted file mode 100644 index 559d092..0000000 --- a/migrations/0001_init.sql +++ /dev/null @@ -1,2 +0,0 @@ --- 0001_init: placeholder so the migrations embed compiles. --- Replaced by the full v1 schema in Feature 02 task 3.