fix(core): finish deferred agentLogEntries drop when migrations 103+ outrun it

Migration 102 defers the destructive agentLogEntries drop until TaskStore
copies legacy rows to JSONL and writes the __meta guard, then relies on a
second init() pass gated on schemaVersion < SCHEMA_VERSION. Migrations
103-105 bump the version to 105 on the first pass, so the second pass never
fired and the legacy table survived forever. Make the drop version-independent
in migrate() and trigger the re-init whenever the legacy table remains.

Also pin secrets-schema.test.ts to String(SCHEMA_VERSION) instead of the
hardcoded "102" string the schema bump invalidated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-06-03 20:42:00 -07:00
parent 4cdf19806b
commit 07489e5820
3 changed files with 37 additions and 5 deletions

View File

@@ -2,7 +2,7 @@ import { describe, it, expect } from "vitest";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { Database } from "../db.js";
import { Database, SCHEMA_VERSION } from "../db.js";
import { createCentralDatabase } from "../central-db.js";
function createTempDir(prefix: string): string {
@@ -42,7 +42,7 @@ describe("secrets schema migrations", () => {
const version = db
.prepare("SELECT value FROM __meta WHERE key = 'schemaVersion'")
.get() as { value: string };
expect(version.value).toBe("102");
expect(version.value).toBe(String(SCHEMA_VERSION));
} finally {
db.close();
rmSync(dir, { recursive: true, force: true });
@@ -105,7 +105,7 @@ describe("secrets schema migrations", () => {
const version = db
.prepare("SELECT value FROM __meta WHERE key = 'schemaVersion'")
.get() as { value: string };
expect(version.value).toBe("102");
expect(version.value).toBe(String(SCHEMA_VERSION));
} finally {
db.close();
rmSync(dir, { recursive: true, force: true });
@@ -155,7 +155,7 @@ describe("secrets schema migrations", () => {
.prepare("SELECT value FROM __meta WHERE key = 'schemaVersion'")
.get() as { value: string };
expect(projectVersion.value).toBe("102");
expect(projectVersion.value).toBe(String(SCHEMA_VERSION));
expect(centralVersion.value).toBe("13");
} finally {
projectDb.close();

View File

@@ -2028,6 +2028,28 @@ export class Database {
this.addColumnIfMissing("tasks", "scopeAutoWiden", "TEXT DEFAULT '[]'");
}
// Deferred agentLogEntries drop (companion to migration 102): when the
// legacy table still had rows on the first init pass, the destructive drop
// was deferred until TaskStore copies the rows to JSONL and writes the
// __meta guard, then re-runs init(). Migrations 103+ bump the schema
// version past 102 on that first pass, so the re-run can no longer reach
// the version-gated 102 block — finish the drop here, version-independent
// (and before the early return below, which fires once the version is
// current).
if (this.hasTable("agentLogEntries")) {
const agentLogMigrationComplete = this.getMetaValue("agentLogEntriesToFileMigrationVersion") === "1";
const legacyAgentLogTableIsEmpty =
(this.db.prepare("SELECT COUNT(*) as count FROM agentLogEntries").get() as { count: number }).count === 0;
const hasLegacyAgentLogCitations = this.hasTable("goal_citations")
? (this.db.prepare(
"SELECT 1 FROM goal_citations WHERE surface = 'agent_log' AND sourceRef GLOB 'agentLog:[0-9]*' LIMIT 1",
).get() ?? undefined) !== undefined
: false;
if (agentLogMigrationComplete || (legacyAgentLogTableIsEmpty && !hasLegacyAgentLogCitations)) {
this.db.exec(`DROP TABLE IF EXISTS agentLogEntries`);
}
}
if (version >= SCHEMA_VERSION) return;
if (version < 2) {

View File

@@ -1443,7 +1443,17 @@ export class TaskStore extends EventEmitter<TaskStoreEvents> {
await this.migrateActiveArchivedTasksToArchiveDb();
await this.migrateAgentLogEntriesToFilesOnce();
await this.cleanupNoOpTaskMovedActivityRowsOnce();
if (this.db.getSchemaVersion() < SCHEMA_VERSION) {
// Re-run init when migrations are pending, or when the deferred
// agentLogEntries drop still needs to fire: migration 102 skips the
// destructive drop until migrateAgentLogEntriesToFilesOnce() above writes
// the __meta guard, but migrations 103+ bump the schema version past 102
// on the first pass, so the version check alone no longer triggers the
// second pass that performs the drop.
const legacyAgentLogTableRemains =
this.db
.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'agentLogEntries' LIMIT 1")
.get() !== undefined;
if (this.db.getSchemaVersion() < SCHEMA_VERSION || legacyAgentLogTableRemains) {
this.db.init();
}
await this.importLegacyAgentLogsOnce();