fix(#2279): versioned DB migrations via schema_versions table
Replace the try-and-ignore-duplicate-column approach in apply_migrations with proper schema versioning using a shared schema_versions table. ## mechanism New function: db::apply_versioned_migrations(conn, subsystem, legacy_column, migrations). Tracks the applied-migration count in a schema_versions table (one row per subsystem key). Only migrations past the stored version run. Legacy detection: pre-versioning databases have no schema_versions row. The legacy_column tuple (table, column) identifies a column that exists only in a fully-migrated legacy database. If present, all known migrations are skipped. If absent, migrations start from 0. ## stores migrated - broker: removes bespoke ensure_message_columns / ensure_reminder_columns. Unified into BROKER_MIGRATIONS (v1-v5). Legacy detector: messages.priority (added in the last pre-versioning migration). - approvals: 4 historical migrations (v1-v4). Legacy detector: approvals.submitter. - operator_questions: 3 historical migrations (v1-v3). Legacy detector: operator_questions.target. - scheduled_prompts: 1 historical migration (v1). Legacy detector: scheduled_prompts.paused_at_unix. apply_migrations removed (no callers). ## tests (db.rs) - fresh_install_runs_all_migrations - legacy_install_skips_all_migrations - partial_migration_resumes_from_version - already_at_latest_is_noop - multiple_stores_in_same_db
This commit is contained in:
parent
01db1af346
commit
7d36ec5e1f
5 changed files with 333 additions and 115 deletions
|
|
@ -24,24 +24,19 @@ CREATE INDEX IF NOT EXISTS idx_approvals_pending
|
|||
ON approvals (id) WHERE status = 'pending';
|
||||
";
|
||||
|
||||
/// Additive column migrations for pre-existing databases, applied via
|
||||
/// `db::apply_migrations` (try-and-ignore-duplicate-column).
|
||||
/// Ordered schema migrations tracked in `schema_versions` (key `"approvals"`).
|
||||
/// Legacy databases are detected via the `submitter` column — the last
|
||||
/// column added before versioning was introduced — and fast-forwarded past
|
||||
/// all known migrations. New columns go here as v5, v6, …
|
||||
const MIGRATIONS: &[&str] = &[
|
||||
// `kind` (pre-Phase-8 dbs): legacy rows default to `apply_commit`,
|
||||
// which matches their actual semantics.
|
||||
// v1: `kind` (pre-Phase-8 dbs): legacy rows default to `apply_commit`.
|
||||
"ALTER TABLE approvals ADD COLUMN kind TEXT NOT NULL DEFAULT 'apply_commit'",
|
||||
// `description`: manager-supplied note shown on the dashboard
|
||||
// approval card at submission time (distinct from `note`, set on
|
||||
// denial/failure).
|
||||
// v2: `description`: manager-supplied note on the dashboard card.
|
||||
"ALTER TABLE approvals ADD COLUMN description TEXT",
|
||||
// `fetched_sha`: the canonical sha hive-c0re vouched for at
|
||||
// `request_apply_commit` time. Distinct from `commit_ref`
|
||||
// (manager-supplied, may not even resolve by approve time).
|
||||
// v3: `fetched_sha`: canonical sha hive-c0re resolved at submit time.
|
||||
"ALTER TABLE approvals ADD COLUMN fetched_sha TEXT",
|
||||
// `submitter`: the agent that submitted the approval (the
|
||||
// authenticated socket caller); approval-scoped helper events
|
||||
// route to it. Legacy rows are NULL → callers fall back to the
|
||||
// root agent.
|
||||
// v4: `submitter`: authenticated agent that submitted the approval.
|
||||
// Legacy rows are NULL → callers fall back to the root agent.
|
||||
"ALTER TABLE approvals ADD COLUMN submitter TEXT",
|
||||
];
|
||||
|
||||
|
|
@ -54,7 +49,12 @@ impl Approvals {
|
|||
let conn = crate::db::open(path, "approvals")?;
|
||||
conn.execute_batch(SCHEMA)
|
||||
.context("apply approvals schema")?;
|
||||
crate::db::apply_migrations(&conn, "approvals", MIGRATIONS)?;
|
||||
crate::db::apply_versioned_migrations(
|
||||
&conn,
|
||||
"approvals",
|
||||
("approvals", "submitter"),
|
||||
MIGRATIONS,
|
||||
)?;
|
||||
Ok(Self {
|
||||
conn: Mutex::new(conn),
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue