Bug Description — CRITICAL: Silent data loss
pruneInvalidIndexEntries (store.go:1211-1229) deletes session files when !ses.HasUserInteraction(). But HasUserInteraction() (line 625) scans in-memory ses.Messages, and with the default fullLoad=false, loadSession (line 699) applies time-windowed loading: when a session has >=500 messages and the last message is older than RecentMessageWindow (24h), only the tail messages are loaded into ses.Messages.
Trigger: A session with >=500 messages, idle >24h, ending with an assistant/tool message (the normal case — the last message is almost always the assistant's reply). The next List() call triggers scheduleMaintenanceLocked → runMaintenance → pruneInvalidIndexEntries. loadSession returns a session whose Messages contains only non-user tail messages → HasUserInteraction() returns false → the entire .jsonl file is deleted, permanently destroying the conversation.
This runs automatically in the background, at least once per 30s while a session list is rendered — no user action required.
Impact
- Silent, irreversible loss of user conversation data for any large session idle for >24h
- Runs automatically without user action
- The session file is permanently deleted, not just hidden
Location
internal/session/store.go:1211-1229 — pruneInvalidIndexEntries deletes based on in-memory HasUserInteraction()
internal/session/store.go:625 — HasUserInteraction() scans in-memory messages only
internal/session/store.go:795-800 — time-windowed loading excludes old messages from ses.Messages
Fix
pruneInvalidIndexEntries must never delete based on a time-windowed load. Either:
- Pass
fullLoad=true when validating for deletion, or
- Gate deletion on the on-disk file (scan for any user-message record in the JSONL) instead of in-memory
Messages
Severity
Critical — Silent permanent data loss of user conversations. This is the most severe bug found in the codebase review.
Bug Description — CRITICAL: Silent data loss
pruneInvalidIndexEntries(store.go:1211-1229) deletes session files when!ses.HasUserInteraction(). ButHasUserInteraction()(line 625) scans in-memoryses.Messages, and with the defaultfullLoad=false,loadSession(line 699) applies time-windowed loading: when a session has >=500 messages and the last message is older thanRecentMessageWindow(24h), only the tail messages are loaded intoses.Messages.Trigger: A session with >=500 messages, idle >24h, ending with an assistant/tool message (the normal case — the last message is almost always the assistant's reply). The next
List()call triggersscheduleMaintenanceLocked→runMaintenance→pruneInvalidIndexEntries.loadSessionreturns a session whoseMessagescontains only non-user tail messages →HasUserInteraction()returns false → the entire.jsonlfile is deleted, permanently destroying the conversation.This runs automatically in the background, at least once per 30s while a session list is rendered — no user action required.
Impact
Location
internal/session/store.go:1211-1229—pruneInvalidIndexEntriesdeletes based on in-memoryHasUserInteraction()internal/session/store.go:625—HasUserInteraction()scans in-memory messages onlyinternal/session/store.go:795-800— time-windowed loading excludes old messages fromses.MessagesFix
pruneInvalidIndexEntriesmust never delete based on a time-windowed load. Either:fullLoad=truewhen validating for deletion, orMessagesSeverity
Critical — Silent permanent data loss of user conversations. This is the most severe bug found in the codebase review.