From 6b3efcee49afed5fde590c56766634e8cbdf921f Mon Sep 17 00:00:00 2001 From: luyao618 <364939526@qq.com> Date: Mon, 4 May 2026 14:47:13 +0800 Subject: [PATCH] fix(kanban): reject direct status transition to 'running' via dashboard API The PATCH /tasks/:id endpoint allows setting status='running' via _set_status_direct(), bypassing the dispatcher/claim path that creates run rows, claim locks, expiry, and worker process metadata. This can leave tasks stuck in 'running' with no active worker. Fix: reject status='running' with HTTP 400, requiring all transitions to 'running' to go through the canonical claim_task() path. Closes #19535 --- plugins/kanban/dashboard/plugin_api.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/kanban/dashboard/plugin_api.py b/plugins/kanban/dashboard/plugin_api.py index d80296b888..1c25f372e6 100644 --- a/plugins/kanban/dashboard/plugin_api.py +++ b/plugins/kanban/dashboard/plugin_api.py @@ -449,7 +449,12 @@ def update_task(task_id: str, payload: UpdateTaskBody, board: Optional[str] = Qu ok = _set_status_direct(conn, task_id, "ready") elif s == "archived": ok = kanban_db.archive_task(conn, task_id) - elif s in ("todo", "running", "triage"): + elif s == "running": + raise HTTPException( + status_code=400, + detail="Cannot set status to 'running' directly; use the dispatcher/claim path", + ) + elif s in ("todo", "triage"): ok = _set_status_direct(conn, task_id, s) else: raise HTTPException(status_code=400, detail=f"unknown status: {s}")