Skip to content

🤖 fix: unread indicators broken after sidebar redesign#2800

Merged
ethanndickson merged 3 commits intomainfrom
sidebar-n221
Mar 5, 2026
Merged

🤖 fix: unread indicators broken after sidebar redesign#2800
ethanndickson merged 3 commits intomainfrom
sidebar-n221

Conversation

@ethanndickson
Copy link
Member

@ethanndickson ethanndickson commented Mar 5, 2026

Summary

Fix unread indicators in the sidebar not appearing after stream completion on background workspaces. The stream-completion recency timestamp was stale, losing a race against the frontend's lastRead.

Background

handleStreamCompletion used extractTimestamp() which returned the message-creation timestamp from stream event metadata — effectively the same as the sendMessage recency. Since the frontend sets lastRead = Date.now() after the IPC round-trip (always slightly later than the backend's message timestamp), stream-end recency could never exceed lastRead, making unread indicators effectively impossible for background workspaces.

Timeline from debug instrumentation showing the race:

lastRead:sendMessage = 1772691545058    ← frontend Date.now() after IPC
activity recency     → 1772691545023    ← backend message-creation timestamp (35ms behind!)
eval: recency < lastRead → read         ← unread indicator never shows

Implementation

Recency timestamphandleStreamCompletion now always uses Date.now() at actual completion time instead of the stale extractTimestamp value. Removed the now-unused extractTimestamp helper. This ensures the completion recency is strictly after any earlier lastRead write.

Test helper — Updated getWorkspaceUnreadIndicator in the unread test to match the current StatusDot component: queries for bg-surface-invert-secondary (the idle dot class) and checks opacity-0 instead of the removed aria-hidden attribute from the old SelectionBar.

Validation

  • Typecheck passes
  • User-confirmed: unread indicators now appear reliably after stream completion on background workspaces
  • Diagnosed via targeted console.debug instrumentation (removed before merge)

Generated with mux • Model: anthropic:claude-opus-4-6 • Thinking: xhigh • Cost: $N/A

- Change idle StatusDot color from bg-surface-invert-secondary (nearly
  invisible against dark sidebar) to bg-muted-foreground
- Update test helper to detect visibility via opacity-0 class check
  instead of stale aria-hidden attribute from old SelectionBar
handleStreamCompletion was using extractTimestamp() which returned the
message-creation timestamp from stream event metadata — effectively the
same time as the sendMessage recency. Since the frontend sets lastRead
via Date.now() after the IPC round-trip (always slightly later), the
stream-end recency could never exceed lastRead, making the unread
indicator invisible for background workspaces.

Now handleStreamCompletion always uses Date.now() at actual completion
time, ensuring recency is strictly after any earlier lastRead write.
@ethanndickson ethanndickson enabled auto-merge March 5, 2026 06:59
@ethanndickson ethanndickson added this pull request to the merge queue Mar 5, 2026
Merged via the queue into main with commit 0b7370d Mar 5, 2026
23 checks passed
@ethanndickson ethanndickson deleted the sidebar-n221 branch March 5, 2026 07:09
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