Skip to content

fix: end TUI sessions in state.db to prevent ghost rows in /resume#18283

Closed
luyao618 wants to merge 1 commit into
NousResearch:mainfrom
luyao618:fix/tui-ghost-sessions-end-session
Closed

fix: end TUI sessions in state.db to prevent ghost rows in /resume#18283
luyao618 wants to merge 1 commit into
NousResearch:mainfrom
luyao618:fix/tui-ghost-sessions-end-session

Conversation

@luyao618

@luyao618 luyao618 commented May 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #18269 — TUI sessions created eagerly in state.db were never marked as ended, leaving ghost rows (with ended_at=NULL, message_count=0) cluttering /resume.

Problem

_finalize_session() committed memory and fired hooks but never called db.end_session(). By contrast, CLI properly calls end_session() on quit, /new, /branch, and /resume. Every TUI session — even ones closed immediately without sending a message — persisted as an open row in the sessions table.

Changes

tui_gateway/server.py

  • _finalize_session() now accepts an end_reason parameter (default "tui_close") and calls db.end_session(session_key, end_reason) after the existing memory-commit and hook logic. Wrapped in try/except to avoid disrupting finalization if DB is unavailable.
  • _shutdown_sessions() passes end_reason="tui_shutdown" to distinguish atexit cleanup.
  • session.branch handler now calls db.end_session(old_key, "branched") on the parent session, mirroring CLI behavior.

tests/tui_gateway/test_ghost_sessions.py (new)

  • 5 tests verifying: end_session is called with correct reason, no double-finalize, graceful handling when DB is None or raises.

Testing

pytest tests/tui_gateway/ -v  # 70 passed (including 5 new)

No changes to hermes_state.py or CLI — the SessionDB.end_session() API already exists and is battle-tested.

TUI sessions were eagerly created in state.db during session.create but
never marked as ended — _finalize_session() and _shutdown_sessions()
committed memory and fired hooks but skipped db.end_session(). This left
every abandoned or normally-closed TUI session with ended_at=NULL,
cluttering /resume with ghost rows.

Add db.end_session() call to _finalize_session() with appropriate
end_reason for each code path:
- session.close → "tui_close"
- session.branch → "branched" (mirrors CLI behavior)
- atexit shutdown → "tui_shutdown"

The call is wrapped in try/except to avoid disrupting the existing
finalization flow if the DB is unavailable or locked.

Closes NousResearch#18269
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/tui Terminal UI (ui-tui/ + tui_gateway/) labels May 1, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Superseded by #18370 which includes this fix (adapted with credit — see tui_gateway/server.py _finalize_session change). Thank you @luyao618!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tui Terminal UI (ui-tui/ + tui_gateway/) P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: TUI eagerly persists empty sessions to DB — ghost sessions clutter /resume

2 participants