fix(core): tolerate missing done task mirrors on startup

This commit is contained in:
gsxdsm
2026-06-22 21:51:28 -07:00
parent 65c4dc5438
commit 32986f6b50
2 changed files with 31 additions and 1 deletions

View File

@@ -67,6 +67,19 @@ describe("TaskStore", () => {
});
});
describe("startup watch recovery", () => {
it("does not crash done-task backfill when a DB row has no task.json mirror", async () => {
const task = await store.createTask({ description: "done task with missing mirror" });
(store as unknown as { db: { prepare: (sql: string) => { run: (...args: unknown[]) => void } } }).db
.prepare(`UPDATE tasks SET "column" = ?, updatedAt = ? WHERE id = ?`)
.run("done", new Date().toISOString(), task.id);
await deleteTaskDir(task.id);
await expect(store.watch()).resolves.toBeUndefined();
await store.close();
});
});
describe("breakIntoSubtasks task creation flag", () => {
it("persists breakIntoSubtasks=true when explicitly requested", async () => {
const task = await store.createTask({

View File

@@ -11712,7 +11712,24 @@ ${TASK_UPSERT_SQL_ASSIGNMENTS}
if (cachedTask.column !== "done") continue;
const taskDir = this.taskDir(taskId);
const raw = await readFile(join(taskDir, "task.json"), "utf-8");
let raw: string;
try {
raw = await readFile(join(taskDir, "task.json"), "utf-8");
} catch (error) {
if ((error as NodeJS.ErrnoException)?.code === "ENOENT") {
/*
* FNXC:StartupRecovery 2026-06-23-05:02:
* A recovered or corrupt SQLite index can retain done-task rows whose legacy task.json mirror was already removed. Startup watch must not crash while running the one-time done-pause backfill; skip the missing mirror and keep the dashboard available so operators can inspect or repair the project.
*/
storeLog.warn("Skipping done-task pause metadata backfill for missing task.json", {
phase: "watch:done-pause-backfill",
taskId,
taskJsonPath: join(taskDir, "task.json"),
});
continue;
}
throw error;
}
const diskTask = JSON.parse(raw) as Task;
if (!this.clearDoneTransientFields(diskTask)) continue;