From e271c54ac615109e2d81845e3559dd9ab42ad40d Mon Sep 17 00:00:00 2001 From: null Date: Wed, 3 Jun 2026 22:38:33 -0500 Subject: [PATCH] fix: reconcileLegacyMigrations asserts version sync with runMigrations to prevent drift --- db/database.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/db/database.js b/db/database.js index 1afdb04..ebc7137 100644 --- a/db/database.js +++ b/db/database.js @@ -608,6 +608,11 @@ fs.mkdirSync(path.dirname(DB_PATH), { recursive: true }); let db = null; 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() { const dir = path.dirname(DB_PATH); 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 for (const migration of migrations) { if (migration.check()) { @@ -2751,6 +2775,9 @@ function runMigrations() { 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 const appliedVersions = new Set( db.prepare('SELECT version FROM schema_migrations').all().map(r => r.version)