Skip to content

fix: recover from premature session-end and improve dashboard stability#2

Open
damahua wants to merge 1 commit into
masterfrom
fix/premature-session-end-recovery
Open

fix: recover from premature session-end and improve dashboard stability#2
damahua wants to merge 1 commit into
masterfrom
fix/premature-session-end-recovery

Conversation

@damahua

@damahua damahua commented Mar 23, 2026

Copy link
Copy Markdown
Owner

Summary

  • Session recovery: premature SessionEnd (from resume/compact) no longer permanently loses session state — cleanOrphanedBuffers respects grace periods, stop hook reconstructs buffers, session-start cleans stale summaries on resume
  • Duplicate event prevention: atomic rename in flushEvents prevents parallel hooks from writing the same events twice; display-level dedup handles existing duplicates
  • Dashboard stability: viewport scroll is state-persisted (no more flowing on data refresh), mouse reporting disabled, idle sessions show amber indicator with duration, CLI sessions properly detected

Changes

Area What
session-store.mjs Grace period in cleanOrphanedBuffers, atomic flush, readBatchEvents(), start_time validation in appendEvent
session-start.mjs Remove stale finalized summaries on resume
stop.mjs Buffer reconstruction without start_time (avoids delta mismatch)
useTelemetry.ts Read .batch events, event deduplication
EventStream.tsx Viewport-aware rendering, idle duration display, stable scroll
StreamDetail.tsx Timeline deduplication (events + debug entries)
Dashboard.tsx Scroll state management, mouse event filtering
cli.tsx Disable terminal mouse reporting in fullscreen
Tests 9 new recovery tests + fixed stop.test.mjs transcript interface

Root cause

When a session resumes, Claude Code fires SessionEnd then SessionStart with the same session ID. The SessionEnd writes a finalized summary and deletes the buffer. When another session starts, cleanOrphanedBuffers sees the finalized summary and deletes any recreated buffer — permanently losing cost/token tracking for the still-active session.

Test plan

  • node --test tests/premature-session-end.test.mjs — 9 tests pass
  • node --test tests/stop.test.mjs — 4 tests pass
  • node --test tests/session-store.test.mjs tests/session-start.test.mjs tests/session-end.test.mjs — all pass
  • Manual testing: dashboard scroll stable, idle sessions visible, CLI sessions detected, no double tracking after removing duplicate hooks

🤖 Generated with Claude Code

A premature SessionEnd (e.g. from session resume) would delete the buffer
and write a finalized summary. Subsequent cleanOrphanedBuffers calls from
other sessions would then keep deleting the recreated buffer, causing lost
cost tracking, invisible events, and wrong timestamps.

Session recovery:
- cleanOrphanedBuffers: grace period prevents deleting recently-active
  buffers; removes stale finalized summaries instead
- session-start: removes stale summaries on resume so cleanup won't
  delete the new buffer
- stop: reconstructs buffer when missing (omits start_time to avoid
  delta timestamp mismatch); falls back to today's date
- appendEvent: validates buffer start_time before using it for delta
  encoding to prevent wrong timestamp restoration
- flushEvents: atomic rename prevents duplicate writes from parallel hooks

Dashboard fixes:
- Read pending .batch events so unflushed activity is visible
- Event deduplication in stream list, detail view, and debug entries
- Disable terminal mouse reporting to prevent scroll-on-click
- Viewport-aware stream list with stable scroll (state persisted in
  Dashboard, only updated on cursor movement)
- Idle sessions show amber indicator with duration ("idle 1h 45m")
- Idle count in collapsed group summaries
- Debug mode indicator checked independently of buffer decode
- CLI session detection improved (short sessions with ≤2 prompts)

Tests:
- New premature-session-end.test.mjs (9 tests covering full recovery)
- Fixed stop.test.mjs to use transcript files (matching actual interface)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant