perf(orchestration): bound in-memory read model and client per-thread state - #4176

Closed
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup
Closed

perf(orchestration): bound in-memory read model and client per-thread state#4176
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup

Conversation

@RusiruSadathana

@RusiruSadathanaRusiruSadathana commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What Changed

Server: replaced the array-backed in-memory orchestration command read model with a HashMap-keyed CommandReadModel. Thread and project lookups and updates are now O(1) instead of O(N) linear scans plus full-array copies on every event, and deleted threads are evicted from the in-memory model (archived threads are retained because unarchive needs them and the projection cannot rehydrate them). The wire OrchestrationReadModel contract is unchanged; it is served by the DB-backed projection, which is untouched.

Web: wired the existing but previously uncalled per-thread cleanup into the thread deletion flow (preview state, right panel, diff panel, ui state), switched previewStateAtom from keepAlive to an idle TTL so idle preview atoms are collected, and made a released browser surface delete its entry instead of leaving a tombstone.

VCS: the VcsStatusBroadcaster per-cwd status cache is now pruned when the last poller subscriber releases, instead of growing for the process lifetime.

Added unit and integration coverage for the read model, projector eviction, decider behavior against a deleted thread, and the client store cleanup.

Why

After long uptime the server RSS and CPU climbed and the web UI became laggy. The cause was unbounded in-memory state on the single orchestration worker fiber (every event did O(N) work over a collection that never shed deleted or archived threads) compounded by client stores that accumulated one entry per thread ever visited and were never pruned on deletion. Making the hot-path structures O(1), evicting dead threads, and pruning the client and VCS caches removes the growth without changing any external contract or the projection that serves reads.

UI Changes

No visible UI changes. The web portion only prunes per-thread client state on deletion and adjusts atom retention; sidebar and panel behavior are unchanged.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (not applicable)
  • I included a video for animation/interaction changes (not applicable)

Related Issues

Closes#4178.


Note

Medium Risk
Orchestration command-path behavior changes (deleted-thread eviction and id retention) affect invariant checks and decider/projector semantics; web/VCS changes are localized leak fixes with tests.

Overview
Addresses unbounded memory growth on long-running server and web sessions by changing how hot-path state is stored and when it is dropped.

Server orchestration introduces an internal CommandReadModel (HashMap/HashSet) for the serial command worker, replacing array scans on every event. thread.deletedevicts thread bodies from memory while deletedThreadIds preserves the “cannot create twice” invariant across restarts; boot seeds via fromWireReadModel with dropDeletedThreads: true. The wire OrchestrationReadModel and DB projection are unchanged.

Web wires per-thread cleanup into thread delete (preview, right panel, diff panel, UI state in localStorage), switches previewStateAtom from keepAlive to a 5-minute idle TTL, and removes browser surface entries on release instead of tombstones.

VCS evicts per-cwd cache when the last remote poller releases, fixing a race where concurrent retain/release could leave stale entries forever.

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

Note

Bound in-memory orchestration read model and client per-thread state to prevent unbounded growth

  • Replaces array-backed OrchestrationReadModel with a CommandReadModel backed by HashMap for O(1) lookups of threads and projects in commandReadModel.ts.
  • Deleted threads are evicted from the in-memory projector state and their IDs tracked in a HashSet, preventing memory growth and blocking re-creation of deleted thread IDs.
  • The VcsStatusBroadcaster now atomically evicts cached VCS status when the last subscriber releases a poller, closing a race condition.
  • Deleting a thread in the client now clears its associated state across preview, right-panel, diff-panel, and UI stores in useThreadActions.ts.
  • Idle per-thread preview atoms are evicted after 5 minutes via Atom.setIdleTTL instead of Atom.keepAlive.
  • Behavioral Change: released browser surface store entries are deleted entirely rather than retained as tombstones with visible=false.

Macroscope summarized 56b6615.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 20, 2026
@coderabbitai

coderabbitaiBot commented Jul 20, 2026

Copy link
Copy Markdown

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: 30f20953-b942-43f8-bcf8-3a2f69a5f75f

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

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.

Comment threadapps/server/src/orchestration/projector.ts
Comment threadapps/server/src/vcs/VcsStatusBroadcaster.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. Cross-cutting performance refactor affecting memory management in orchestration engine and multiple client stores. Unresolved review comments include a high-severity issue where the preview index keys may still grow unbounded despite the eviction changes.

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

@RusiruSadathana
RusiruSadathanaforce-pushed the pr/read-model-and-store-cleanup branch from 7b31cf8 to e30b77fCompareJuly 20, 2026 07:45
… state (Issue pingdotgg#4178)
Replays PR pingdotgg#4176 on current main and preserves the connection catch-up path from pingdotgg#4177.
Replace the array-backed command model with HashMap/HashSet state, evict deleted thread bodies, prune released VCS and browser caches, and clear per-thread client state.
Adds focused coverage for read-model invariants, deletion behavior, client cleanup, and VCS cache eviction after the final subscriber releases.
Co-authored-by: codex <codex@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium

presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current){
return{
byTabId: {
...state.byTabId,
[tabId]: {
rect: null,
visible: false,
content,
updatedAt: Date.now(),
owner: null,
},
},
};
}

release deletes the entry from byTabId, but presentContent is owner-independent and recreates a { owner: null } entry whenever the entry is missing. If HostedBrowserWebview fires a scheduled layout or scroll update after the lease has released, presentContent resurrects the deleted entry, so released tabs still accumulate in byTabId — defeating the bounded-state goal of this change. Consider guarding presentContent so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new owner: null entry.

Suggested change
presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current)returnstate;
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/browser/browserSurfaceStore.ts around lines 104-120:
`release` deletes the entry from `byTabId`, but `presentContent` is owner-independent and recreates a `{ owner: null }` entry whenever the entry is missing. If `HostedBrowserWebview` fires a scheduled layout or scroll update after the lease has released, `presentContent` resurrects the deleted entry, so released tabs still accumulate in `byTabId` — defeating the bounded-state goal of this change. Consider guarding `presentContent` so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new `owner: null` entry.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Idle preview TTL drops tab suppressions

Medium Severity

Introducing Atom.setIdleTTL on previewStateAtom causes client-only suppressedTabIds to be lost when a thread's preview state is evicted. This results in preview tabs that a user previously closed reappearing from the server list.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Preview index keys never pruned

High Severity

activePreviewThreadKeysAtom is keepAlive and only updated via syncActivePreviewThread on explicit preview writes. When previewStateAtom idle TTL evicts a thread that still had sessions, the index entry is never removed, so the key set grows without bound and activePreviewSessionsAtom keeps scanning stale keys.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

@danieliserdanieliser mentioned this pull request Jul 22, 2026
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza added a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 28, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 1, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
omegent-appBot pushed a commit to patroza/t3code that referenced this pull request Aug 6, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Orchestration read model and per-thread client/VCS state grow unbounded over uptime

2 participants

@RusiruSadathana@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

perf(orchestration): bound in-memory read model and client per-thread state - #4176

Closed
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup
Closed

perf(orchestration): bound in-memory read model and client per-thread state#4176
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup

