Skip to content

Fix session list freshness and unread indicators#470

Open
Liu-KM wants to merge 4 commits intotiann:mainfrom
Liu-KM:liu/pr-session-list-reminders
Open

Fix session list freshness and unread indicators#470
Liu-KM wants to merge 4 commits intotiann:mainfrom
Liu-KM:liu/pr-session-list-reminders

Conversation

@Liu-KM
Copy link
Copy Markdown

@Liu-KM Liu-KM commented Apr 16, 2026

Summary

Fix stale session-list state and add lightweight unread indicators for sessions that update while the user is looking elsewhere.

  • update sessions.updated_at whenever messages are stored or moved between sessions
  • keep a global SSE subscription active so the sidebar receives updates even when a specific session is selected
  • patch session-list timestamps immediately from message-received events
  • persist per-session last-seen timestamps in localStorage and show unread dots on sessions, project groups, and machines

Why

The sidebar could show stale thinking/status and stale relative times until a session was opened. This made completed sessions still look active and made it hard to tell which background sessions had new output.

Validation

  • cd hub && bun test src/sync/sessionModel.test.ts
  • cd web && bun test src/components/SessionList.test.ts
  • bun run typecheck:hub
  • bun run typecheck:web

Notes

AI-assisted with GPT-5.4.

@Liu-KM Liu-KM marked this pull request as ready for review April 16, 2026 15:48
Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Findings

  • [Major] Selected-session SSE connection never reports visibility changes — The new second useSSE call opens another /events?sessionId=... stream, but only the global subscriptionId is passed to useVisibilityReporter. That leaves the session-scoped subscription stuck with whatever visibility it had at connect time. Because push fallback checks hasVisibleConnection(namespace) before sending notifications, backgrounding the app after opening a session can suppress push delivery and keep routing toasts to a hidden tab instead. Evidence web/src/App.tsx:259, related context web/src/hooks/useVisibilityReporter.ts:13, hub/src/push/pushNotificationChannel.ts:39.
    Suggested fix:
    const { subscriptionId } = useSSE({ ...globalOptions })
    const { subscriptionId: sessionSubscriptionId } = useSSE({
        enabled: Boolean(api && token && selectedSessionId),
        token: token ?? '',
        baseUrl,
        subscription: sessionEventSubscription,
        onEvent: handleSseEvent
    })
    
    useVisibilityReporter({
        api,
        subscriptionId,
        enabled: Boolean(api && token)
    })
    useVisibilityReporter({
        api,
        subscriptionId: sessionSubscriptionId,
        enabled: Boolean(api && token && selectedSessionId)
    })

Summary

  • Review mode: initial
  • 1 finding. Main regression: the new per-session SSE stream can keep a hidden client marked visible, which suppresses push notifications for that namespace.

Testing

  • Not run (automation)

HAPI Bot

Comment thread web/src/App.tsx
onToast: handleToast
})

useSSE({
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[MAJOR] This second SSE stream never gets a visibility report. useVisibilityReporter only receives the global subscriptionId below, so this session-scoped subscription stays visible after a visible connect. PushNotificationChannel then sees hasVisibleConnection(namespace) and can skip push delivery even when the tab is hidden.

Suggested fix:

const { subscriptionId: sessionSubscriptionId } = useSSE({
    enabled: Boolean(api && token && selectedSessionId),
    token: token ?? '',
    baseUrl,
    subscription: sessionEventSubscription,
    onEvent: handleSseEvent
})

useVisibilityReporter({
    api,
    subscriptionId: sessionSubscriptionId,
    enabled: Boolean(api && token && selectedSessionId)
})

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