diff --git a/crates/buzz-db/src/runtime/migration.rs b/crates/buzz-db/src/runtime/migration.rs index c6e4416e7e..a525e130d8 100644 --- a/crates/buzz-db/src/runtime/migration.rs +++ b/crates/buzz-db/src/runtime/migration.rs @@ -2588,8 +2588,10 @@ mod postgres_tests { /// /// This bootstraps one probe database from `schema.sql` **through the real /// `bin/pgschema apply` binary** — the exact path CI (`ci.yml`) and both - /// test-relay launchers take — and migrates another through 1–38, then - /// asserts the three admin tables have identical column definitions (name, + /// test-relay launchers take — including partition reconciliation — and + /// migrates another through the current version. It verifies both IFC + /// startup catalogs and column parity, then asserts the three admin tables + /// have identical column definitions (name, /// type, nullability, default) and identical index shapes, including each /// key's catalog sort/null options (`pg_index.indoption`). Columns are keyed /// by name, not ordinal, because migrations append via `ALTER TABLE` while @@ -2719,13 +2721,43 @@ mod postgres_tests { let desired = PgPool::connect(&format!("{base_prefix}/{desired_db}")) .await .expect("connect desired-state probe database"); + sqlx::raw_sql(include_str!( + "../../../../scripts/reconcile-schema-after-pgschema.sql" + )) + .execute(&desired) + .await + .expect("reconcile standalone partitions and inherited IFC origin triggers"); let migrated = PgPool::connect(&format!("{base_prefix}/{migrated_db}")) .await .expect("connect migrated probe database"); - MIGRATOR - .run_to(55, &migrated) + run_migrations(&migrated) .await - .expect("apply migrations 1-55"); + .expect("apply all current migrations"); + + for table in [ + "channels", + "events", + "channel_policy_generations", + "ifc_event_acceptances", + ] { + assert_eq!( + columns(&desired, table).await, + columns(&migrated, table).await, + "IFC column parity mismatch for {table}" + ); + } + for database in [&desired_db, &migrated_db] { + let db = crate::Db::new(&crate::DbConfig { + database_url: format!("{base_prefix}/{database}"), + ..crate::DbConfig::default() + }) + .await + .expect("connect IFC catalog probe"); + db.verify_ifc_policy_catalog() + .await + .expect("both schema paths must satisfy the startup IFC gate"); + db.pool().close().await; + } for table in [ "relay_admin_actions", diff --git a/scripts/reconcile-schema-after-pgschema.sql b/scripts/reconcile-schema-after-pgschema.sql index 7eef8c4bbe..9cffac6e0a 100644 --- a/scripts/reconcile-schema-after-pgschema.sql +++ b/scripts/reconcile-schema-after-pgschema.sql @@ -21,6 +21,7 @@ BEGIN DROP TRIGGER IF EXISTS events_created_at_floor ON events_p_past; DROP TRIGGER IF EXISTS community_write_fence_events ON events_p_past; DROP TRIGGER IF EXISTS trg_events_guard_channel_roster_snapshot ON events_p_past; + DROP TRIGGER IF EXISTS trg_events_guard_origin_generation ON events_p_past; ALTER TABLE events ATTACH PARTITION events_p_past FOR VALUES FROM (MINVALUE) TO ('2026-01-01'); END IF; @@ -35,6 +36,7 @@ BEGIN DROP TRIGGER IF EXISTS events_created_at_floor ON events_p2026_01; DROP TRIGGER IF EXISTS community_write_fence_events ON events_p2026_01; DROP TRIGGER IF EXISTS trg_events_guard_channel_roster_snapshot ON events_p2026_01; + DROP TRIGGER IF EXISTS trg_events_guard_origin_generation ON events_p2026_01; ALTER TABLE events ATTACH PARTITION events_p2026_01 FOR VALUES FROM ('2026-01-01') TO ('2026-02-01'); END IF; @@ -49,6 +51,7 @@ BEGIN DROP TRIGGER IF EXISTS events_created_at_floor ON events_p2026_02; DROP TRIGGER IF EXISTS community_write_fence_events ON events_p2026_02; DROP TRIGGER IF EXISTS trg_events_guard_channel_roster_snapshot ON events_p2026_02; + DROP TRIGGER IF EXISTS trg_events_guard_origin_generation ON events_p2026_02; ALTER TABLE events ATTACH PARTITION events_p2026_02 FOR VALUES FROM ('2026-02-01') TO ('2026-03-01'); END IF; @@ -63,6 +66,7 @@ BEGIN DROP TRIGGER IF EXISTS events_created_at_floor ON events_p2026_03; DROP TRIGGER IF EXISTS community_write_fence_events ON events_p2026_03; DROP TRIGGER IF EXISTS trg_events_guard_channel_roster_snapshot ON events_p2026_03; + DROP TRIGGER IF EXISTS trg_events_guard_origin_generation ON events_p2026_03; ALTER TABLE events ATTACH PARTITION events_p2026_03 FOR VALUES FROM ('2026-03-01') TO ('2026-04-01'); END IF; @@ -77,6 +81,7 @@ BEGIN DROP TRIGGER IF EXISTS events_created_at_floor ON events_p2026_04; DROP TRIGGER IF EXISTS community_write_fence_events ON events_p2026_04; DROP TRIGGER IF EXISTS trg_events_guard_channel_roster_snapshot ON events_p2026_04; + DROP TRIGGER IF EXISTS trg_events_guard_origin_generation ON events_p2026_04; ALTER TABLE events ATTACH PARTITION events_p2026_04 FOR VALUES FROM ('2026-04-01') TO ('2026-05-01'); END IF; @@ -91,6 +96,7 @@ BEGIN DROP TRIGGER IF EXISTS events_created_at_floor ON events_p2026_05; DROP TRIGGER IF EXISTS community_write_fence_events ON events_p2026_05; DROP TRIGGER IF EXISTS trg_events_guard_channel_roster_snapshot ON events_p2026_05; + DROP TRIGGER IF EXISTS trg_events_guard_origin_generation ON events_p2026_05; ALTER TABLE events ATTACH PARTITION events_p2026_05 FOR VALUES FROM ('2026-05-01') TO ('2026-06-01'); END IF; @@ -105,6 +111,7 @@ BEGIN DROP TRIGGER IF EXISTS events_created_at_floor ON events_p2026_06; DROP TRIGGER IF EXISTS community_write_fence_events ON events_p2026_06; DROP TRIGGER IF EXISTS trg_events_guard_channel_roster_snapshot ON events_p2026_06; + DROP TRIGGER IF EXISTS trg_events_guard_origin_generation ON events_p2026_06; ALTER TABLE events ATTACH PARTITION events_p2026_06 FOR VALUES FROM ('2026-06-01') TO ('2026-07-01'); END IF; @@ -119,6 +126,7 @@ BEGIN DROP TRIGGER IF EXISTS events_created_at_floor ON events_p_future; DROP TRIGGER IF EXISTS community_write_fence_events ON events_p_future; DROP TRIGGER IF EXISTS trg_events_guard_channel_roster_snapshot ON events_p_future; + DROP TRIGGER IF EXISTS trg_events_guard_origin_generation ON events_p_future; ALTER TABLE events ATTACH PARTITION events_p_future FOR VALUES FROM ('2026-07-01') TO (MAXVALUE); END IF;