diff --git a/src/lib/db/migrationRunner.ts b/src/lib/db/migrationRunner.ts index e7a2d06b3b..fabcd06e6d 100644 --- a/src/lib/db/migrationRunner.ts +++ b/src/lib/db/migrationRunner.ts @@ -487,8 +487,6 @@ function isSchemaAlreadyApplied( // but still burn a version-tracking slot mismatch — guard it the same // way as the other renumbers for consistency. return hasTable(db, "connection_runtime_state"); - case "146": - return hasTable(db, "jobs") && hasTable(db, "job_runs"); default: return false; } diff --git a/tests/unit/db-job-registry-migration-renumber-139.test.ts b/tests/unit/db-job-registry-migration-renumber-139.test.ts index b2dfff0d3e..5e0ccc9361 100644 --- a/tests/unit/db-job-registry-migration-renumber-139.test.ts +++ b/tests/unit/db-job-registry-migration-renumber-139.test.ts @@ -15,7 +15,11 @@ fs.writeFileSync( ); fs.writeFileSync( path.join(migrationsDir, "146_job_registry.sql"), - "CREATE TABLE jobs (id TEXT PRIMARY KEY); CREATE TABLE job_runs (id INTEGER PRIMARY KEY);" + [ + "CREATE TABLE IF NOT EXISTS jobs (id TEXT PRIMARY KEY);", + "CREATE TABLE IF NOT EXISTS job_runs (id INTEGER PRIMARY KEY);", + "CREATE TABLE job_registry_reexecuted (id INTEGER PRIMARY KEY);", + ].join(" ") ); const { runMigrations } = await import("../../src/lib/db/migrationRunner.ts"); @@ -53,6 +57,54 @@ test("job registry previously applied on 139 is rehomed so CCR can claim that sl .prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'ccr_blocks'") .get() ); + assert.equal( + db + .prepare( + "SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'job_registry_reexecuted'" + ) + .get(), + undefined, + "tracked legacy Job Registry must reconcile to 146 without replaying the migration" + ); + } finally { + db.close(); + } +}); + +test("untracked Job Registry tables do not suppress pending migration 146", () => { + const db = new Database(":memory:"); + try { + db.exec(` + CREATE TABLE jobs (id TEXT PRIMARY KEY); + CREATE TABLE job_runs (id INTEGER PRIMARY KEY); + CREATE TABLE ccr_blocks (principal_id TEXT PRIMARY KEY); + CREATE TABLE _omniroute_migrations ( + version TEXT PRIMARY KEY, + name TEXT NOT NULL, + applied_at TEXT NOT NULL DEFAULT (datetime('now')) + ); + INSERT INTO _omniroute_migrations (version, name) + VALUES ('139', 'ccr_blocks'); + `); + + assert.equal(runMigrations(db), 1); + + assert.deepEqual( + db.prepare("SELECT version, name FROM _omniroute_migrations ORDER BY version").all(), + [ + { version: "139", name: "ccr_blocks" }, + { version: "146", name: "job_registry" }, + ] + ); + + assert.ok( + db + .prepare( + "SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'job_registry_reexecuted'" + ) + .get(), + "a genuinely pending 146 migration must execute even when jobs and job_runs already exist" + ); } finally { db.close(); }