fix(kanban): wake the origin on review handoffs and triage escalations

`review_requested` and `block_loop_detected` are terminal event kinds that
hand a decision back to the origin subscriber, but neither was listed in the
gateway notifier's `_WAKE_KINDS`. A `notify+wake` subscription therefore got
the passive ping only and the origin agent never took a turn — so an agent
that delegated implementation work slept through the "ready for review"
handoff and through a task being routed to triage, while the equivalent
`blocked` event woke it.

Add both kinds to the wake set, add their status strings to the synthetic
wake message in every locale, and document which events wake.
This commit is contained in:
Nikita Barkov
2026-08-16 15:46:18 +02:00
committed by Teknium
parent 5538bd1f93
commit 7700d3a011
20 changed files with 161 additions and 1 deletions
+12 -1
View File
@@ -781,7 +781,16 @@ class GatewayKanbanWatchersMixin:
# claim exactly like a failed send() above, so the
# next tick retries.
task_terminal = task and task.status == "archived"
_WAKE_KINDS = ("completed", "gave_up", "crashed", "timed_out", "blocked")
# Kinds that hand a decision back to the origin, so the
# origin has to take a turn. ``review_requested`` (the
# implementation is done and waits for a reviewer) and
# ``block_loop_detected`` (routed to triage) belong here
# for the same reason ``blocked`` does. ``status`` /
# ``archived`` / ``unblocked`` stay out: bookkeeping.
_WAKE_KINDS = (
"completed", "gave_up", "crashed", "timed_out",
"blocked", "review_requested", "block_loop_detected",
)
_wake_kinds = (
{ev.kind for ev in d["events"] if ev.kind in _WAKE_KINDS}
if wake_agent
@@ -818,6 +827,8 @@ class GatewayKanbanWatchersMixin:
if "crashed" in _wake_kinds: _parts.append(t("gateway.kanban.wake.crashed"))
if "timed_out" in _wake_kinds: _parts.append(t("gateway.kanban.wake.timed_out"))
if "blocked" in _wake_kinds: _parts.append(t("gateway.kanban.wake.blocked"))
if "review_requested" in _wake_kinds: _parts.append(t("gateway.kanban.wake.review_requested"))
if "block_loop_detected" in _wake_kinds: _parts.append(t("gateway.kanban.wake.block_loop_detected"))
_status = t("gateway.kanban.wake.status_joiner").join(_parts) or t("gateway.kanban.wake.status_default")
_synth = t(
"gateway.kanban.wake.message",