Skip to content

Commit 8de172a

Browse files
committed
fix: publish final ask ledger schema atomically
1 parent d6f38d5 commit 8de172a

1 file changed

Lines changed: 47 additions & 2 deletions

File tree

crates/capsem-logger/src/schema.rs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,8 @@ pub const CREATE_SCHEMA: &str = "
405405
event_json TEXT NOT NULL CHECK (json_valid(event_json)),
406406
resolver TEXT,
407407
reason TEXT,
408-
trace_id TEXT
408+
trace_id TEXT,
409+
turn_id TEXT
409410
);
410411
CREATE INDEX IF NOT EXISTS idx_security_ask_events_timestamp
411412
ON security_ask_events(timestamp_unix_ms);
@@ -1663,7 +1664,8 @@ pub fn migrate(conn: &Connection) {
16631664
event_json TEXT NOT NULL CHECK (json_valid(event_json)),
16641665
resolver TEXT,
16651666
reason TEXT,
1666-
trace_id TEXT
1667+
trace_id TEXT,
1668+
turn_id TEXT
16671669
);
16681670
CREATE INDEX IF NOT EXISTS idx_security_ask_events_timestamp
16691671
ON security_ask_events(timestamp_unix_ms);
@@ -1773,6 +1775,49 @@ mod tests {
17731775
}
17741776
}
17751777

1778+
#[test]
1779+
fn fresh_create_schema_has_no_migration_only_columns() {
1780+
let conn = Connection::open_in_memory().unwrap();
1781+
create_tables(&conn).unwrap();
1782+
let before = READY_SCHEMA_COLUMNS
1783+
.iter()
1784+
.map(|(table, _)| (*table, columns_for_schema(&conn, "main", table)))
1785+
.collect::<BTreeMap<_, _>>();
1786+
1787+
migrate(&conn);
1788+
1789+
for (table, columns_before_migrate) in before {
1790+
assert_eq!(
1791+
columns_before_migrate,
1792+
columns_for_schema(&conn, "main", table),
1793+
"fresh CREATE_SCHEMA must publish the final {table} shape; migrations are only for existing databases"
1794+
);
1795+
}
1796+
}
1797+
1798+
#[test]
1799+
fn fresh_schema_is_final_before_external_memory_rehydrate() {
1800+
let conn = Connection::open_in_memory().unwrap();
1801+
create_tables(&conn).unwrap();
1802+
create_memory_tables(
1803+
&conn,
1804+
&memory_uri_for_name("fresh_schema_is_final_before_external_memory_rehydrate"),
1805+
)
1806+
.unwrap();
1807+
1808+
// Reproduce the production ordering window: an external reader mirrors
1809+
// the freshly published schema before the writer runs legacy migrations.
1810+
migrate(&conn);
1811+
sync_memory_tables_from_disk(&conn, ["security_ask_events"])
1812+
.expect("fresh canonical DDL must already match its post-migration shape");
1813+
1814+
assert_eq!(
1815+
columns_for_schema(&conn, MEMORY_SCHEMA, "security_ask_events"),
1816+
columns_for_schema(&conn, "main", "security_ask_events"),
1817+
"a fresh DB must not publish a pre-migration table shape to external readers"
1818+
);
1819+
}
1820+
17761821
#[test]
17771822
fn db_mem_disk_ready_rejects_missing_memory_schema() {
17781823
let conn = Connection::open_in_memory().unwrap();

0 commit comments

Comments
 (0)