diff --git a/packages/engine/src/__tests__/self-healing.test.ts b/packages/engine/src/__tests__/self-healing.test.ts index 1431a9ed3..ea00a7ad4 100644 --- a/packages/engine/src/__tests__/self-healing.test.ts +++ b/packages/engine/src/__tests__/self-healing.test.ts @@ -1024,6 +1024,31 @@ describe("SelfHealingManager", () => { managerWithRecovery.stop(); }); + + it("does not clear errors on paused tasks (respects user investigate intent)", async () => { + const managerWithRecovery = new SelfHealingManager(store, { + rootDir: "/tmp/test-project", + }); + + (store.listTasks as ReturnType).mockResolvedValue([ + { + id: "FN-303", + column: "in-review", + status: "failed", + paused: true, + error: "Agent finished without calling task_done", + steps: [{ status: "done" }, { status: "done" }], + log: [], + }, + ]); + + const result = await managerWithRecovery.recoverMisclassifiedFailures(); + + expect(result).toBe(0); + expect(store.updateTask).not.toHaveBeenCalled(); + + managerWithRecovery.stop(); + }); }); describe("recoverPartialProgressNoTaskDoneFailures", () => { @@ -1642,6 +1667,33 @@ describe("SelfHealingManager", () => { managerWithRecovery.stop(); }); + + it("does not move paused merged tasks to done (respects user pause intent)", async () => { + const managerWithRecovery = new SelfHealingManager(store, { + rootDir: "/tmp/test-project", + }); + + (store.listTasks as ReturnType).mockResolvedValue([ + { + id: "FN-352", + column: "in-review", + paused: true, + mergeDetails: { + mergeConfirmed: true, + mergedAt: "2026-01-01T00:00:00.000Z", + }, + log: [], + }, + ]); + + const result = await managerWithRecovery.recoverMergedReviewTasks(); + + expect(result).toBe(0); + expect(store.updateTask).not.toHaveBeenCalled(); + expect(store.moveTask).not.toHaveBeenCalled(); + + managerWithRecovery.stop(); + }); }); describe("recoverReviewTasksWithFailedPreMergeSteps", () => { diff --git a/packages/engine/src/self-healing.ts b/packages/engine/src/self-healing.ts index 5ae8ded19..665f23612 100644 --- a/packages/engine/src/self-healing.ts +++ b/packages/engine/src/self-healing.ts @@ -1016,6 +1016,7 @@ export class SelfHealingManager { const mergedButNotDone = tasks.filter((t) => t.column === "in-review" && + !t.paused && t.mergeDetails?.mergeConfirmed === true, ); @@ -1069,6 +1070,7 @@ export class SelfHealingManager { const misclassified = tasks.filter((t) => t.column === "in-review" && + !t.paused && t.status === "failed" && t.error?.includes("without calling task_done") && t.steps.length > 0 &&