fix: sidebar session staleness and sort ordering#257
fix: sidebar session staleness and sort ordering#257mattleaverton wants to merge 3 commits intodanshapiro:mainfrom
Conversation
…urface The sidebar session list went stale because applySessionsPatch, setProjects, and mergeProjects only synced top-level state to the active surface window. When the sidebar wasn't active, its window state diverged from fresh data. Changes: - Add syncAllWindowsFromTopLevel() that propagates project data to every initialized window (skipping windows with active search queries) - Replace syncActiveWindowFromTopLevel calls in patch/merge/set paths - Surface errors in refreshVisibleSessionWindowSilently instead of swallowing - Add logging to sessionsThunks for refresh decisions and failures Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The activity sort mode segregated sessions by whether they had ratchetedActivity, always putting sessions with any local activity above those without — regardless of how stale that activity was. A session with ratchetedActivity from days ago sorted above a session with fresh server activity from seconds ago. Now uses Math.max(ratchetedActivity, lastActivityAt) so whichever timestamp is more recent wins. Also unified withTabs/withoutTabs to use the same compareByActivity function. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The activity sort mode used client-side ratchetedActivity timestamps (updated on every keystroke) to boost sessions above those with only server-side timestamps. This caused confusing ordering: stale sessions with old local activity sorted above genuinely recent sessions, and the displayed timestamps (server-side) didn't match the sort order. Tab pinning already handles the "I'm actively working here" signal. The ratchetedActivity layer on top added confusion without value. Activity sort now uses server-side lastActivityAt (same as recency), with tab pinning preserved. The sessionActivity store still exists but no longer feeds into the sort selector. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2391ad2005
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| dispatch(setSessionWindowError({ | ||
| surface, | ||
| loading: false, | ||
| error: error instanceof Error ? error.message : 'Background refresh failed', | ||
| })) |
There was a problem hiding this comment.
Keep loading kind intact during preserved refresh errors
When refreshVisibleSessionWindowSilently runs with preserveLoadingState: true (the search/requested-vs-visible drift path), this new setSessionWindowError dispatch clears loadingKind in the reducer even though the foreground request is still loading. That breaks the contract of preserveLoadingState and can hide the active search/loading indicator while the in-flight visible fetch is still running, which is especially reproducible when the background refresh fails transiently during a query transition.
Useful? React with 👍 / 👎.
Summary
applySessionsPatch,setProjects, andmergeProjectsonly calledsyncActiveWindowFromTopLevel(), which skipped the sidebar when it wasn't the active surface.refreshVisibleSessionWindowSilently. Failed refreshes now dispatchsetSessionWindowErrorand log warnings.sessionsThunks.tsfor refresh decisions and failures (previously zero observability).Test plan
🤖 Generated with Claude Code