Skip to content

perf(renderer): index unread completion tabs once per snapshot - #17246

Merged
nwparker merged 1 commit into
mainfrom
nwparker/perf-unread-agent-completion-tab-index
Aug 29, 2026
Merged

nwparker merged 1 commit into
mainfrom
nwparker/perf-unread-agent-completion-tab-index

Conversation

@nwparker

@nwparker nwparker commented Aug 29, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 1 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​55 0 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​55
Prod 1 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​35 $\color{#cf222e}{\Huge{\mathbf{−}}}$​15 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​20

ELI5

Every mounted terminal tab was rereading the entire unread-completion list whenever Zustand published any store update. With many tabs and markers, that made one harmless publication do the same long scan hundreds or thousands of times on the renderer thread.

This builds the list of owning tab IDs once for each immutable unread-map snapshot. Every tab then does one constant-time membership check. No notification, marker, tab, or feature is capped or disabled.

User-visible problem

SortableTab stays mounted for every terminal and agent-session tab. Its selector called hasUnreadAgentCompletionForTerminalTab, which scanned all U pane markers for each of T tabs on every store publication—even when React ultimately rendered nothing. Accumulated sessions could therefore turn background status/title writes into synchronous O(T × U) input and status latency.

Change

  • Cache ReadonlySet<tabId> by unreadAgentCompletionPanes object identity in a WeakMap.
  • Preserve truthy-marker filtering and the existing first-colon/no-colon ownership rule.
  • Let old snapshots and their indexes be garbage-collected; retained palette snapshots can coexist safely.
  • Reset the cache only in tests.

Production add, clear, close, hibernate, move, and purge paths already replace this map rather than mutating it in place; the test exercises add/clear through new snapshot identities.

Deterministic before / after

Node 24.18.0, actual helper, mostly-absent lookups, three samples per case. Before uses origin/main; after uses a fresh marker-map identity for every sample so index construction is included.

Mounted tabs Pane markers Before median After cold median Improvement
100 1,000 9.46 ms 0.15 ms 63×
100 10,000 128.29 ms 1.39 ms 92×
500 5,000 273.84 ms 0.70 ms 391×
1,000 10,000 1,245.73 ms 1.30 ms 958×

The committed structural regression test is timing-independent: 2,500 tab lookups over one 1,000-marker snapshot caused 2,500 enumerations / 2,500,000 marker reads before and exactly 1 enumeration / 1,000 reads after.

Parity measurements at 1,000 lookups × 10,000 markers kept identical hit counts for absent, first match, last match, explicit false, and legacy no-colon keys. After times were 1.13–1.46 ms versus 1,110.50–1,330.56 ms before.

Low-cardinality guard: one tab with an early match did not regress cold construction—at 10,000 markers it measured 1.157 ms before and 0.999 ms after; an absent match measured 1.267 ms before and 1.012 ms after.

Regression and compatibility proof

  • Exact booleans remain unchanged for canonical, numeric legacy, no-colon, multi-colon, prefix-collision, falsy, missing, add, and clear cases.
  • Adding or clearing one marker changes only its owning tab in the parity test.
  • Duplicate tab IDs retain the prior existential behavior; the cache does not infer worktree or host ownership.
  • Native, folder-workspace, WSL, direct-SSH, and paired/remote tab IDs remain opaque strings. There is no Git command, provider, process, RPC, stream, persisted-state, or remote-wire change.
  • WeakMap avoids strong retention and supports multiple concurrently retained snapshots.

Electron CDP validation used an isolated profile and the intended branch identity. On two real rendered terminal tabs, adding an unread completion marker to the inactive tab visibly applied the amber unread treatment only there; the real clear action removed the store marker and the treatment from both tabs. The only console errors were the pre-existing exhausted GitHub API limit.

Verification

  • pnpm tc
  • 78/78 related tests across terminal-tab status, SortableTab update-depth, Cmd+J live status, and recent tabs
  • pnpm run check:code-quality:changed — 0 findings
  • pnpm run check:max-lines-ratchet
  • targeted oxfmt
  • git diff --check
  • independent review: no blocking correctness issue

GitHub overlap and merge risk

Checked before editing. Merged PRs #13554 and #16173 cache/gate different unread projections; no active PR implements this per-tab index. Open PR #9318 is the only direct file overlap and still scans the marker map per tab, so this is not duplicate work.

  • Behavioral risk: low. Pure renderer-derived cache; no source-of-truth or user-facing behavior changes.
  • Compatibility risk: low. No platform, execution-host, Git, provider, or wire boundary is touched.
  • Textual/rebase risk: high. fix(opencode): make agent status lifecycle and chrome truthful #9318 rewrites the same status module and is currently stale/dirty. If it lands first, this must be rebased into its provider-aware resolver (likely indexing pane keys per tab, not only booleans) while retaining current false-marker semantics.
  • Backout: revert this single commit; there is no migration or external state.

@greptile-apps

greptile-apps Bot commented Aug 29, 2026

Copy link
Copy Markdown

Greptile Summary

This PR replaces repeated per-tab scans of unread completion markers with a snapshot-identity WeakMap index while preserving existing marker ownership and truthiness semantics.

  • Builds the owning-tab ID set once per immutable unread-marker snapshot.
  • Performs constant-time membership checks for each mounted terminal tab.
  • Adds parity, snapshot invalidation, legacy-key, falsy-marker, and structural performance coverage.

Confidence Score: 5/5

The PR appears safe to merge with no actionable correctness, security, or quality issues identified.

The cache preserves the prior ownership and truthy-marker behavior, while marker updates use replacement snapshots that naturally invalidate the identity-keyed index.

Important Files Changed

Filename Overview
src/renderer/src/components/tab-bar/terminal-tab-activity-status.ts Adds a garbage-collectable per-snapshot unread-tab index; all identified producers preserve its immutability requirement.
src/renderer/src/components/tab-bar/terminal-tab-activity-status.test.ts Extends behavioral parity coverage and verifies that one snapshot is enumerated only once across repeated tab lookups.

Reviews (1): Last reviewed commit: "perf(renderer): index unread completion ..." | Re-trigger Greptile

@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f0e7a413-4b0a-4b99-b4d3-8c38dbdf73e7

📥 Commits

Reviewing files that changed from the base of the PR and between a1f198b and 175fc3a.

📒 Files selected for processing (2)
  • src/renderer/src/components/tab-bar/terminal-tab-activity-status.test.ts
  • src/renderer/src/components/tab-bar/terminal-tab-activity-status.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The change adds a WeakMap cache keyed by immutable unread-marker snapshots. The cache stores terminal tab IDs with truthy unread markers. Tab lookups use the cached ID set. A test-only reset function clears the cache. Tests cover undefined markers, pane-key parsing, marker updates, cache reset behavior, and single-index reuse across repeated lookups.

Merge Risk: ⚪ Minimal · up to 175fc

The change reuses a per-snapshot tab lookup index to reduce repeated renderer work without changing unread-marker behavior or external interfaces. No actionable merge-blocking risk remains beyond normal checks and review.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is detailed and relevant, but it omits required template information. No linked issue is provided, and the required Visual Proof section is missing despite describing visible behavior … Add the required Linked Issue with an issue reference. Add a Visual Proof section with before-and-after attachments, or write N/A with a reason if the change has no visual or interaction impact. Include the required Testing, AI Disclosure, …
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: indexing unread completion tabs once per snapshot to improve renderer performance.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 2 files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description is detailed and relevant, but it omits required template information. No linked issue is provided, and the required Visual Proof section is missing despite describing visible behavior validation. Several template sections and checklist confirmations are also absent.

Resolution

Add the required Linked Issue with an issue reference. Add a Visual Proof section with before-and-after attachments, or write N/A with a reason if the change has no visual or interaction impact. Include the required Testing, AI Disclosure, Review, Agent skill upstream boundary, Notes, and Checklist sections, with applicable items completed or marked N/A.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@nwparker
nwparker merged commit 79aea81 into main Aug 29, 2026
27 checks passed
enrick-dev pushed a commit to enrick-dev/orca that referenced this pull request Oct 15, 2026
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