fix(cron): finalize kanban worker sessions with ended_at (#76914) - #76995
fix(cron): finalize kanban worker sessions with ended_at (#76914)#76995webtecnica wants to merge 1 commit into
Conversation
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tracing the Kanban worker lifecycle. The premise is confirmed on current main: hermes_cli/kanban_db.py:9131-9134 launches workers through chat -q, while cli.py:1341-1347 does not call agent.close(); run_agent.py:4096-4100 is the path that ends an owned SQLite session.
Problems
- The new
close()is after_run_cleanup()(cli.py:1352in this diff). If cleanup raises, it is never reached.tests/cli/test_single_query_session_finalize.py:16-34already exercises a cleanup exception and proves the finalizer must continue its teardown path.
Suggested changes
- Put the guarded
agent.close()in afinallybefore_release_active_session(), with release protected by its ownfinally. - Extend
tests/cli/test_single_query_session_finalize.pyto assertclose()runs on both normal and cleanup-failure paths.
This is an automated hermes-sweeper review.
| # workers / cron pipes / `hermes chat -q` exit with ended_at NULL. | ||
| agent = getattr(cli, "agent", None) | ||
| close = getattr(agent, "close", None) | ||
| if callable(close): |
There was a problem hiding this comment.
_run_cleanup() can raise (see tests/cli/test_single_query_session_finalize.py:16-34), which skips this call and leaves the owned session open. Move this guarded close into a finally that runs before the lease-release finally, and add coverage for that error path.
SummaryOne PR addresses #76914. #76995 targets the reported quiet-path lifecycle gap by adding Related pull requests
Suggested consolidationKeep #76995 open with a salvage path: move the guarded Complex graphflowchart LR
classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
classDef best stroke-width:3px,stroke:#b45309
classDef target stroke-width:3px,stroke:#4338ca
I76914(["issue #76914 (open)"])
P76995["PR #76995 (open)"]
P76995 -->|best fix| I76914
class I76914 open
class P76995 open
class P76995 best
class P76995 target
click I76914 "https://github.com/NousResearch/hermes-agent/issues/76914"
click P76995 "https://github.com/NousResearch/hermes-agent/pull/76995"
Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label). Cross-PR triage: Reviewed 1 pull request and 1 issue in this complex. Each diff was read against this issue; Assessment working set: <1 kB of PR diffs, 4 kB of issue/PR text, 1 kB of discussion (2 comments), 2 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch. |
Summary
Kanban worker sessions completed their tasks but left
sessions.ended_atNULL instate.db(reproduced 2/2 runs). The worker exits via the quiet single-query CLI path, which never finalized the SQLite session.Root Cause
Kanban workers are spawned as
hermes -p <profile> --cli chat -q "work kanban task <id>"(hermes_cli/kanban_db.py:8964). The quiet path incli.py(_finalize_single_query, ~L1342) only notifies session-finalize hooks and runs cleanup — it never callsagent.close(), which is what invokessession_db.end_session(session_id, "agent_close")(run_agent.py:4150-4157, gated by_end_session_on_close, defaultTrue).The interactive
run()loop closes the session in itsfinallyblock (cli.py:17718-17721), but the quiet path bypasses it entirely. Comparehermes_cli/oneshot.py:461-481(hermes -zcallsagent.close()in its own finally) andcron/scheduler.py:3829-3832(end_session(..., "cron_complete")explicitly).Change
cli.py—_finalize_single_querynow callsagent.close()(defensively, viagetattr/callableso stub agents in tests are unaffected) before releasing the active session lease.close()is idempotent in the run loop path and triggersend_session→ended_atset.Verification
pytest tests/cli/test_single_query_session_finalize.py tests/cli/test_chat_q_exit_clear.py— 9 passedpytest tests/hermes_cli/test_kanban_lifecycle_hooks.py::test_claim_fires_hook tests/hermes_cli/test_kanban_write_guard.py— 4 passed-k kanbanrun reproduce on unpatchedupstream/main(pre-existing order-dependent flakes, not caused by this change)Closes #76914