Conversation

@RusiruSadathana

@RusiruSadathanaRusiruSadathana commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What Changed

Server: replaced the array-backed in-memory orchestration command read model with a HashMap-keyed CommandReadModel. Thread and project lookups and updates are now O(1) instead of O(N) linear scans plus full-array copies on every event, and deleted threads are evicted from the in-memory model (archived threads are retained because unarchive needs them and the projection cannot rehydrate them). The wire OrchestrationReadModel contract is unchanged; it is served by the DB-backed projection, which is untouched.

Web: wired the existing but previously uncalled per-thread cleanup into the thread deletion flow (preview state, right panel, diff panel, ui state), switched previewStateAtom from keepAlive to an idle TTL so idle preview atoms are collected, and made a released browser surface delete its entry instead of leaving a tombstone.

VCS: the VcsStatusBroadcaster per-cwd status cache is now pruned when the last poller subscriber releases, instead of growing for the process lifetime.

Added unit and integration coverage for the read model, projector eviction, decider behavior against a deleted thread, and the client store cleanup.

Why

After long uptime the server RSS and CPU climbed and the web UI became laggy. The cause was unbounded in-memory state on the single orchestration worker fiber (every event did O(N) work over a collection that never shed deleted or archived threads) compounded by client stores that accumulated one entry per thread ever visited and were never pruned on deletion. Making the hot-path structures O(1), evicting dead threads, and pruning the client and VCS caches removes the growth without changing any external contract or the projection that serves reads.

UI Changes

No visible UI changes. The web portion only prunes per-thread client state on deletion and adjusts atom retention; sidebar and panel behavior are unchanged.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (not applicable)
  • I included a video for animation/interaction changes (not applicable)

Related Issues

Closes#4178.


Note

Medium Risk
Orchestration command-path behavior changes (deleted-thread eviction and id retention) affect invariant checks and decider/projector semantics; web/VCS changes are localized leak fixes with tests.

Overview
Addresses unbounded memory growth on long-running server and web sessions by changing how hot-path state is stored and when it is dropped.

Server orchestration introduces an internal CommandReadModel (HashMap/HashSet) for the serial command worker, replacing array scans on every event. thread.deletedevicts thread bodies from memory while deletedThreadIds preserves the “cannot create twice” invariant across restarts; boot seeds via fromWireReadModel with dropDeletedThreads: true. The wire OrchestrationReadModel and DB projection are unchanged.

Web wires per-thread cleanup into thread delete (preview, right panel, diff panel, UI state in localStorage), switches previewStateAtom from keepAlive to a 5-minute idle TTL, and removes browser surface entries on release instead of tombstones.

VCS evicts per-cwd cache when the last remote poller releases, fixing a race where concurrent retain/release could leave stale entries forever.

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

Note

Bound in-memory orchestration read model and client per-thread state to prevent unbounded growth

  • Replaces array-backed OrchestrationReadModel with a CommandReadModel backed by HashMap for O(1) lookups of threads and projects in commandReadModel.ts.
  • Deleted threads are evicted from the in-memory projector state and their IDs tracked in a HashSet, preventing memory growth and blocking re-creation of deleted thread IDs.
  • The VcsStatusBroadcaster now atomically evicts cached VCS status when the last subscriber releases a poller, closing a race condition.
  • Deleting a thread in the client now clears its associated state across preview, right-panel, diff-panel, and UI stores in useThreadActions.ts.
  • Idle per-thread preview atoms are evicted after 5 minutes via Atom.setIdleTTL instead of Atom.keepAlive.
  • Behavioral Change: released browser surface store entries are deleted entirely rather than retained as tombstones with visible=false.

Macroscope summarized 56b6615.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 20, 2026
@coderabbitai

coderabbitaiBot commented Jul 20, 2026

Copy link
Copy Markdown

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: 30f20953-b942-43f8-bcf8-3a2f69a5f75f

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

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.

Comment threadapps/server/src/orchestration/projector.ts
Comment threadapps/server/src/vcs/VcsStatusBroadcaster.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. Cross-cutting performance refactor affecting memory management in orchestration engine and multiple client stores. Unresolved review comments include a high-severity issue where the preview index keys may still grow unbounded despite the eviction changes.

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

@RusiruSadathana
RusiruSadathanaforce-pushed the pr/read-model-and-store-cleanup branch from 7b31cf8 to e30b77fCompareJuly 20, 2026 07:45
… state (Issue pingdotgg#4178)
Replays PR pingdotgg#4176 on current main and preserves the connection catch-up path from pingdotgg#4177.
Replace the array-backed command model with HashMap/HashSet state, evict deleted thread bodies, prune released VCS and browser caches, and clear per-thread client state.
Adds focused coverage for read-model invariants, deletion behavior, client cleanup, and VCS cache eviction after the final subscriber releases.
Co-authored-by: codex <codex@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium

presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current){
return{
byTabId: {
...state.byTabId,
[tabId]: {
rect: null,
visible: false,
content,
updatedAt: Date.now(),
owner: null,
},
},
};
}

release deletes the entry from byTabId, but presentContent is owner-independent and recreates a { owner: null } entry whenever the entry is missing. If HostedBrowserWebview fires a scheduled layout or scroll update after the lease has released, presentContent resurrects the deleted entry, so released tabs still accumulate in byTabId — defeating the bounded-state goal of this change. Consider guarding presentContent so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new owner: null entry.

Suggested change
presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current)returnstate;
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/browser/browserSurfaceStore.ts around lines 104-120:
`release` deletes the entry from `byTabId`, but `presentContent` is owner-independent and recreates a `{ owner: null }` entry whenever the entry is missing. If `HostedBrowserWebview` fires a scheduled layout or scroll update after the lease has released, `presentContent` resurrects the deleted entry, so released tabs still accumulate in `byTabId` — defeating the bounded-state goal of this change. Consider guarding `presentContent` so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new `owner: null` entry.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Idle preview TTL drops tab suppressions

Medium Severity

Introducing Atom.setIdleTTL on previewStateAtom causes client-only suppressedTabIds to be lost when a thread's preview state is evicted. This results in preview tabs that a user previously closed reappearing from the server list.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Preview index keys never pruned

High Severity

activePreviewThreadKeysAtom is keepAlive and only updated via syncActivePreviewThread on explicit preview writes. When previewStateAtom idle TTL evicts a thread that still had sessions, the index entry is never removed, so the key set grows without bound and activePreviewSessionsAtom keeps scanning stale keys.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

@danieliserdanieliser mentioned this pull request Jul 22, 2026
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza added a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 28, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 1, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
omegent-appBot pushed a commit to patroza/t3code that referenced this pull request Aug 6, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Orchestration read model and per-thread client/VCS state grow unbounded over uptime

2 participants

@RusiruSadathana@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(orchestration): bound in-memory read model and client per-thread state - #4176

Closed
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup
Closed

perf(orchestration): bound in-memory read model and client per-thread state#4176
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup

Conversation

@RusiruSadathana

@RusiruSadathanaRusiruSadathana commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What Changed

