mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-02 07:11:49 +00:00
fix(kanban): demote ready children when a parent is reopened
This commit is contained in:
parent
9281599b6f
commit
917e51858d
2 changed files with 72 additions and 0 deletions
|
|
@ -722,6 +722,10 @@ def _set_status_direct(
|
|||
return False
|
||||
|
||||
was_running = prev["status"] == "running"
|
||||
reopening_satisfied_parent = (
|
||||
prev["status"] in {"done", "archived"}
|
||||
and new_status not in {"done", "archived"}
|
||||
)
|
||||
|
||||
cur = conn.execute(
|
||||
"UPDATE tasks SET status = ?, "
|
||||
|
|
@ -745,6 +749,37 @@ def _set_status_direct(
|
|||
"VALUES (?, ?, 'status', ?, ?)",
|
||||
(task_id, run_id, json.dumps({"status": new_status}), int(time.time())),
|
||||
)
|
||||
if reopening_satisfied_parent:
|
||||
# A parent leaving done/archived invalidates any direct child that
|
||||
# was sitting in ready solely because that parent used to satisfy
|
||||
# the dependency gate. Demote those children immediately so the
|
||||
# dashboard does not keep advertising stale-ready work.
|
||||
for row in conn.execute(
|
||||
"SELECT child_id FROM task_links WHERE parent_id = ? ORDER BY child_id",
|
||||
(task_id,),
|
||||
).fetchall():
|
||||
child_id = row["child_id"]
|
||||
demoted = conn.execute(
|
||||
"UPDATE tasks SET status = 'todo' "
|
||||
"WHERE id = ? AND status = 'ready'",
|
||||
(child_id,),
|
||||
)
|
||||
if demoted.rowcount == 1:
|
||||
conn.execute(
|
||||
"INSERT INTO task_events (task_id, kind, payload, created_at) "
|
||||
"VALUES (?, 'status', ?, ?)",
|
||||
(
|
||||
child_id,
|
||||
json.dumps(
|
||||
{
|
||||
"status": "todo",
|
||||
"reason": "parent_reopened",
|
||||
"parent": task_id,
|
||||
}
|
||||
),
|
||||
int(time.time()),
|
||||
),
|
||||
)
|
||||
# If we re-opened something, children may have gone stale.
|
||||
if new_status in {"done", "ready"}:
|
||||
kanban_db.recompute_ready(conn)
|
||||
|
|
|
|||
|
|
@ -308,6 +308,43 @@ def test_patch_drag_drop_move_todo_to_ready(client):
|
|||
assert child_after["status"] == "ready"
|
||||
|
||||
|
||||
def test_reopening_parent_demotes_ready_child(client):
|
||||
"""Reopening a completed parent must invalidate ready children immediately.
|
||||
|
||||
The dispatcher re-checks parent completion on claim, but the dashboard
|
||||
should not keep showing a stale child as ready after an operator drags
|
||||
its parent back out of done for more work.
|
||||
"""
|
||||
parent = client.post("/api/plugins/kanban/tasks", json={"title": "p"}).json()["task"]
|
||||
child = client.post(
|
||||
"/api/plugins/kanban/tasks",
|
||||
json={"title": "c", "parents": [parent["id"]]},
|
||||
).json()["task"]
|
||||
assert child["status"] == "todo"
|
||||
|
||||
r = client.patch(
|
||||
f"/api/plugins/kanban/tasks/{parent['id']}",
|
||||
json={"status": "done"},
|
||||
)
|
||||
assert r.status_code == 200
|
||||
|
||||
child_after_done = client.get(
|
||||
f"/api/plugins/kanban/tasks/{child['id']}"
|
||||
).json()["task"]
|
||||
assert child_after_done["status"] == "ready"
|
||||
|
||||
r = client.patch(
|
||||
f"/api/plugins/kanban/tasks/{parent['id']}",
|
||||
json={"status": "todo"},
|
||||
)
|
||||
assert r.status_code == 200
|
||||
|
||||
child_after_reopen = client.get(
|
||||
f"/api/plugins/kanban/tasks/{child['id']}"
|
||||
).json()["task"]
|
||||
assert child_after_reopen["status"] == "todo"
|
||||
|
||||
|
||||
def test_patch_reassign(client):
|
||||
t = client.post(
|
||||
"/api/plugins/kanban/tasks",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue