Summary
Sessions (and entire worktrees) silently disappear from the sidebar even though their transcripts are intact on disk. They don't come back by reopening or restarting — the sidebar is rebuilt purely from the SQLite cache, and the cache never gets re-reconciled against the filesystem once it's populated.
Steps to reproduce
- Use Switchboard for a while so several projects/sessions are indexed.
- Quit Switchboard.
- While it's closed, have sessions change or new ones appear (normal CLI use, new worktrees, etc.). Or simply update Switchboard to a build whose indexing differs from the one that first populated the cache.
- Reopen Switchboard.
Expected: the sidebar reflects what's on disk under ~/.claude/projects/.
Actual: folders that weren't already in the cache show up empty (or not at all). Clicking them does nothing — there's nothing cached to show. The .jsonl transcripts are all still on disk.
Root cause
get-projects only triggers a filesystem scan when the cache is completely empty:
const needsPopulate = !isCachePopulated() || !isSearchIndexPopulated();
if (needsPopulate) {
populateCacheViaWorker(); // full scan, cold start only
return [];
}
return buildProjectsFromCache(showArchived); // otherwise: cache only, never reconciled
buildProjectsFromCache reads strictly from session_cache. After the first cold start the cache is non-empty forever, so:
- folders that changed while the app was closed are not re-scanned (the live
fs.watch only covers changes while running), and
- folders that were never indexed by the current build (their
cache_meta.indexMtimeMs is 0) stay invisible permanently.
populateCacheFromFilesystem() exists for exactly this kind of full reconcile but is dead code — defined and exported, never called.
Impact
Common and confusing: sessions appear "lost" after an app update or a normal quit/relaunch cycle, with no UI way to recover them (reopen/restart don't help). The only workaround is forcing a re-index (e.g. touch-ing the .jsonl to trip the watcher, or wiping the cache so the cold-start scan runs).
Proposed fix
Reconcile the cache against the filesystem on get-projects, gated by mtime so it's cheap when nothing changed: re-index only folders that are new or whose newest .jsonl is newer than cache_meta.indexMtimeMs. PR incoming.
Environment: Linux, Switchboard 0.0.30 (reproducible on current main).
Summary
Sessions (and entire worktrees) silently disappear from the sidebar even though their transcripts are intact on disk. They don't come back by reopening or restarting — the sidebar is rebuilt purely from the SQLite cache, and the cache never gets re-reconciled against the filesystem once it's populated.
Steps to reproduce
Expected: the sidebar reflects what's on disk under
~/.claude/projects/.Actual: folders that weren't already in the cache show up empty (or not at all). Clicking them does nothing — there's nothing cached to show. The
.jsonltranscripts are all still on disk.Root cause
get-projectsonly triggers a filesystem scan when the cache is completely empty:buildProjectsFromCachereads strictly fromsession_cache. After the first cold start the cache is non-empty forever, so:fs.watchonly covers changes while running), andcache_meta.indexMtimeMsis0) stay invisible permanently.populateCacheFromFilesystem()exists for exactly this kind of full reconcile but is dead code — defined and exported, never called.Impact
Common and confusing: sessions appear "lost" after an app update or a normal quit/relaunch cycle, with no UI way to recover them (reopen/restart don't help). The only workaround is forcing a re-index (e.g.
touch-ing the.jsonlto trip the watcher, or wiping the cache so the cold-start scan runs).Proposed fix
Reconcile the cache against the filesystem on
get-projects, gated by mtime so it's cheap when nothing changed: re-index only folders that are new or whose newest.jsonlis newer thancache_meta.indexMtimeMs. PR incoming.Environment: Linux, Switchboard 0.0.30 (reproducible on current
main).