Server: replaced the array-backed in-memory orchestration command read model with a HashMap-keyed CommandReadModel. Thread and project lookups and updates are now O(1) instead of O(N) linear scans plus full-array copies on every event, and deleted threads are evicted from the in-memory model (archived threads are retained because unarchive needs them and the projection cannot rehydrate them). The wire OrchestrationReadModel contract is unchanged; it is served by the DB-backed projection, which is untouched.

Web: wired the existing but previously uncalled per-thread cleanup into the thread deletion flow (preview state, right panel, diff panel, ui state), switched previewStateAtom from keepAlive to an idle TTL so idle preview atoms are collected, and made a released browser surface delete its entry instead of leaving a tombstone.

VCS: the VcsStatusBroadcaster per-cwd status cache is now pruned when the last poller subscriber releases, instead of growing for the process lifetime.

Added unit and integration coverage for the read model, projector eviction, decider behavior against a deleted thread, and the client store cleanup.

Why

After long uptime the server RSS and CPU climbed and the web UI became laggy. The cause was unbounded in-memory state on the single orchestration worker fiber (every event did O(N) work over a collection that never shed deleted or archived threads) compounded by client stores that accumulated one entry per thread ever visited and were never pruned on deletion. Making the hot-path structures O(1), evicting dead threads, and pruning the client and VCS caches removes the growth without changing any external contract or the projection that serves reads.

UI Changes

No visible UI changes. The web portion only prunes per-thread client state on deletion and adjusts atom retention; sidebar and panel behavior are unchanged.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (not applicable)
  • I included a video for animation/interaction changes (not applicable)

Related Issues

Closes#4178.


Note

Medium Risk
Orchestration command-path behavior changes (deleted-thread eviction and id retention) affect invariant checks and decider/projector semantics; web/VCS changes are localized leak fixes with tests.

Overview
Addresses unbounded memory growth on long-running server and web sessions by changing how hot-path state is stored and when it is dropped.

Server orchestration introduces an internal CommandReadModel (HashMap/HashSet) for the serial command worker, replacing array scans on every event. thread.deletedevicts thread bodies from memory while deletedThreadIds preserves the “cannot create twice” invariant across restarts; boot seeds via fromWireReadModel with dropDeletedThreads: true. The wire OrchestrationReadModel and DB projection are unchanged.

Web wires per-thread cleanup into thread delete (preview, right panel, diff panel, UI state in localStorage), switches previewStateAtom from keepAlive to a 5-minute idle TTL, and removes browser surface entries on release instead of tombstones.

VCS evicts per-cwd cache when the last remote poller releases, fixing a race where concurrent retain/release could leave stale entries forever.

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

Note

Bound in-memory orchestration read model and client per-thread state to prevent unbounded growth

  • Replaces array-backed OrchestrationReadModel with a CommandReadModel backed by HashMap for O(1) lookups of threads and projects in commandReadModel.ts.
  • Deleted threads are evicted from the in-memory projector state and their IDs tracked in a HashSet, preventing memory growth and blocking re-creation of deleted thread IDs.
  • The VcsStatusBroadcaster now atomically evicts cached VCS status when the last subscriber releases a poller, closing a race condition.
  • Deleting a thread in the client now clears its associated state across preview, right-panel, diff-panel, and UI stores in useThreadActions.ts.
  • Idle per-thread preview atoms are evicted after 5 minutes via Atom.setIdleTTL instead of Atom.keepAlive.
  • Behavioral Change: released browser surface store entries are deleted entirely rather than retained as tombstones with visible=false.

Macroscope summarized 56b6615.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 20, 2026
@coderabbitai

coderabbitaiBot commented Jul 20, 2026

Copy link
Copy Markdown

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: 30f20953-b942-43f8-bcf8-3a2f69a5f75f

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

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.

Comment threadapps/server/src/orchestration/projector.ts
Comment threadapps/server/src/vcs/VcsStatusBroadcaster.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. Cross-cutting performance refactor affecting memory management in orchestration engine and multiple client stores. Unresolved review comments include a high-severity issue where the preview index keys may still grow unbounded despite the eviction changes.

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

@RusiruSadathana
RusiruSadathanaforce-pushed the pr/read-model-and-store-cleanup branch from 7b31cf8 to e30b77fCompareJuly 20, 2026 07:45
… state (Issue pingdotgg#4178)
Replays PR pingdotgg#4176 on current main and preserves the connection catch-up path from pingdotgg#4177.
Replace the array-backed command model with HashMap/HashSet state, evict deleted thread bodies, prune released VCS and browser caches, and clear per-thread client state.
Adds focused coverage for read-model invariants, deletion behavior, client cleanup, and VCS cache eviction after the final subscriber releases.
Co-authored-by: codex <codex@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium

presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current){
return{
byTabId: {
...state.byTabId,
[tabId]: {
rect: null,
visible: false,
content,
updatedAt: Date.now(),
owner: null,
},
},
};
}

release deletes the entry from byTabId, but presentContent is owner-independent and recreates a { owner: null } entry whenever the entry is missing. If HostedBrowserWebview fires a scheduled layout or scroll update after the lease has released, presentContent resurrects the deleted entry, so released tabs still accumulate in byTabId — defeating the bounded-state goal of this change. Consider guarding presentContent so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new owner: null entry.

Suggested change
presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current)returnstate;
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/browser/browserSurfaceStore.ts around lines 104-120:
`release` deletes the entry from `byTabId`, but `presentContent` is owner-independent and recreates a `{ owner: null }` entry whenever the entry is missing. If `HostedBrowserWebview` fires a scheduled layout or scroll update after the lease has released, `presentContent` resurrects the deleted entry, so released tabs still accumulate in `byTabId` — defeating the bounded-state goal of this change. Consider guarding `presentContent` so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new `owner: null` entry.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Idle preview TTL drops tab suppressions

Medium Severity

Introducing Atom.setIdleTTL on previewStateAtom causes client-only suppressedTabIds to be lost when a thread's preview state is evicted. This results in preview tabs that a user previously closed reappearing from the server list.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Preview index keys never pruned

High Severity

activePreviewThreadKeysAtom is keepAlive and only updated via syncActivePreviewThread on explicit preview writes. When previewStateAtom idle TTL evicts a thread that still had sessions, the index entry is never removed, so the key set grows without bound and activePreviewSessionsAtom keeps scanning stale keys.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

@danieliserdanieliser mentioned this pull request Jul 22, 2026
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza added a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 28, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 1, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
omegent-appBot pushed a commit to patroza/t3code that referenced this pull request Aug 6, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Orchestration read model and per-thread client/VCS state grow unbounded over uptime

2 participants

@RusiruSadathana@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(orchestration): bound in-memory read model and client per-thread state - #4176

Closed
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup
Closed

perf(orchestration): bound in-memory read model and client per-thread state#4176
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup

Conversation

@RusiruSadathana

@RusiruSadathanaRusiruSadathana commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What Changed

Server: replaced the array-backed in-memory orchestration command read model with a HashMap-keyed CommandReadModel. Thread and project lookups and updates are now O(1) instead of O(N) linear scans plus full-array copies on every event, and deleted threads are evicted from the in-memory model (archived threads are retained because unarchive needs them and the projection cannot rehydrate them). The wire OrchestrationReadModel contract is unchanged; it is served by the DB-backed projection, which is untouched.

Web: wired the existing but previously uncalled per-thread cleanup into the thread deletion flow (preview state, right panel, diff panel, ui state), switched previewStateAtom from keepAlive to an idle TTL so idle preview atoms are collected, and made a released browser surface delete its entry instead of leaving a tombstone.

VCS: the VcsStatusBroadcaster per-cwd status cache is now pruned when the last poller subscriber releases, instead of growing for the process lifetime.

Added unit and integration coverage for the read model, projector eviction, decider behavior against a deleted thread, and the client store cleanup.

Why

After long uptime the server RSS and CPU climbed and the web UI became laggy. The cause was unbounded in-memory state on the single orchestration worker fiber (every event did O(N) work over a collection that never shed deleted or archived threads) compounded by client stores that accumulated one entry per thread ever visited and were never pruned on deletion. Making the hot-path structures O(1), evicting dead threads, and pruning the client and VCS caches removes the growth without changing any external contract or the projection that serves reads.

UI Changes

No visible UI changes. The web portion only prunes per-thread client state on deletion and adjusts atom retention; sidebar and panel behavior are unchanged.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (not applicable)
  • I included a video for animation/interaction changes (not applicable)

Related Issues

Closes#4178.


Note

Medium Risk
Orchestration command-path behavior changes (deleted-thread eviction and id retention) affect invariant checks and decider/projector semantics; web/VCS changes are localized leak fixes with tests.

Overview
Addresses unbounded memory growth on long-running server and web sessions by changing how hot-path state is stored and when it is dropped.

Server orchestration introduces an internal CommandReadModel (HashMap/HashSet) for the serial command worker, replacing array scans on every event. thread.deletedevicts thread bodies from memory while deletedThreadIds preserves the “cannot create twice” invariant across restarts; boot seeds via fromWireReadModel with dropDeletedThreads: true. The wire OrchestrationReadModel and DB projection are unchanged.

Web wires per-thread cleanup into thread delete (preview, right panel, diff panel, UI state in localStorage), switches previewStateAtom from keepAlive to a 5-minute idle TTL, and removes browser surface entries on release instead of tombstones.

VCS evicts per-cwd cache when the last remote poller releases, fixing a race where concurrent retain/release could leave stale entries forever.

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

Note

Bound in-memory orchestration read model and client per-thread state to prevent unbounded growth

  • Replaces array-backed OrchestrationReadModel with a CommandReadModel backed by HashMap for O(1) lookups of threads and projects in commandReadModel.ts.
  • Deleted threads are evicted from the in-memory projector state and their IDs tracked in a HashSet, preventing memory growth and blocking re-creation of deleted thread IDs.
  • The VcsStatusBroadcaster now atomically evicts cached VCS status when the last subscriber releases a poller, closing a race condition.
  • Deleting a thread in the client now clears its associated state across preview, right-panel, diff-panel, and UI stores in useThreadActions.ts.
  • Idle per-thread preview atoms are evicted after 5 minutes via Atom.setIdleTTL instead of Atom.keepAlive.
  • Behavioral Change: released browser surface store entries are deleted entirely rather than retained as tombstones with visible=false.

Macroscope summarized 56b6615.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 20, 2026
@coderabbitai

coderabbitaiBot commented Jul 20, 2026

Copy link
Copy Markdown

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: 30f20953-b942-43f8-bcf8-3a2f69a5f75f

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

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.

Comment threadapps/server/src/orchestration/projector.ts
Comment threadapps/server/src/vcs/VcsStatusBroadcaster.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. Cross-cutting performance refactor affecting memory management in orchestration engine and multiple client stores. Unresolved review comments include a high-severity issue where the preview index keys may still grow unbounded despite the eviction changes.

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

@RusiruSadathana
RusiruSadathanaforce-pushed the pr/read-model-and-store-cleanup branch from 7b31cf8 to e30b77fCompareJuly 20, 2026 07:45
… state (Issue pingdotgg#4178)
Replays PR pingdotgg#4176 on current main and preserves the connection catch-up path from pingdotgg#4177.
Replace the array-backed command model with HashMap/HashSet state, evict deleted thread bodies, prune released VCS and browser caches, and clear per-thread client state.
Adds focused coverage for read-model invariants, deletion behavior, client cleanup, and VCS cache eviction after the final subscriber releases.
Co-authored-by: codex <codex@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium

presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current){
return{
byTabId: {
...state.byTabId,
[tabId]: {
rect: null,
visible: false,
content,
updatedAt: Date.now(),
owner: null,
},
},
};
}

release deletes the entry from byTabId, but presentContent is owner-independent and recreates a { owner: null } entry whenever the entry is missing. If HostedBrowserWebview fires a scheduled layout or scroll update after the lease has released, presentContent resurrects the deleted entry, so released tabs still accumulate in byTabId — defeating the bounded-state goal of this change. Consider guarding presentContent so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new owner: null entry.

Suggested change
presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current)returnstate;
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/browser/browserSurfaceStore.ts around lines 104-120:
`release` deletes the entry from `byTabId`, but `presentContent` is owner-independent and recreates a `{ owner: null }` entry whenever the entry is missing. If `HostedBrowserWebview` fires a scheduled layout or scroll update after the lease has released, `presentContent` resurrects the deleted entry, so released tabs still accumulate in `byTabId` — defeating the bounded-state goal of this change. Consider guarding `presentContent` so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new `owner: null` entry.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Idle preview TTL drops tab suppressions

Medium Severity

Introducing Atom.setIdleTTL on previewStateAtom causes client-only suppressedTabIds to be lost when a thread's preview state is evicted. This results in preview tabs that a user previously closed reappearing from the server list.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Preview index keys never pruned

High Severity

activePreviewThreadKeysAtom is keepAlive and only updated via syncActivePreviewThread on explicit preview writes. When previewStateAtom idle TTL evicts a thread that still had sessions, the index entry is never removed, so the key set grows without bound and activePreviewSessionsAtom keeps scanning stale keys.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

@danieliserdanieliser mentioned this pull request Jul 22, 2026
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza added a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 28, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 1, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
omegent-appBot pushed a commit to patroza/t3code that referenced this pull request Aug 6, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Orchestration read model and per-thread client/VCS state grow unbounded over uptime

2 participants

@RusiruSadathana@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

perf(orchestration): bound in-memory read model and client per-thread state - #4176

Closed
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup
Closed

perf(orchestration): bound in-memory read model and client per-thread state#4176
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup

Conversation

@RusiruSadathana

@RusiruSadathanaRusiruSadathana commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What Changed

Server: replaced the array-backed in-memory orchestration command read model with a HashMap-keyed CommandReadModel. Thread and project lookups and updates are now O(1) instead of O(N) linear scans plus full-array copies on every event, and deleted threads are evicted from the in-memory model (archived threads are retained because unarchive needs them and the projection cannot rehydrate them). The wire OrchestrationReadModel contract is unchanged; it is served by the DB-backed projection, which is untouched.

Web: wired the existing but previously uncalled per-thread cleanup into the thread deletion flow (preview state, right panel, diff panel, ui state), switched previewStateAtom from keepAlive to an idle TTL so idle preview atoms are collected, and made a released browser surface delete its entry instead of leaving a tombstone.

VCS: the VcsStatusBroadcaster per-cwd status cache is now pruned when the last poller subscriber releases, instead of growing for the process lifetime.

Added unit and integration coverage for the read model, projector eviction, decider behavior against a deleted thread, and the client store cleanup.

Why

After long uptime the server RSS and CPU climbed and the web UI became laggy. The cause was unbounded in-memory state on the single orchestration worker fiber (every event did O(N) work over a collection that never shed deleted or archived threads) compounded by client stores that accumulated one entry per thread ever visited and were never pruned on deletion. Making the hot-path structures O(1), evicting dead threads, and pruning the client and VCS caches removes the growth without changing any external contract or the projection that serves reads.

UI Changes

No visible UI changes. The web portion only prunes per-thread client state on deletion and adjusts atom retention; sidebar and panel behavior are unchanged.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (not applicable)
  • I included a video for animation/interaction changes (not applicable)

Related Issues

Closes#4178.


Note

Medium Risk
Orchestration command-path behavior changes (deleted-thread eviction and id retention) affect invariant checks and decider/projector semantics; web/VCS changes are localized leak fixes with tests.

Overview
Addresses unbounded memory growth on long-running server and web sessions by changing how hot-path state is stored and when it is dropped.

Server orchestration introduces an internal CommandReadModel (HashMap/HashSet) for the serial command worker, replacing array scans on every event. thread.deletedevicts thread bodies from memory while deletedThreadIds preserves the “cannot create twice” invariant across restarts; boot seeds via fromWireReadModel with dropDeletedThreads: true. The wire OrchestrationReadModel and DB projection are unchanged.

Web wires per-thread cleanup into thread delete (preview, right panel, diff panel, UI state in localStorage), switches previewStateAtom from keepAlive to a 5-minute idle TTL, and removes browser surface entries on release instead of tombstones.

VCS evicts per-cwd cache when the last remote poller releases, fixing a race where concurrent retain/release could leave stale entries forever.

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

Note

Bound in-memory orchestration read model and client per-thread state to prevent unbounded growth

  • Replaces array-backed OrchestrationReadModel with a CommandReadModel backed by HashMap for O(1) lookups of threads and projects in commandReadModel.ts.
  • Deleted threads are evicted from the in-memory projector state and their IDs tracked in a HashSet, preventing memory growth and blocking re-creation of deleted thread IDs.
  • The VcsStatusBroadcaster now atomically evicts cached VCS status when the last subscriber releases a poller, closing a race condition.
  • Deleting a thread in the client now clears its associated state across preview, right-panel, diff-panel, and UI stores in useThreadActions.ts.
  • Idle per-thread preview atoms are evicted after 5 minutes via Atom.setIdleTTL instead of Atom.keepAlive.
  • Behavioral Change: released browser surface store entries are deleted entirely rather than retained as tombstones with visible=false.

Macroscope summarized 56b6615.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 20, 2026
@coderabbitai

coderabbitaiBot commented Jul 20, 2026

Copy link
Copy Markdown

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: 30f20953-b942-43f8-bcf8-3a2f69a5f75f

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

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.

Comment threadapps/server/src/orchestration/projector.ts
Comment threadapps/server/src/vcs/VcsStatusBroadcaster.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. Cross-cutting performance refactor affecting memory management in orchestration engine and multiple client stores. Unresolved review comments include a high-severity issue where the preview index keys may still grow unbounded despite the eviction changes.

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

@RusiruSadathana
RusiruSadathanaforce-pushed the pr/read-model-and-store-cleanup branch from 7b31cf8 to e30b77fCompareJuly 20, 2026 07:45
… state (Issue pingdotgg#4178)
Replays PR pingdotgg#4176 on current main and preserves the connection catch-up path from pingdotgg#4177.
Replace the array-backed command model with HashMap/HashSet state, evict deleted thread bodies, prune released VCS and browser caches, and clear per-thread client state.
Adds focused coverage for read-model invariants, deletion behavior, client cleanup, and VCS cache eviction after the final subscriber releases.
Co-authored-by: codex <codex@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium

presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current){
return{
byTabId: {
...state.byTabId,
[tabId]: {
rect: null,
visible: false,
content,
updatedAt: Date.now(),
owner: null,
},
},
};
}

release deletes the entry from byTabId, but presentContent is owner-independent and recreates a { owner: null } entry whenever the entry is missing. If HostedBrowserWebview fires a scheduled layout or scroll update after the lease has released, presentContent resurrects the deleted entry, so released tabs still accumulate in byTabId — defeating the bounded-state goal of this change. Consider guarding presentContent so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new owner: null entry.

Suggested change
presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current)returnstate;
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/browser/browserSurfaceStore.ts around lines 104-120:
`release` deletes the entry from `byTabId`, but `presentContent` is owner-independent and recreates a `{ owner: null }` entry whenever the entry is missing. If `HostedBrowserWebview` fires a scheduled layout or scroll update after the lease has released, `presentContent` resurrects the deleted entry, so released tabs still accumulate in `byTabId` — defeating the bounded-state goal of this change. Consider guarding `presentContent` so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new `owner: null` entry.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Idle preview TTL drops tab suppressions

Medium Severity

Introducing Atom.setIdleTTL on previewStateAtom causes client-only suppressedTabIds to be lost when a thread's preview state is evicted. This results in preview tabs that a user previously closed reappearing from the server list.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Preview index keys never pruned

High Severity

activePreviewThreadKeysAtom is keepAlive and only updated via syncActivePreviewThread on explicit preview writes. When previewStateAtom idle TTL evicts a thread that still had sessions, the index entry is never removed, so the key set grows without bound and activePreviewSessionsAtom keeps scanning stale keys.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

@danieliserdanieliser mentioned this pull request Jul 22, 2026
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza added a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 28, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 1, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
omegent-appBot pushed a commit to patroza/t3code that referenced this pull request Aug 6, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Orchestration read model and per-thread client/VCS state grow unbounded over uptime

2 participants

@RusiruSadathana@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(orchestration): bound in-memory read model and client per-thread state - #4176

Closed
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup
Closed

perf(orchestration): bound in-memory read model and client per-thread state#4176
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup

Conversation

@RusiruSadathana

@RusiruSadathanaRusiruSadathana commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What Changed

Server: replaced the array-backed in-memory orchestration command read model with a HashMap-keyed CommandReadModel. Thread and project lookups and updates are now O(1) instead of O(N) linear scans plus full-array copies on every event, and deleted threads are evicted from the in-memory model (archived threads are retained because unarchive needs them and the projection cannot rehydrate them). The wire OrchestrationReadModel contract is unchanged; it is served by the DB-backed projection, which is untouched.

Web: wired the existing but previously uncalled per-thread cleanup into the thread deletion flow (preview state, right panel, diff panel, ui state), switched previewStateAtom from keepAlive to an idle TTL so idle preview atoms are collected, and made a released browser surface delete its entry instead of leaving a tombstone.

VCS: the VcsStatusBroadcaster per-cwd status cache is now pruned when the last poller subscriber releases, instead of growing for the process lifetime.

Added unit and integration coverage for the read model, projector eviction, decider behavior against a deleted thread, and the client store cleanup.

Why

After long uptime the server RSS and CPU climbed and the web UI became laggy. The cause was unbounded in-memory state on the single orchestration worker fiber (every event did O(N) work over a collection that never shed deleted or archived threads) compounded by client stores that accumulated one entry per thread ever visited and were never pruned on deletion. Making the hot-path structures O(1), evicting dead threads, and pruning the client and VCS caches removes the growth without changing any external contract or the projection that serves reads.

UI Changes

No visible UI changes. The web portion only prunes per-thread client state on deletion and adjusts atom retention; sidebar and panel behavior are unchanged.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (not applicable)
  • I included a video for animation/interaction changes (not applicable)

Related Issues

Closes#4178.


Note

Medium Risk
Orchestration command-path behavior changes (deleted-thread eviction and id retention) affect invariant checks and decider/projector semantics; web/VCS changes are localized leak fixes with tests.

Overview
Addresses unbounded memory growth on long-running server and web sessions by changing how hot-path state is stored and when it is dropped.

Server orchestration introduces an internal CommandReadModel (HashMap/HashSet) for the serial command worker, replacing array scans on every event. thread.deletedevicts thread bodies from memory while deletedThreadIds preserves the “cannot create twice” invariant across restarts; boot seeds via fromWireReadModel with dropDeletedThreads: true. The wire OrchestrationReadModel and DB projection are unchanged.

Web wires per-thread cleanup into thread delete (preview, right panel, diff panel, UI state in localStorage), switches previewStateAtom from keepAlive to a 5-minute idle TTL, and removes browser surface entries on release instead of tombstones.

VCS evicts per-cwd cache when the last remote poller releases, fixing a race where concurrent retain/release could leave stale entries forever.

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

Note

Bound in-memory orchestration read model and client per-thread state to prevent unbounded growth

  • Replaces array-backed OrchestrationReadModel with a CommandReadModel backed by HashMap for O(1) lookups of threads and projects in commandReadModel.ts.
  • Deleted threads are evicted from the in-memory projector state and their IDs tracked in a HashSet, preventing memory growth and blocking re-creation of deleted thread IDs.
  • The VcsStatusBroadcaster now atomically evicts cached VCS status when the last subscriber releases a poller, closing a race condition.
  • Deleting a thread in the client now clears its associated state across preview, right-panel, diff-panel, and UI stores in useThreadActions.ts.
  • Idle per-thread preview atoms are evicted after 5 minutes via Atom.setIdleTTL instead of Atom.keepAlive.
  • Behavioral Change: released browser surface store entries are deleted entirely rather than retained as tombstones with visible=false.

Macroscope summarized 56b6615.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 20, 2026
@coderabbitai

coderabbitaiBot commented Jul 20, 2026

Copy link
Copy Markdown

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: 30f20953-b942-43f8-bcf8-3a2f69a5f75f

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

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.

Comment threadapps/server/src/orchestration/projector.ts
Comment threadapps/server/src/vcs/VcsStatusBroadcaster.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. Cross-cutting performance refactor affecting memory management in orchestration engine and multiple client stores. Unresolved review comments include a high-severity issue where the preview index keys may still grow unbounded despite the eviction changes.

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

@RusiruSadathana
RusiruSadathanaforce-pushed the pr/read-model-and-store-cleanup branch from 7b31cf8 to e30b77fCompareJuly 20, 2026 07:45
… state (Issue pingdotgg#4178)
Replays PR pingdotgg#4176 on current main and preserves the connection catch-up path from pingdotgg#4177.
Replace the array-backed command model with HashMap/HashSet state, evict deleted thread bodies, prune released VCS and browser caches, and clear per-thread client state.
Adds focused coverage for read-model invariants, deletion behavior, client cleanup, and VCS cache eviction after the final subscriber releases.
Co-authored-by: codex <codex@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium

presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current){
return{
byTabId: {
...state.byTabId,
[tabId]: {
rect: null,
visible: false,
content,
updatedAt: Date.now(),
owner: null,
},
},
};
}

release deletes the entry from byTabId, but presentContent is owner-independent and recreates a { owner: null } entry whenever the entry is missing. If HostedBrowserWebview fires a scheduled layout or scroll update after the lease has released, presentContent resurrects the deleted entry, so released tabs still accumulate in byTabId — defeating the bounded-state goal of this change. Consider guarding presentContent so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new owner: null entry.

Suggested change
presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current)returnstate;
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/browser/browserSurfaceStore.ts around lines 104-120:
`release` deletes the entry from `byTabId`, but `presentContent` is owner-independent and recreates a `{ owner: null }` entry whenever the entry is missing. If `HostedBrowserWebview` fires a scheduled layout or scroll update after the lease has released, `presentContent` resurrects the deleted entry, so released tabs still accumulate in `byTabId` — defeating the bounded-state goal of this change. Consider guarding `presentContent` so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new `owner: null` entry.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Idle preview TTL drops tab suppressions

Medium Severity

Introducing Atom.setIdleTTL on previewStateAtom causes client-only suppressedTabIds to be lost when a thread's preview state is evicted. This results in preview tabs that a user previously closed reappearing from the server list.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Preview index keys never pruned

High Severity

activePreviewThreadKeysAtom is keepAlive and only updated via syncActivePreviewThread on explicit preview writes. When previewStateAtom idle TTL evicts a thread that still had sessions, the index entry is never removed, so the key set grows without bound and activePreviewSessionsAtom keeps scanning stale keys.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

@danieliserdanieliser mentioned this pull request Jul 22, 2026
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza added a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 28, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 1, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
omegent-appBot pushed a commit to patroza/t3code that referenced this pull request Aug 6, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Orchestration read model and per-thread client/VCS state grow unbounded over uptime

2 participants

@RusiruSadathana@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(orchestration): bound in-memory read model and client per-thread state - #4176

Closed
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup
Closed

perf(orchestration): bound in-memory read model and client per-thread state#4176
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup

Conversation

@RusiruSadathana

@RusiruSadathanaRusiruSadathana commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What Changed

Server: replaced the array-backed in-memory orchestration command read model with a HashMap-keyed CommandReadModel. Thread and project lookups and updates are now O(1) instead of O(N) linear scans plus full-array copies on every event, and deleted threads are evicted from the in-memory model (archived threads are retained because unarchive needs them and the projection cannot rehydrate them). The wire OrchestrationReadModel contract is unchanged; it is served by the DB-backed projection, which is untouched.

Web: wired the existing but previously uncalled per-thread cleanup into the thread deletion flow (preview state, right panel, diff panel, ui state), switched previewStateAtom from keepAlive to an idle TTL so idle preview atoms are collected, and made a released browser surface delete its entry instead of leaving a tombstone.

VCS: the VcsStatusBroadcaster per-cwd status cache is now pruned when the last poller subscriber releases, instead of growing for the process lifetime.

Added unit and integration coverage for the read model, projector eviction, decider behavior against a deleted thread, and the client store cleanup.

Why

After long uptime the server RSS and CPU climbed and the web UI became laggy. The cause was unbounded in-memory state on the single orchestration worker fiber (every event did O(N) work over a collection that never shed deleted or archived threads) compounded by client stores that accumulated one entry per thread ever visited and were never pruned on deletion. Making the hot-path structures O(1), evicting dead threads, and pruning the client and VCS caches removes the growth without changing any external contract or the projection that serves reads.

UI Changes

No visible UI changes. The web portion only prunes per-thread client state on deletion and adjusts atom retention; sidebar and panel behavior are unchanged.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (not applicable)
  • I included a video for animation/interaction changes (not applicable)

Related Issues

Closes#4178.


Note

Medium Risk
Orchestration command-path behavior changes (deleted-thread eviction and id retention) affect invariant checks and decider/projector semantics; web/VCS changes are localized leak fixes with tests.

Overview
Addresses unbounded memory growth on long-running server and web sessions by changing how hot-path state is stored and when it is dropped.

Server orchestration introduces an internal CommandReadModel (HashMap/HashSet) for the serial command worker, replacing array scans on every event. thread.deletedevicts thread bodies from memory while deletedThreadIds preserves the “cannot create twice” invariant across restarts; boot seeds via fromWireReadModel with dropDeletedThreads: true. The wire OrchestrationReadModel and DB projection are unchanged.

Web wires per-thread cleanup into thread delete (preview, right panel, diff panel, UI state in localStorage), switches previewStateAtom from keepAlive to a 5-minute idle TTL, and removes browser surface entries on release instead of tombstones.

VCS evicts per-cwd cache when the last remote poller releases, fixing a race where concurrent retain/release could leave stale entries forever.

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

Note

Bound in-memory orchestration read model and client per-thread state to prevent unbounded growth

  • Replaces array-backed OrchestrationReadModel with a CommandReadModel backed by HashMap for O(1) lookups of threads and projects in commandReadModel.ts.
  • Deleted threads are evicted from the in-memory projector state and their IDs tracked in a HashSet, preventing memory growth and blocking re-creation of deleted thread IDs.
  • The VcsStatusBroadcaster now atomically evicts cached VCS status when the last subscriber releases a poller, closing a race condition.
  • Deleting a thread in the client now clears its associated state across preview, right-panel, diff-panel, and UI stores in useThreadActions.ts.
  • Idle per-thread preview atoms are evicted after 5 minutes via Atom.setIdleTTL instead of Atom.keepAlive.
  • Behavioral Change: released browser surface store entries are deleted entirely rather than retained as tombstones with visible=false.

Macroscope summarized 56b6615.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 20, 2026
@coderabbitai

coderabbitaiBot commented Jul 20, 2026

Copy link
Copy Markdown

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: 30f20953-b942-43f8-bcf8-3a2f69a5f75f

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

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.

Comment threadapps/server/src/orchestration/projector.ts
Comment threadapps/server/src/vcs/VcsStatusBroadcaster.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. Cross-cutting performance refactor affecting memory management in orchestration engine and multiple client stores. Unresolved review comments include a high-severity issue where the preview index keys may still grow unbounded despite the eviction changes.

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

@RusiruSadathana
RusiruSadathanaforce-pushed the pr/read-model-and-store-cleanup branch from 7b31cf8 to e30b77fCompareJuly 20, 2026 07:45
… state (Issue pingdotgg#4178)
Replays PR pingdotgg#4176 on current main and preserves the connection catch-up path from pingdotgg#4177.
Replace the array-backed command model with HashMap/HashSet state, evict deleted thread bodies, prune released VCS and browser caches, and clear per-thread client state.
Adds focused coverage for read-model invariants, deletion behavior, client cleanup, and VCS cache eviction after the final subscriber releases.
Co-authored-by: codex <codex@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium

presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current){
return{
byTabId: {
...state.byTabId,
[tabId]: {
rect: null,
visible: false,
content,
updatedAt: Date.now(),
owner: null,
},
},
};
}

release deletes the entry from byTabId, but presentContent is owner-independent and recreates a { owner: null } entry whenever the entry is missing. If HostedBrowserWebview fires a scheduled layout or scroll update after the lease has released, presentContent resurrects the deleted entry, so released tabs still accumulate in byTabId — defeating the bounded-state goal of this change. Consider guarding presentContent so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new owner: null entry.

Suggested change
presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current)returnstate;
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/browser/browserSurfaceStore.ts around lines 104-120:
`release` deletes the entry from `byTabId`, but `presentContent` is owner-independent and recreates a `{ owner: null }` entry whenever the entry is missing. If `HostedBrowserWebview` fires a scheduled layout or scroll update after the lease has released, `presentContent` resurrects the deleted entry, so released tabs still accumulate in `byTabId` — defeating the bounded-state goal of this change. Consider guarding `presentContent` so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new `owner: null` entry.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Idle preview TTL drops tab suppressions

Medium Severity

Introducing Atom.setIdleTTL on previewStateAtom causes client-only suppressedTabIds to be lost when a thread's preview state is evicted. This results in preview tabs that a user previously closed reappearing from the server list.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Preview index keys never pruned

High Severity

activePreviewThreadKeysAtom is keepAlive and only updated via syncActivePreviewThread on explicit preview writes. When previewStateAtom idle TTL evicts a thread that still had sessions, the index entry is never removed, so the key set grows without bound and activePreviewSessionsAtom keeps scanning stale keys.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

@danieliserdanieliser mentioned this pull request Jul 22, 2026
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza added a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 28, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 1, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
omegent-appBot pushed a commit to patroza/t3code that referenced this pull request Aug 6, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Orchestration read model and per-thread client/VCS state grow unbounded over uptime

2 participants

@RusiruSadathana@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

perf(orchestration): bound in-memory read model and client per-thread state - #4176

Closed
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup
Closed

perf(orchestration): bound in-memory read model and client per-thread state#4176
RusiruSadathana wants to merge 1 commit into
pingdotgg:mainfrom
RusiruSadathana:pr/read-model-and-store-cleanup

Conversation

@RusiruSadathana

@RusiruSadathanaRusiruSadathana commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

What Changed

Server: replaced the array-backed in-memory orchestration command read model with a HashMap-keyed CommandReadModel. Thread and project lookups and updates are now O(1) instead of O(N) linear scans plus full-array copies on every event, and deleted threads are evicted from the in-memory model (archived threads are retained because unarchive needs them and the projection cannot rehydrate them). The wire OrchestrationReadModel contract is unchanged; it is served by the DB-backed projection, which is untouched.

Web: wired the existing but previously uncalled per-thread cleanup into the thread deletion flow (preview state, right panel, diff panel, ui state), switched previewStateAtom from keepAlive to an idle TTL so idle preview atoms are collected, and made a released browser surface delete its entry instead of leaving a tombstone.

VCS: the VcsStatusBroadcaster per-cwd status cache is now pruned when the last poller subscriber releases, instead of growing for the process lifetime.

Added unit and integration coverage for the read model, projector eviction, decider behavior against a deleted thread, and the client store cleanup.

Why

After long uptime the server RSS and CPU climbed and the web UI became laggy. The cause was unbounded in-memory state on the single orchestration worker fiber (every event did O(N) work over a collection that never shed deleted or archived threads) compounded by client stores that accumulated one entry per thread ever visited and were never pruned on deletion. Making the hot-path structures O(1), evicting dead threads, and pruning the client and VCS caches removes the growth without changing any external contract or the projection that serves reads.

UI Changes

No visible UI changes. The web portion only prunes per-thread client state on deletion and adjusts atom retention; sidebar and panel behavior are unchanged.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes (not applicable)
  • I included a video for animation/interaction changes (not applicable)

Related Issues

Closes#4178.


Note

Medium Risk
Orchestration command-path behavior changes (deleted-thread eviction and id retention) affect invariant checks and decider/projector semantics; web/VCS changes are localized leak fixes with tests.

Overview
Addresses unbounded memory growth on long-running server and web sessions by changing how hot-path state is stored and when it is dropped.

Server orchestration introduces an internal CommandReadModel (HashMap/HashSet) for the serial command worker, replacing array scans on every event. thread.deletedevicts thread bodies from memory while deletedThreadIds preserves the “cannot create twice” invariant across restarts; boot seeds via fromWireReadModel with dropDeletedThreads: true. The wire OrchestrationReadModel and DB projection are unchanged.

Web wires per-thread cleanup into thread delete (preview, right panel, diff panel, UI state in localStorage), switches previewStateAtom from keepAlive to a 5-minute idle TTL, and removes browser surface entries on release instead of tombstones.

VCS evicts per-cwd cache when the last remote poller releases, fixing a race where concurrent retain/release could leave stale entries forever.

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

Note

Bound in-memory orchestration read model and client per-thread state to prevent unbounded growth

  • Replaces array-backed OrchestrationReadModel with a CommandReadModel backed by HashMap for O(1) lookups of threads and projects in commandReadModel.ts.
  • Deleted threads are evicted from the in-memory projector state and their IDs tracked in a HashSet, preventing memory growth and blocking re-creation of deleted thread IDs.
  • The VcsStatusBroadcaster now atomically evicts cached VCS status when the last subscriber releases a poller, closing a race condition.
  • Deleting a thread in the client now clears its associated state across preview, right-panel, diff-panel, and UI stores in useThreadActions.ts.
  • Idle per-thread preview atoms are evicted after 5 minutes via Atom.setIdleTTL instead of Atom.keepAlive.
  • Behavioral Change: released browser surface store entries are deleted entirely rather than retained as tombstones with visible=false.

Macroscope summarized 56b6615.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 20, 2026
@coderabbitai

coderabbitaiBot commented Jul 20, 2026

Copy link
Copy Markdown

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: 30f20953-b942-43f8-bcf8-3a2f69a5f75f

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

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.

Comment threadapps/server/src/orchestration/projector.ts
Comment threadapps/server/src/vcs/VcsStatusBroadcaster.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

1 blocking correctness issue found. Cross-cutting performance refactor affecting memory management in orchestration engine and multiple client stores. Unresolved review comments include a high-severity issue where the preview index keys may still grow unbounded despite the eviction changes.

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

@RusiruSadathana
RusiruSadathanaforce-pushed the pr/read-model-and-store-cleanup branch from 7b31cf8 to e30b77fCompareJuly 20, 2026 07:45
… state (Issue pingdotgg#4178)
Replays PR pingdotgg#4176 on current main and preserves the connection catch-up path from pingdotgg#4177.
Replace the array-backed command model with HashMap/HashSet state, evict deleted thread bodies, prune released VCS and browser caches, and clear per-thread client state.
Adds focused coverage for read-model invariants, deletion behavior, client cleanup, and VCS cache eviction after the final subscriber releases.
Co-authored-by: codex <codex@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium

presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current){
return{
byTabId: {
...state.byTabId,
[tabId]: {
rect: null,
visible: false,
content,
updatedAt: Date.now(),
owner: null,
},
},
};
}

release deletes the entry from byTabId, but presentContent is owner-independent and recreates a { owner: null } entry whenever the entry is missing. If HostedBrowserWebview fires a scheduled layout or scroll update after the lease has released, presentContent resurrects the deleted entry, so released tabs still accumulate in byTabId — defeating the bounded-state goal of this change. Consider guarding presentContent so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new owner: null entry.

Suggested change
presentContent: (tabId,content)=>
set((state)=>{
constcurrent=state.byTabId[tabId];
if(!current)returnstate;
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/browser/browserSurfaceStore.ts around lines 104-120:
`release` deletes the entry from `byTabId`, but `presentContent` is owner-independent and recreates a `{ owner: null }` entry whenever the entry is missing. If `HostedBrowserWebview` fires a scheduled layout or scroll update after the lease has released, `presentContent` resurrects the deleted entry, so released tabs still accumulate in `byTabId` — defeating the bounded-state goal of this change. Consider guarding `presentContent` so it no-ops (or requires a valid owner) when no entry exists, instead of creating a new `owner: null` entry.

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

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 using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Idle preview TTL drops tab suppressions

Medium Severity

Introducing Atom.setIdleTTL on previewStateAtom causes client-only suppressedTabIds to be lost when a thread's preview state is evicted. This results in preview tabs that a user previously closed reappearing from the server list.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

export const previewStateAtom = Atom.family((threadKey: string) =>
Atom.make<ThreadPreviewState>(EMPTY_THREAD_PREVIEW_STATE).pipe(
Atom.keepAlive,
Atom.setIdleTTL(PREVIEW_STATE_IDLE_TTL_MS),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Preview index keys never pruned

High Severity

activePreviewThreadKeysAtom is keepAlive and only updated via syncActivePreviewThread on explicit preview writes. When previewStateAtom idle TTL evicts a thread that still had sessions, the index entry is never removed, so the key set grows without bound and activePreviewSessionsAtom keeps scanning stale keys.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 56b6615. Configure here.

@danieliserdanieliser mentioned this pull request Jul 22, 2026
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza pushed a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
patroza added a commit to patroza/t3code that referenced this pull request Jul 25, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 27, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 28, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 29, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 30, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Jul 31, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 1, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 4, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
patroza added a commit to patroza/t3code that referenced this pull request Aug 5, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
omegent-appBot pushed a commit to patroza/t3code that referenced this pull request Aug 6, 2026
Source: pingdotgg#4176
Source SHA: 56b6615
Imported: O(1) command read-model maps, deleted-thread eviction, VCS cache cleanup, browser surface cleanup, preview idle TTL, and per-thread UI cleanup.
Adapted: preserved our thread settlement, snooze, and sequential worktree deletion actions while wiring upstream cleanup into the current hook.
Excluded: none.
Co-authored-by: Rusiru Sadathana <27785781+RusiruSadathana@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Orchestration read model and per-thread client/VCS state grow unbounded over uptime

2 participants

@RusiruSadathana@juliusmarminge