fix(kanban): reset failure counters on unblock_task

When a task is manually unblocked (blocked → ready/todo), the
consecutive_failures counter and last_failure_error were left intact.
The next failure would immediately re-trip the circuit breaker because
the counter was still at or above the failure limit.

Reset both fields on unblock so the task gets a fresh retry budget.

Includes a regression test that verifies counters are zeroed.
This commit is contained in:
bradhallett 2026-05-18 20:16:26 -07:00 committed by Teknium
parent 5db0d72c90
commit f042931852
2 changed files with 22 additions and 1 deletions

View file

@ -2718,7 +2718,8 @@ def unblock_task(conn: sqlite3.Connection, task_id: str) -> bool:
).fetchone()
new_status = "todo" if undone_parents else "ready"
cur = conn.execute(
"UPDATE tasks SET status = ?, current_run_id = NULL "
"UPDATE tasks SET status = ?, current_run_id = NULL, "
"consecutive_failures = 0, last_failure_error = NULL "
"WHERE id = ? AND status = 'blocked'",
(new_status, task_id),
)

View file

@ -406,6 +406,26 @@ def test_block_then_unblock(kanban_home):
assert kb.get_task(conn, t).status == "ready"
def test_unblock_resets_failure_counters(kanban_home):
"""unblock_task must reset consecutive_failures and last_failure_error."""
with kb.connect() as conn:
t = kb.create_task(conn, title="x", assignee="a")
kb.claim_task(conn, t)
assert kb.block_task(conn, t, reason="need input")
# Simulate accumulated failures from the circuit breaker
conn.execute(
"UPDATE tasks SET consecutive_failures = 5, "
"last_failure_error = 'test error' WHERE id = ?",
(t,),
)
conn.commit()
assert kb.unblock_task(conn, t)
task = kb.get_task(conn, t)
assert task.status == "ready"
assert task.consecutive_failures == 0
assert task.last_failure_error is None
# ---------------------------------------------------------------------------
# Parent-completion invariant at the claim gate (RCA t_a6acd07d)
# ---------------------------------------------------------------------------