fix: reconcileLegacyMigrations asserts version sync with runMigrations to prevent drift

This commit is contained in:
null 2026-06-03 22:38:33 -05:00
parent b81b41d302
commit e271c54ac6
1 changed files with 27 additions and 0 deletions

View File

@ -608,6 +608,11 @@ fs.mkdirSync(path.dirname(DB_PATH), { recursive: true });
let db = null; let db = null;
let initializing = false; let initializing = false;
// Populated by runMigrations() so reconcileLegacyMigrations() can assert
// its own version list matches. Catches drift between the two arrays at startup
// on any legacy-DB upgrade path, rather than silently misconfiguring the schema.
let _runMigrationVersions = null;
function assertWritableDbPath() { function assertWritableDbPath() {
const dir = path.dirname(DB_PATH); const dir = path.dirname(DB_PATH);
const probe = path.join(dir, `.write-test-${process.pid}-${Date.now()}`); const probe = path.join(dir, `.write-test-${process.pid}-${Date.now()}`);
@ -1605,6 +1610,25 @@ function reconcileLegacyMigrations() {
} }
} }
// Assert version sync with runMigrations() to catch drift between the two arrays.
// runMigrations() always runs first and populates _runMigrationVersions.
if (_runMigrationVersions !== null) {
const reconcileVersions = migrations.map(m => m.version);
const runSet = new Set(_runMigrationVersions);
const reconcileSet = new Set(reconcileVersions);
const onlyInRun = _runMigrationVersions.filter(v => !reconcileSet.has(v));
const onlyInReconcile = reconcileVersions.filter(v => !runSet.has(v));
if (onlyInRun.length || onlyInReconcile.length) {
const msg =
'[migration-sync] reconcileLegacyMigrations and runMigrations version lists are out of sync.' +
(onlyInRun.length ? ` Only in runMigrations: ${onlyInRun.join(', ')}.` : '') +
(onlyInReconcile.length ? ` Only in reconcile: ${onlyInReconcile.join(', ')}.` : '') +
' Add the missing version to both arrays.';
console.error(msg);
throw new Error(msg);
}
}
// Process all versioned migrations // Process all versioned migrations
for (const migration of migrations) { for (const migration of migrations) {
if (migration.check()) { if (migration.check()) {
@ -2751,6 +2775,9 @@ function runMigrations() {
throw err; throw err;
} }
// Store version list so reconcileLegacyMigrations() can assert sync.
_runMigrationVersions = migrations.map(m => m.version);
// Build set of already-applied versions for dependency checking // Build set of already-applied versions for dependency checking
const appliedVersions = new Set( const appliedVersions = new Set(
db.prepare('SELECT version FROM schema_migrations').all().map(r => r.version) db.prepare('SELECT version FROM schema_migrations').all().map(r => r.version)