You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Following the investigation of #5627, three measured Desktop session-switch workloads need follow-up: a small-turn tool-rich local fixture (A), very large local histories (B), and a continuously generating session on a Linux Runtime Host with matched source/destination histories (C).
This issue covers A, B, and C, with C first. Each scenario needs its own baseline and acceptance results; a shared implementation may help several scenarios, but that is not yet established. The current work is reproduction and design discussion. Product optimization starts after the proposed approach is reviewed.
Relationship to #5627: C partially reproduces delayed old-content removal and target-content appearance during an active remote A → B → A switch. We have not reproduced the exact Windows/WSL workload, established an active-specific penalty, aligned the approximately five-second settled milestone, or identified the original bottleneck. This issue scopes work around the workloads we can measure; completing it alone will not establish that #5627 is fixed. Related broader performance work: #2913 and #4677.
Real isolated local macOS Host and E2E FakeBackend.
One sample per state/build: production-renderer historical/streaming DOM endpoints 1.497 / 1.351 s; dev 2.313 / 2.308 s.
These legacy measurements start at probe arming before the automation click, not the actual input event. Dev click calls themselves took 0.83–1.09 s. Idle and streaming endpoints differ, and the old-content detector did not establish old-transcript persistence.
Rebaseline A with C's actual-pointerdown timing and active-turn continuity checks before using it to justify or accept a fix.
One sample per state/build: production-renderer historical/streaming DOM endpoints 13.964 / 14.156 s; dev 14.125 / 13.736 s.
These are returns to a previously visited session after app/Host startup, not launch-to-ready measurements. The timer includes click preparation; the automation click returned in 0.29–0.58 s, while the old source transcript remained until about 13.7–14.0 s.
A previously visited idle target can require a new subscription/replica on return. The legacy streaming samples did not verify Host-side generation throughout the switch, so the full 13–14 s must not be attributed to either idle reconstruction or active generation without new evidence.
For both A and B, “production renderer” means built Vite output in an unpackaged Electron launch. The legacy endpoint is a DOM observation, not protocol ready or stable paint. These are initial observations, not a statistically established active/idle difference.
C. Retained, continuously active remote session — first priority
macOS Desktop → authenticated WebSocket → independent Linux Runtime Host.
Two synthetic root sessions with the same history recipe: 30 turns / 300 tools each, or 100 turns / 1,000 tools each. The 100-turn fixture has about 4.64 MB payload per session and a 42.7 MB two-session database.
A short prompt starts controlled FakeBackend output, about nine characters every 45 ms. The same turn remains non-terminated, with output counters increasing before leaving, before returning, and after returning. The UI continues displaying growing output.
Real packaged .app / app.asar comparison, with runtime app.isPackaged === true verified.
Timing begins at the actual Renderer pointerdown; DOM sampling is 50 ms. The content-frame endpoint is target content observed followed by two animation frames: a paint-opportunity proxy, not a compositor timestamp or settled page.
100-turn results, milliseconds / median of three switches per state/configuration:
Build
Added RTT
Idle old content gone
Idle content frame
Active old content gone
Active content frame
Dev
0
1,295.1
1,517.2
1,147.4
1,204.5
Dev
20
1,919.4
2,027.6
1,632.5
1,718.3
Packaged
0
755.7
819.9
678.0
713.6
Packaged
20
1,407.2
1,488.2
1,270.3
1,310.0
+20 ms is 10 ms injected each direction for sensitivity testing, not an estimate of WSL latency. +0 means no injected delay. Idle and active run in blocks, with active output growing; these differences do not isolate the causal cost of being active.
The target has zero new subscription.open requests on every measured active remote return, versus one for idle. Nevertheless, the 100-turn active return issues 20 history-page requests and delivers 41 Renderer batches / approximately 2.65 MB. Retaining the subscription does not eliminate history delivery to the returning viewer.
For dev/+20, median timestamps after pointerdown are: preload open 104.7 ms, first preload batch 233.0 ms, protocol-ready batch 1,258.2 ms, open promise resolution 1,632.2 ms, old content removal 1,632.5 ms, and content-frame proxy 1,718.3 ms. These are independent timestamp medians, not additive CPU costs.
The full C campaign includes 48 primary returns and 24 control/probe/extended-observation measurements. Detailed-probe on/off ranges overlap; CPU profilers were off. Six extended active observations did not produce a 500 ms quiet historical-layout window while output and scrolling continued. That does not mean seven-second loading or reproduce the original five-second settled milestone.
How to reproduce
Use baseline fb9df6c3dbbc449b8ff54dd4b608cc04381d3d81 with isolated synthetic data. Generate the Linux Host's data natively on Linux. Keep A/B fixture shapes separate from C.
For C, create two sessions with identical completed tool-history recipes at 30 turns / 10 tools per turn and 100 turns / 10 tools per turn, with 4,096-byte synthetic tool payloads. Connect Desktop to the Linux Host over authenticated WebSocket.
Start controlled streaming in A, visit B, wait for B's last historical turn plus at least 1.3 s of dwell, then return to A. Verify the same running turn and output growth across all three stages. Use an idle return with the same history recipe as a control.
Measure from actual pointerdown, separating old-content removal, transcript open, Host/Main/preload delivery, protocol-ready batch, open completion, target content frame, and resumed output. Track target subscription opens, history page count and delivered bytes.
Re-run A/B with the corrected timing and equivalent endpoint definitions. Distinguish application cold start, a target's first open, idle re-subscription, and retained active return.
The current harness and raw traces are local reproduction artifacts, not yet committed to the repository. A portable harness and sanitized traces should accompany implementation review.
Desktop: Apple M2 Pro / 16 GiB / macOS Darwin 25.6.0 arm64; Electron 43.4.1 / Chromium 150.0.7871.224.
Node: macOS harness/local Host 24.20.0; Linux Host 24.21.0.
Remote Host: arm64 Docker / LinuxKit 6.12.76, SQLite on a macOS bind mount, authenticated WebSocket. This does not simulate WSL filesystem performance.
Dev: Vite renderer plus tsc-built Main/preload, not the original npm run dev launcher.
Packaged C build: local unsigned/unnotarized .app with ASAR; optional unbuilt Direct peer addon omitted. Measurements use WebSocket.
Synthetic settled tool histories and deterministic text streaming, not real LLM/tool execution during the active turn.
Work and acceptance scope
C first: explain the retained-return history work and the first-batch → ready → visible intervals; review a bounded proposal before product changes.
Rebaseline A with actual input timing and reliable historical/streaming endpoints, then address the measured residual latency.
Address B's long-history return latency, separating idle reconstruction from retained active return and measuring both source and destination costs.
Validate all three with fixed fixtures and before/after commits, dev and packaged results, at least ten repetitions, median/p95, request/byte counts, and raw traces. Agree numerical acceptance budgets during design review; the existing three-sample medians do not establish p95 compliance.
Preserve streaming continuity, generation/Host identity checks, readable complete Turns, older-history paging, cancellation/reconnection, and reading position. Check memory growth and fast repeated switching; avoid trading latency for unbounded retention.
What happened
Following the investigation of #5627, three measured Desktop session-switch workloads need follow-up: a small-turn tool-rich local fixture (A), very large local histories (B), and a continuously generating session on a Linux Runtime Host with matched source/destination histories (C).
This issue covers A, B, and C, with C first. Each scenario needs its own baseline and acceptance results; a shared implementation may help several scenarios, but that is not yet established. The current work is reproduction and design discussion. Product optimization starts after the proposed approach is reviewed.
Relationship to #5627: C partially reproduces delayed old-content removal and target-content appearance during an active remote A → B → A switch. We have not reproduced the exact Windows/WSL workload, established an active-specific penalty, aligned the approximately five-second settled milestone, or identified the original bottleneck. This issue scopes work around the workloads we can measure; completing it alone will not establish that #5627 is fixed. Related broader performance work: #2913 and #4677.
Detailed methodology and results: A/B/C reproduction comment on #5627.
A. Five-turn local fixture
B. Very large local histories
For both A and B, “production renderer” means built Vite output in an unpackaged Electron launch. The legacy endpoint is a DOM observation, not protocol
readyor stable paint. These are initial observations, not a statistically established active/idle difference.C. Retained, continuously active remote session — first priority
.app/app.asarcomparison, with runtimeapp.isPackaged === trueverified.pointerdown; DOM sampling is 50 ms. The content-frame endpoint is target content observed followed by two animation frames: a paint-opportunity proxy, not a compositor timestamp or settled page.100-turn results, milliseconds / median of three switches per state/configuration:
+20 ms is 10 ms injected each direction for sensitivity testing, not an estimate of WSL latency. +0 means no injected delay. Idle and active run in blocks, with active output growing; these differences do not isolate the causal cost of being active.
The target has zero new
subscription.openrequests on every measured active remote return, versus one for idle. Nevertheless, the 100-turn active return issues 20 history-page requests and delivers 41 Renderer batches / approximately 2.65 MB. Retaining the subscription does not eliminate history delivery to the returning viewer.For dev/+20, median timestamps after pointerdown are: preload open 104.7 ms, first preload batch 233.0 ms, protocol-ready batch 1,258.2 ms, open promise resolution 1,632.2 ms, old content removal 1,632.5 ms, and content-frame proxy 1,718.3 ms. These are independent timestamp medians, not additive CPU costs.
The full C campaign includes 48 primary returns and 24 control/probe/extended-observation measurements. Detailed-probe on/off ranges overlap; CPU profilers were off. Six extended active observations did not produce a 500 ms quiet historical-layout window while output and scrolling continued. That does not mean seven-second loading or reproduce the original five-second settled milestone.
How to reproduce
fb9df6c3dbbc449b8ff54dd4b608cc04381d3d81with isolated synthetic data. Generate the Linux Host's data natively on Linux. Keep A/B fixture shapes separate from C.The current harness and raw traces are local reproduction artifacts, not yet committed to the repository. A portable harness and sanitized traces should accompany implementation review.
Environment
fb9df6c3dbbc449b8ff54dd4b608cc04381d3d81, differing from perf(desktop): reduce session-switch latency for active sessions #5627'sb004473ed.npm run devlauncher..appwith ASAR; optional unbuilt Direct peer addon omitted. Measurements use WebSocket.Work and acceptance scope
Prepared with Codex assistance at the contributor's direction.