diff --git a/hermes_cli/kanban_db.py b/hermes_cli/kanban_db.py index ec7f16f05e..4a80385b6f 100644 --- a/hermes_cli/kanban_db.py +++ b/hermes_cli/kanban_db.py @@ -1366,6 +1366,13 @@ def create_task( "provider_override": provider_override, }, ) + if task_status == "blocked": + _append_event( + conn, + task_id, + "blocked", + {"reason": "initial_status", "status": "blocked", "actor": created_by or "user"}, + ) # ACK-edge: the originating channel hears a child BLOCK, not just the fan-in. inherit_creator_origin(conn, task_id, creator_task_id, created_at=now) _inherit_notify_subs(conn, task_id, parents, created_at=now) diff --git a/tests/hermes_cli/test_kanban_blocked_sticky.py b/tests/hermes_cli/test_kanban_blocked_sticky.py index 85fe183721..9f2e4c027b 100644 --- a/tests/hermes_cli/test_kanban_blocked_sticky.py +++ b/tests/hermes_cli/test_kanban_blocked_sticky.py @@ -156,9 +156,22 @@ def test_protocol_violation_loop_is_broken(kanban_home: Path) -> None: assert kb.get_task(conn, tid).status == "blocked" -# --------------------------------------------------------------------------- -# Schema-init recovery on legacy DBs is covered by -# tests/hermes_cli/test_kanban_db.py::test_connect_migrates_legacy_db_before_optional_column_indexes -# (landed via #28754 / #28781). The original PR shipped a duplicate test -# here; dropped during salvage to avoid two assertions of the same contract. -# --------------------------------------------------------------------------- +def test_created_with_initial_status_blocked_is_not_promoted_by_recompute_ready(kanban_home: Path) -> None: + """Verify a task created with initial_status='blocked' remains blocked when parents complete.""" + with kbc.connect() as conn: + parent_id = kb.create_task(conn, title="parent task") + child_id = kb.create_task( + conn, title="gated child task", parents=[parent_id], initial_status="blocked" + ) + assert kb.get_task(conn, child_id).status == "blocked" + + # Complete parent task + kb.claim_task(conn, parent_id) + kb.complete_task(conn, parent_id, result="done") + assert kb.get_task(conn, parent_id).status == "done" + + # recompute_ready must NOT promote the blocked child task + promoted = kb.recompute_ready(conn) + assert promoted == 0 + assert kb.get_task(conn, child_id).status == "blocked" +