From c3178b564b51cc754f9e7c1294479da6c46c1f70 Mon Sep 17 00:00:00 2001 From: "Fusion (runfusion.ai)" Date: Tue, 19 May 2026 05:56:35 -0700 Subject: [PATCH] =?UTF-8?q?fix(FN-5127):=20complete=20Step=201=20=E2=80=94?= =?UTF-8?q?=20make=20deleteTask=20idempotent=20on=20re-delete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fusion-Task-Id: FN-5127 Fusion-Task-Lineage: aafbc6a7-fa26-4dad-ab16-96ea79f8cee2 --- packages/core/src/store.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/core/src/store.ts b/packages/core/src/store.ts index ca2c4495b..94791655f 100644 --- a/packages/core/src/store.ts +++ b/packages/core/src/store.ts @@ -5687,6 +5687,9 @@ export class TaskStore extends EventEmitter { /** * Soft-delete a live task by setting tasks.deletedAt/updatedAt while leaving * the row and on-disk task artifacts in place for potential recovery. + * + * Idempotent (FN-5127): calling deleteTask on an already-soft-deleted task is + * a no-op and does not re-emit task:deleted. */ async deleteTask( id: string, @@ -5696,11 +5699,15 @@ export class TaskStore extends EventEmitter { // Flush buffered agent logs inside the lock so no new appends for this // task can sneak in between flush and soft-delete mutation. this.flushAgentLogBuffer(); - const task = this.readTaskFromDb(id); + const task = this.readTaskFromDb(id, { includeDeleted: true }); if (!task) { throw new Error(`Task ${id} not found`); } + if (task.deletedAt) { + return task; + } + // Refuse to delete a task that is still referenced as a dependency // by another live task unless the caller explicitly opts into // removing those incoming references as part of this delete.