Skip to content

Warm sidebar thread detail subscriptions#2001

Merged
juliusmarminge merged 2 commits intomainfrom
t3code/thread-subscription-cache-policy
Apr 13, 2026
Merged

Warm sidebar thread detail subscriptions#2001
juliusmarminge merged 2 commits intomainfrom
t3code/thread-subscription-cache-policy

Conversation

@juliusmarminge
Copy link
Copy Markdown
Member

@juliusmarminge juliusmarminge commented Apr 13, 2026

Summary

  • Prewarm thread detail subscriptions for the first visible sidebar threads so nearby navigation can reuse hot data.
  • Extend the thread-detail cache policy to keep non-idle threads sticky and only evict idle subscriptions.
  • Increase the idle TTL and cache capacity to reduce churn while navigating and working in active threads.
  • Add tests for sidebar prewarm selection and the updated subscription eviction behavior.

Testing

  • bun fmt
  • bun lint
  • bun typecheck
  • bun run test apps/web/src/components/Sidebar.logic.test.ts
  • bun run test apps/web/src/environments/runtime/service.threadSubscriptions.test.ts

Note

Medium Risk
Changes thread-detail subscription caching/eviction and adds background prewarming from the sidebar, which can affect memory/network usage and when subscriptions are released. Logic now depends on thread activity state to prevent eviction, so regressions could keep subscriptions alive longer than intended.

Overview
Prewarms thread-detail data for the first visible sidebar threads by retaining their detail subscriptions (default 10) while they remain visible, releasing them when the visible set changes.

Updates the runtime thread-detail subscription cache policy to be stickier for non-idle threads (pending approvals/input/plan, running turns, or non-idle orchestration), and to evict only idle unretained entries; idle TTL increases to 15 minutes and cache capacity to 32.

Adds unit tests covering getSidebarThreadIdsToPrewarm and the new eviction behavior (longer warm period, non-idle stickiness, and increased capacity before eviction).

Reviewed by Cursor Bugbot for commit a4afe8c. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Warm thread detail subscriptions for visible sidebar threads

  • The sidebar now retains thread detail subscriptions for up to 10 visible threads (SIDEBAR_THREAD_PREWARM_LIMIT) using retainThreadDetailSubscription, releasing them when threads leave the prewarmed set.
  • The thread detail subscription cache is expanded from 8 to 32 entries and the idle eviction timeout is increased from 2 to 15 minutes.
  • Non-idle threads (pending approvals, running turns, etc.) are exempt from eviction via a new isNonIdleThreadDetailSubscription helper in service.ts; eviction is deferred until the thread becomes idle.
  • Eviction schedules are reconciled after shell snapshot syncs, recovered event batches, and shell upserts to keep cache state consistent.
  • Behavioral Change: releasing a subscription no longer always schedules eviction — non-idle threads remain cached until idle, and capacity eviction only removes the least-recently-accessed idle entries.

Macroscope summarized a4afe8c.

- Prewarm visible sidebar threads
- Keep active thread subscriptions sticky until idle
- Expand cache capacity and add coverage
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 13, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 65d2f790-b9a8-4a72-937c-a2601d27dbcc

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/thread-subscription-cache-policy

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added size:L 100-499 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Apr 13, 2026
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Prewarm effect re-runs on every sidebar thread change
    • Replaced the prewarmedSidebarThreads memo (which depended on the frequently-changing sidebarThreadByKey map) with prewarmedSidebarThreadRefs that uses parseScopedThreadKey to extract stable identity pairs directly from prewarmedSidebarThreadKeys, breaking the dependency chain that caused unnecessary effect re-runs on every thread summary update.

Create PR

Or push these changes by commenting:

@cursor push 1017cc1156
Preview (1017cc1156)
diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx
--- a/apps/web/src/components/Sidebar.tsx
+++ b/apps/web/src/components/Sidebar.tsx
@@ -43,6 +43,7 @@
   type GitStatusResult,
 } from "@t3tools/contracts";
 import {
+  parseScopedThreadKey,
   scopedProjectKey,
   scopedThreadKey,
   scopeProjectRef,
@@ -2884,18 +2885,18 @@
     () => getSidebarThreadIdsToPrewarm(visibleSidebarThreadKeys),
     [visibleSidebarThreadKeys],
   );
-  const prewarmedSidebarThreads = useMemo(
+  const prewarmedSidebarThreadRefs = useMemo(
     () =>
       prewarmedSidebarThreadKeys.flatMap((threadKey) => {
-        const thread = sidebarThreadByKey.get(threadKey);
-        return thread ? [thread] : [];
+        const ref = parseScopedThreadKey(threadKey);
+        return ref ? [ref] : [];
       }),
-    [prewarmedSidebarThreadKeys, sidebarThreadByKey],
+    [prewarmedSidebarThreadKeys],
   );
 
   useEffect(() => {
-    const releases = prewarmedSidebarThreads.map((thread) =>
-      retainThreadDetailSubscription(thread.environmentId, thread.id),
+    const releases = prewarmedSidebarThreadRefs.map((ref) =>
+      retainThreadDetailSubscription(ref.environmentId, ref.threadId),
     );
 
     return () => {
@@ -2903,7 +2904,7 @@
         release();
       }
     };
-  }, [prewarmedSidebarThreads]);
+  }, [prewarmedSidebarThreadRefs]);
 
   useEffect(() => {
     const clearThreadJumpHints = () => {

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 9284b86. Configure here.

@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp bot commented Apr 13, 2026

Approvability

Verdict: Needs human review

This PR introduces a new feature that proactively warms thread subscriptions for visible sidebar items and significantly changes the subscription cache policy (longer TTL, larger cache, sticky non-idle threads). While the author owns this code and changes are well-tested, this is a new capability with runtime behavior implications around network subscriptions and resource management that warrants human review.

You can customize Macroscope's approvability policy. Learn more.

@juliusmarminge
Copy link
Copy Markdown
Member Author

@cursor push 1017cc1

…s on thread summary changes

The prewarmedSidebarThreads memo depended on sidebarThreadByKey, which is
recreated whenever any sidebar thread summary changes. Since the useEffect
only needs environmentId and threadId (stable identities), this caused
unnecessary cleanup/re-setup cycles for all prewarm subscriptions on every
thread status update.

Replace the thread-object lookup with parseScopedThreadKey to extract
identity pairs directly from the already-stable prewarmedSidebarThreadKeys,
breaking the dependency on the frequently-changing sidebarThreadByKey map.

Applied via @cursor push command
@juliusmarminge juliusmarminge merged commit 569fea8 into main Apr 13, 2026
12 checks passed
@juliusmarminge juliusmarminge deleted the t3code/thread-subscription-cache-policy branch April 13, 2026 20:55
juliusmarminge added a commit that referenced this pull request Apr 13, 2026
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants