fix(engine): skip paused tasks in interrupted-merge recovery
recoverInterruptedMergingTasks was the one self-healing scan that didn't guard !task.paused. A user who paused a task mid-merge (status=merging, column=in-review) would still see the recovery scan finalize or unblock the merge once the stuck timeout elapsed, violating their pause intent. The other 12 self-healing recovery scans either explicitly skip paused tasks or operate on terminal/metadata-only state where pause is moot. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1368,6 +1368,36 @@ describe("SelfHealingManager", () => {
|
||||
managerWithRecovery.stop();
|
||||
});
|
||||
|
||||
it("does not recover paused merging tasks even when past the stuck timeout", async () => {
|
||||
const managerWithRecovery = new SelfHealingManager(store, {
|
||||
rootDir: "/tmp/test-project",
|
||||
});
|
||||
(store.getSettings as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||
taskStuckTimeoutMs: 60_000,
|
||||
});
|
||||
|
||||
(store.listTasks as ReturnType<typeof vi.fn>).mockResolvedValue([
|
||||
{
|
||||
id: "FN-1677",
|
||||
column: "in-review",
|
||||
status: "merging",
|
||||
paused: true,
|
||||
error: null,
|
||||
updatedAt: new Date(Date.now() - 24 * 60 * 60_000).toISOString(),
|
||||
steps: [{ name: "Ship it", status: "done" }],
|
||||
log: [],
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await managerWithRecovery.recoverInterruptedMergingTasks();
|
||||
|
||||
expect(result).toBe(0);
|
||||
expect(store.updateTask).not.toHaveBeenCalled();
|
||||
expect(store.moveTask).not.toHaveBeenCalled();
|
||||
|
||||
managerWithRecovery.stop();
|
||||
});
|
||||
|
||||
it("does not recover stale merging tasks when stuck detection is disabled", async () => {
|
||||
const managerWithRecovery = new SelfHealingManager(store, {
|
||||
rootDir: "/tmp/test-project",
|
||||
|
||||
@@ -927,6 +927,7 @@ export class SelfHealingManager {
|
||||
const tasks = await this.store.listTasks({ column: "in-review", slim: true });
|
||||
const candidates = tasks.filter((task) =>
|
||||
task.column === "in-review" &&
|
||||
!task.paused &&
|
||||
Boolean(task.status && ACTIVE_MERGE_STATUSES.has(task.status)) &&
|
||||
this.isPastInterruptedMergeGrace(task, timeoutMs),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user