Skip to content

fix: sidebar session staleness and sort ordering#257

Open
mattleaverton wants to merge 3 commits intodanshapiro:mainfrom
mattleaverton:fix/sidebar-session-staleness
Open

fix: sidebar session staleness and sort ordering#257
mattleaverton wants to merge 3 commits intodanshapiro:mainfrom
mattleaverton:fix/sidebar-session-staleness

Conversation

@mattleaverton
Copy link
Copy Markdown
Collaborator

Summary

  • WebSocket patches now sync to all session windows, not just the active surface. The sidebar went stale because applySessionsPatch, setProjects, and mergeProjects only called syncActiveWindowFromTopLevel(), which skipped the sidebar when it wasn't the active surface.
  • Removed ratchetedActivity from sidebar sort. The activity sort used client-side keystroke timestamps (updated on every keypress, persisted to localStorage) to boost sessions above those with only server-side timestamps. This caused confusing ordering where stale sessions appeared above genuinely recent ones, and displayed timestamps didn't match the sort order. Tab pinning already handles the "actively working here" signal.
  • Silent error swallowing replaced with error surfacing in refreshVisibleSessionWindowSilently. Failed refreshes now dispatch setSessionWindowError and log warnings.
  • Added logging to sessionsThunks.ts for refresh decisions and failures (previously zero observability).

Test plan

  • 5 new unit tests covering window sync, error surfacing, and sort behavior
  • 112 existing selector/thunk tests pass
  • Full suite: 2842 passed, 3 pre-existing failures (WSL paths + flaky socket)
  • Verified in Chrome: sidebar self-heals from stale localStorage, timestamps monotonically decreasing within each group

🤖 Generated with Claude Code

mattleaverton and others added 3 commits March 30, 2026 17:11
…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>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +429 to 432
dispatch(setSessionWindowError({
surface,
loading: false,
error: error instanceof Error ? error.message : 'Background refresh failed',
}))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

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