From 034feea8f76d72bb2db815d66a162ee6cb8bf8f1 Mon Sep 17 00:00:00 2001 From: J Date: Wed, 6 May 2026 15:50:07 +0800 Subject: [PATCH] fix(daemon): honor task-deleted signal in post-runTask completion guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The final pre-completion check in handleTask only looked for status == "cancelled" and ignored errors. After PR #2107 added a 404 task-deleted cancellation path to the in-flight watcher, this trailing guard fell out of sync — if the task was deleted between the watcher's last poll and runTask returning, handleTask would still try to call CompleteTask and only learn about the deletion via the 404 from that callback. Reuse shouldInterruptAgent so the same truth table (cancelled OR 404 task-not-found, but NOT transient errors) drives both polling and the final guard. Co-authored-by: multica-agent --- server/internal/daemon/daemon.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/server/internal/daemon/daemon.go b/server/internal/daemon/daemon.go index 88aae699d..22ebb98fe 100644 --- a/server/internal/daemon/daemon.go +++ b/server/internal/daemon/daemon.go @@ -1463,11 +1463,12 @@ func (d *Daemon) handleTask(ctx context.Context, task Task, slot int) { _ = d.client.ReportProgress(ctx, task.ID, "Finishing task", 2, 2) - // Check if the task was cancelled while it was running (e.g. issue - // was reassigned). If so, skip reporting results — the server already - // moved the task to 'cancelled' so complete/fail would fail anyway. - if status, err := d.client.GetTaskStatus(ctx, task.ID); err == nil && status == "cancelled" { - taskLog.Info("task cancelled during execution, discarding result") + // Final pre-completion check: if the server already moved the task to + // "cancelled" or deleted the row outright, skip reporting — the + // complete/fail callbacks would fail anyway. Reuse shouldInterruptAgent + // so this guard honors the same signals as the in-flight watcher. + if status, err := d.client.GetTaskStatus(ctx, task.ID); shouldInterruptAgent(status, err) { + taskLog.Info("task cancelled during execution, discarding result", "status", status, "error", err) return }