Description
Session status spinners (the animated dot grid) persist indefinitely in the sidebar session list, even when sessions are actually idle on the server. This happens because bootstrapDirectory in bootstrap.ts uses setStore("session_status", x.data!) to sync session statuses from the server, but SolidJS's setStore merges object keys rather than replacing them.
When the server returns {} (all sessions idle), setStore("session_status", {}) iterates zero keys and does nothing — stale { type: "busy" } entries from previous SSE events are never removed.
The codebase already handles this correctly for permission and question (which manually iterate and clean old keys + use reconcile), but session_status was missed.
Root cause
In SolidJS's updatePath, when the path terminates at an existing store node and the value is a plain non-array object, it enters a merge loop:
for (const key in value) {
setProperty(current, key, value[key]);
}
Old keys not present in the new value are preserved. For session_status (a Record<string, SessionStatus>), this means stale session IDs with { type: "busy" } accumulate and are never cleared by bootstrap.
Fix
Use reconcile (already imported in bootstrap.ts) to properly replace the entire record:
// Before (merges, stale keys persist):
input.sdk.session.status().then((x) => input.setStore("session_status", x.data!))
// After (replaces, stale keys removed):
input.sdk.session.status().then((x) => input.setStore("session_status", reconcile(x.data!)))
Steps to reproduce
- Open the desktop app with multiple projects and sessions
- Have sessions that transition from busy → idle while SSE is briefly disconnected (or manipulate the DB externally)
- Observe that session spinners persist even after the sessions are idle
- Restarting the app does not fix the issue because SSE events can re-populate stale entries before bootstrap clears them
Operating System
macOS
Description
Session status spinners (the animated dot grid) persist indefinitely in the sidebar session list, even when sessions are actually idle on the server. This happens because
bootstrapDirectoryinbootstrap.tsusessetStore("session_status", x.data!)to sync session statuses from the server, but SolidJS'ssetStoremerges object keys rather than replacing them.When the server returns
{}(all sessions idle),setStore("session_status", {})iterates zero keys and does nothing — stale{ type: "busy" }entries from previous SSE events are never removed.The codebase already handles this correctly for
permissionandquestion(which manually iterate and clean old keys + usereconcile), butsession_statuswas missed.Root cause
In SolidJS's
updatePath, when the path terminates at an existing store node and the value is a plain non-array object, it enters a merge loop:Old keys not present in the new value are preserved. For
session_status(aRecord<string, SessionStatus>), this means stale session IDs with{ type: "busy" }accumulate and are never cleared by bootstrap.Fix
Use
reconcile(already imported in bootstrap.ts) to properly replace the entire record:Steps to reproduce
Operating System
macOS