Repository navigation
tracking(perf): bound Desktop and Runtime Host work as history grows #4677
Description
Problem
Desktop responsiveness and Runtime Host work should depend on the visible window and the amount of new data, rather than the full Session history. Several paths have violated that constraint: long-session hydration, oversized-Turn rendering, Usage tables, WorkHub linkage reconstruction, and artifact persistence/recovery.
This tracker defines the intended architecture, performance budgets, and remaining delivery work. Individual issues retain their reproductions and detailed reviews. #2913 contains the broader incremental-data-flow design; this issue tracks the measured Desktop and Host outcomes across that work.
Desired outcome
A user can open a long Session, read and scroll while output streams, switch Sessions, and open Usage or WorkHub without full-history work blocking the interaction. Reading position, focus, selection, accessibility, and durable execution semantics remain correct.
Target architecture
flowchart TD
L[Durable execution and domain records] --> H[Runtime Host: lifecycle and query authority]
H -->|bounded pages, watermarks and changes| M[Desktop Main: bounded sparse replica]
M -->|incremental IPC| R[Renderer: bounded visible window]
R --> S[One transcript scroll authority]
R --> B[Render boundaries within oversized Turns]
H --> Q[On-demand WorkHub linkage queries]
H --> P[Delta persistence and bounded diagnostics]
- Runtime Host owns execution. Session/Turn lifecycle and terminal facts remain authoritative there. RuntimeEvent and the appropriate domain ledgers feed read projections; Desktop does not reconstruct execution state from its rendered history.
- Desktop is an incremental client. Tail bootstrap, bounded pages and generation-checked updates replace full-history loading. Resident data and DOM stay bounded as history grows. One scroll authority owns viewport changes; sub-Turn containment limits rendering work without becoming a second paging or scrolling mechanism.
- WorkHub reads linkage at its owner. The target Session and Coordination ledger establish current delegation facts on demand. Replace/stop revalidate them under the existing admission boundary. No renderer replay or additional durable active-delegation table is required. The current fix(workhub): resolve WorkHub delegation linkage on demand #4699 lookup still scales with target-local assignment history; its cost must be measured rather than called constant-time.
- Persistence writes the change. Artifact metadata uses delta writes, and per-call diagnostics store bounded summaries rather than another copy of the conversation. Remaining recovery scans and repeated full metadata reads need a defined consistency/invalidation boundary before optimization.
- Other views follow the same rule. Usage rows are paged; catalog updates preserve unchanged items; streaming processing consumes new chunks; search and inactive views avoid remote full-history work.
Performance baseline and results
These are measurements or estimates recorded in the linked issues/PRs, not a new benchmark of current main. Each row is a separate workload; the results must not be combined into an overall speedup.
| Scenario and source | Starting baseline | Reported result / remaining gap |
|---|---|---|
| Tool-rich 1,000-Turn hydration, 30ms RTT — #2913 | About 5,000 sequential requests; 150s theoretical transport lower bound, not a wall-clock measurement | Tail bootstrap and byte-bounded paging landed in #2922/#2937. End-to-end latency must be checked against the budgets below. |
| Hover over an oversized Turn of roughly 15k elements — #4259 | Hover p95 59ms; about 20 LoAF >50ms; style recalculation about 1,270ms per measured sweep | PR reports 9ms, 0 LoAF >50ms, and about 100ms respectively. This is a hover result, not proof of faster scrolling. |
| Cold upward scroll, eight 240px wheel steps — #4259 measurement | Same-build control with inner containment disabled: 0px worst unexpected anchor movement | Old head bfee6e1c: 239.44px, light/dark, three runs each at 1400×900. Later head bd8e0299 changes folded estimates to 32px and uses a 120px test bound; independent remeasurement is outstanding. |
| Usage Activity log, 409 records — #4531 / #4539 | 409 rows mounted on each visit | Proposed page size: 50 rows. Before/after tab-entry median and p95 are still needed. |
| Per-call durable data, 600-message conversation and 60 tools — #4722 | 405,729 B across diagnostic records and capture file | 3,944 B after removing the capture and folding diagnostics; same-machine comparison against 780dc4b4. |
| Cumulative model-call diagnostics over 500 Turns — #4722 | 193.44 MiB, preparation CPU 607ms | 1.88 MiB, 139ms, under the PR's synthetic workload. |
| Artifact store, 6,000 records / 400 Sessions — #4722 | listPage 13.45ms; create 38.32ms |
11.54ms / 37.42ms; means of 50 / 20 operations in one run. Full reads and filesystem durability remain significant. |
| Host cold start, roughly 11.7k artifacts — #4027 / #4037 / #4038 | Historical profile: about 130s total, roughly 90s in the artifact metadata/cleanup phase | Several persistence changes have landed. A fresh startup profile is required; the historical timing is not the current baseline. |
| WorkHub linkage lookup — #4699 | Opening/reconnecting replayed the Coordination history | Current PR reports about 3.8 / 33.8 / 205.3ms for 100 / 1,000 / 6,000 terminal assignments. No comparable before/after wall-clock result is recorded yet. |
Target performance
The latency budgets below carry forward the proposed budgets in #2913; they are acceptance targets, not claims that current main meets them.
| Scenario | Target |
|---|---|
| Local Session open to visible tail | p95 ≤ 150ms |
| Long Session over 30ms RTT | p95 ≤ 800ms, with initial useful tail in one subscription-open round trip |
| 64 MiB Session | Tail opens and older history remains pageable; no full-history prerequisite |
| Normal input, scroll and hover | No task/LoAF over 50ms in the fixed interaction trace |
| Transcript and Sidebar rendering | DOM bounded by the resident window/viewport, independent of total history; #2913's initial transcript ceiling is normally 100 Turns |
| One catalog update with 1,000 Sessions | Renderer work ≤ 16ms |
| 256 KiB output arriving in 20-character deltas | Cumulative sanitizer CPU ≤ 250ms, preserving cross-delta redaction |
| Steady-state synchronization and per-call diagnostics | Work proportional to changed data; no full conversation copy per call |
| Cold-scroll geometry | No stalled/reversed step or snap to tail. Calibrate the numerical anchor-displacement bound against the control; 120px is not yet an accepted product budget. |
| Host startup, WorkHub and Usage latency | Establish comparable current-main baselines and explicit p95 budgets before accepting these work items. Missing numbers remain open acceptance work. |
Implementation plan
- Replace full transcript snapshots with bounded pages and a Desktop sparse replica — perf(runtime-host): replace transcript snapshots with bounded pages #2922, perf(desktop): keep transcript state incremental #2937.
- Reduce repeated rendering work in streamed Markdown, prompt rail and Session rail — perf(ui): incrementally prepare streamed Markdown math #4207, perf(ui): scope prompt rail observation to mounted turns #4203, fix(desktop): keep session workspace action identities fixed #4110.
- Fix native peer snapshot-watch busy loops — fix(peer): stop snapshot watch busy loops #4687.
- Land artifact delta writes, bounded per-call diagnostics and old-capture reclamation — perf(storage): persist artifact metadata deltas #4716, perf: bound what one model call costs to store #4722, feat(storage): reclaim the prepared-request captures already on disk #4738.
- Establish transcript regression fixtures and land the tail-pin correction — test(desktop): make the transcript scroll regression line real #4796, fix(ui): preserve tail pin and correct reader scroll assertion #4831.
- Accept oversized-Turn rendering with both hover gains and cold-scroll/AX validation — perf(ui): oversized single Turn defeats transcript render bounds #4256 / perf(desktop): bound rendering within oversized turns #4259.
- Accept older → newer → latest navigation, retained focus and reading position — feat(desktop): preserve transcript continuity across bounded ranges #4123 / feat(desktop): preserve transcript continuity across bounded ranges #4560.
- Remove WorkHub open/reconnect full replay and validate current linkage under recovery/concurrency — WorkHub Coordination transcript is replayed in full on every open and every reconnect #4647 / fix(workhub): resolve WorkHub delegation linkage on demand #4699.
- Bound Usage Activity rendering and record tab-entry latency — perf(desktop): Usage activity log is slow with large histories #4531 / perf(desktop): paginate usage activity #4539.
- Re-profile Host startup and resolve remaining recovery/batch-retirement costs — fix(runtime-host): cold-start artifact recovery sweeps O(all files) realpath/lstat, blocking Host readiness for minutes #4027 / perf(storage): batch multi-Session artifact purge during session retirement (O(M×N) guard scans) #4038; reassess the residual full-read cost documented in perf: bound what one model call costs to store #4722.
- Reconcile remaining catalog, startup, streaming and search work with perf(desktop): make session data flow incremental and bounded #2913, then enforce the budgets above.
Implementation merged and behavior accepted are separate milestones: the checked items above record landed changes, while the open items retain their outstanding acceptance work.
Validation and completion criteria
Run before/after measurements on the same machine, fixture, viewport, theme and motion settings. Record both commits, OS/runtime versions, fixture size, and whether a result is measured, theoretical, or author-reported. Separate cold from warm runs and hover from scrolling. For latency comparisons, use at least 10 repetitions and report median/p95; keep raw traces with the implementation PR.
Use small and oversized Turns, local and 30ms-RTT Sessions, growing WorkHub histories, the 409-record Usage fixture, and the artifact-startup fixture. Exercise actual Electron/CDP interaction where compositor scrolling, focus or startup is relevant. Storybook covers deterministic layout and accessibility; storage microbenchmarks do not establish end-to-end responsiveness.
This tracker is complete when the open work above is resolved, the performance targets are measured on the delivered implementation, and there is no regression in reading position, focus, selection, accessibility, redaction, or durable execution/recovery. Update the result table and work-item checkboxes as changes land; keep review conversations in the linked PRs.
Related work
- Existing common-path defects remain tracked individually: fix(desktop): archived sessions can remain selected and trigger Skills and Plan queries #4430, Permission mode switch (Auto→Bypass) is not honored by the next turn #3349, Default-model picker in Settings spins on every switch #3827, The Goal chip reads "running" while an armed Goal waits for its first Turn #3362, fix(desktop): connection base URL gate is looser than the Runtime Host contract, so a rejected endpoint reports a misleading error #3672, fix(desktop): agent graph appears frozen while 0/7 operators are running (no heartbeat) #3878, Failed turns hide the provider's own response; show it collapsed, expandable, for every failure class #4502.
- Historical renderer/data-flow work: perf(desktop): stop forwarding unobserved session events #1957, perf(desktop): stop idle-session event-health polling from re-rendering the whole shell #1979, perf(desktop): AppShell subscribes to all session UI state at one granularity, so every stream token re-renders the whole shell #1985, refactor(ui): stream the transcript incrementally instead of re-deriving it per token #2030, perf(desktop): switching back to a long session mounts the whole transcript in one commit, freezing the UI ~0.35s #2052, perf(desktop): remove models.dev metadata from the renderer startup path #2063, perf(ui): seed transcript geometry before progressive fill #2224. Consult these before duplicating a previous optimization.
- Test-suite runtime is tracked separately in tracking(desktop): move every test out of Electron E2E that does not need it #4761.
Prepared with Codex assistance under maintainer direction.
Activity
Astro-Han commentedon Sep 3, 2026
take
[-]tracking(desktop): clear common-path defects and renderer performance debt[/-][+]tracking(perf): bound Desktop and Runtime Host work as history grows[/+]Astro-Han commentedon Sep 10, 2026
The open item "Accept older → newer → latest navigation, retained focus and reading position — #4123 / #4560" now has a design in #5163: the Renderer owns the transcript window (budgets in screens, not Turn counts) and the scroll authority is the single owner of the reading position. #5163 lists the ten navigation scenarios from the post-#4206 fix PRs as one regression line.
ggbdpq commentedon Sep 27, 2026
Fresh startup profile for current
main(fffc19fb5), filling the "re-profile Host startup" acceptance item in the checklist. Method and script: a self-containedstartup-profile.mjs(runtime-host scripts, runnable locally on Windows and Linux) that seeds a usage-shaped fixture, then reopens the composition and times four anchors per restart — composition open, five-phase domain recovery, firstsession.catalog.query, and orderly close. Happy to open the script as a PR if you want it in-tree.Fixture A — 100 Sessions × 3 Turns × 2 artifacts (3 restart rounds, medians): open 16ms / recover 159ms / first query 1.1ms / close 10ms / total 185ms.
Fixture B — 300 Sessions × 900 Turns × 12,000 artifacts (the scale class of #4027's historical ~130s startup / ~90s artifact phase): open 14ms / recover 397ms / first query 1.2ms / close 23ms / total 435ms. Recovery grows 2.5× for 30× the data (sub-linear), stable across rounds.
Reading: the historical 130s/90s artifact-phase costs no longer exist on current main at either scale — the accumulated persistence and recovery work (#5556, #4716, #4037, #4038, #4874 and neighbors) has brought Host restart to sub-second at the 12k-artifact scale. For the still-open budget line ("Host startup, WorkHub and Usage latency — establish comparable current-main baselines"), I'd propose recording Host restart total p95 ≤ 1s at 12k artifacts as the baseline budget going forward, with the measured 435ms as headroom. Caveats: single Windows machine, medians of 3 rounds,
FakeBackendtopology (no real model IO); a Linux CI run of the same script would strengthen the baseline. No claims here about WorkHub or Usage budgets — those still need their own numbers.ggbdpq commentedon Sep 28, 2026
The measurement script from my 09-27 comment is now proposed for inclusion as #5791: a self-contained
packages/runtime-host/scripts/startup-profile.mjs, registered asbenchmark:startup-profilealongside the two existing runtime-host benchmarks. The PR body carries the method, the 100-session and 12k-artifact fixture tables, and a same-head verification run. If the tracker wants different anchors or a different fixture shape for the startup acceptance numbers, happy to adjust.ggbdpq commentedon Sep 28, 2026
Acceptance evidence for checklist item 3 — "Remove WorkHub open/reconnect full replay and validate current linkage under recovery/concurrency" (#4647 / #4699).
Independent reproduction of the on-demand linkage resolution cost reported in the #4699 description, on a different machine and OS (Windows 11, Node 26.10.0, local SQLite, median of 20 samples after 3 warm-ups):
Fixture: 32 target Sessions, assignments round-robin across targets, every delegation terminal (
delegation_superseded/delegation_replacement_abortedrotation), read through the candidates-page shapereadActiveWorkHubAssignmentsByTarget(targets, cap 1, includeStopped true)plus a no-cap variant. The harness asserts its own correctness (0 active links expected on the all-terminal history; anot_ownedstop resolution seeded as a positive control is returned). The measurements confirm the documented residual: resolution is O(A) in the target's own history and the per-target cap does not engage on all-terminal targets, exactly as analyzed in #4699. The WorkHub open path itself issues one bounded linkage read per candidate page (candidatesmaps the page through a single store call), not a transcript replay.Recovery/concurrency suites on the same head (Windows,
node --teston built dist):workhub-message-assignment.test(assignment atomicity, terminal matrix, stop/replacement gates)workhub-assignment-crash-recovery.testworkhub-coordination-coordinator.testThese cover admission atomicity, terminal filtering for every outcome shape, crash recovery of in-flight assignments, and the stop/replacement gate races that have test coverage. There is no WorkHub-specific two-client UDS suite, and Windows cannot run the UDS family, so transport-level concurrency remains CI territory - I have not run those locally and claim nothing about them.
From my side, the validation half of item 3 is closed on the Windows-runnable paths: open/reconnect no longer replays the full Coordination transcript, current linkage resolves within the author-reported bounds, and the residual O(A) scan is the deliberate, documented trade-off. The remaining sub-item is the terminal-record identity / stop protocol asymmetry named in #4699, which I understand is being tracked separately.
2 remaining items
ggbdpq commentedon Sep 28, 2026
Status inventory for checklist item 2 - "Accept older -> newer -> latest navigation, retained focus and reading position (#4123 / #4560)" - because the architecture the item was written against no longer exists.
Timeline: #4123/#4560 landed the original bounded-range continuity (merged 09-06). #5163's ten-scenario regression line landed via #5170 (merged 09-11, with an ablation table). Then #5366 (merged 09-17) replaced that architecture: load the durable transcript whole (64 MiB cap) and virtualize in the renderer - deleting the renderer range store, gap rows, prefetch, eviction, and the server-side pager, and with them the #5170 regression files (
transcript-navigation-race/-regression/-pager.test.ts,transcript-scroll-cost.spec.ts,return-to-latest-pin.test.tsx). So "accept the ten scenarios as one regression line" is no longer the right acceptance shape; below is the scenario-by-scenario mapping onto the current architecture (source inspection at58d09e0a8):apps/desktop/src/main/__tests__/transcript-send-viewport.test.tstranscript-tail-restore.test.tsbookmark assertions (switch away/back, reopen)packages/ui/src/__tests__/transcript-scroll-authority.test.ts- fullest coverage (~12 assertions: pin/release/gesture release/re-pin)packages/ui/src/__tests__/prompt-rail-reading-position.test.tsx(renamed in #5170, still present)workhub-coordination-transcript-preload.test.tspresent, not assertion-by-assertion auditedapps/desktop/perf/transcript-memory.spec.ts(memory return) ande2e/partial-history-notice.spec.ts(explicit load past budget)Ask for a maintainer ruling on this item: either tick it on the strength of this inventory (scenarios 4-8 carry live assertions; 1/3/10 are dissolved by the #5366 direction the maintainers set), or keep it open for scenario 9's frame-budget assertion - and if so, whether that belongs in a #5366 follow-up rather than a restoration of the deleted #5170 spec, since re-adding the old line would fight the new architecture.
One residual worth a look either way:
desktop-transcript-range-store.test.tswas still present at the inspection baseline even though #5366 says it removed the renderer range store - unclear whether that is a Main-side tail cache (intentional) or a cleanup leftover.Source inspection, not a measured claim; happy to run the surviving suites and record pass counts if that helps the ruling.
ggbdpq commentedon Sep 28, 2026
Correction to my hydration acceptance comment above (#4677 (comment)): hqhq1025's review of #5800 correctly points out that the measured endpoint is Host-client decode (
ClientSessionSubscription.decodeTranscriptPage), not the Desktop visible point - noDesktopTranscriptReplicainstallation, Electron IPC, renderer update, or paint, and the RPC handlers are invoked directly rather than through protocol transport/serialization.So the 62.6ms / 95.8ms numbers are a Host-side proxy metric, not an end-to-end visible-tail result, and my "PASS, 8.4x headroom" framing against the 800ms UI budget was an overclaim - the proxy passing does not prove the UI budget is met. #5800 will relabel the metric (Host-client decode proxy, no UI-budget verdict) per the review.
Two findings from that measurement survive the correction because they don't depend on the endpoint: the resident tail is bounded (~84 messages / ~20.5KiB, bootstrap fills and stops) regardless of Session length, and full hydration of the same Session costs ~22x the proxy open. Measuring the actual visible point (through
DesktopTranscriptReplica, IPC and paint) needs an Electron-harness extension - recording that as open acceptance work for this line.fix(runtime-host): label the hydration tail metric as a host-side dec…
ggbdpq commentedon Sep 28, 2026
Acceptance evidence for checklist item 4 - "Bound Usage Activity rendering and record tab-entry latency (#4531 / #4539)" - the tab-entry median/p95 the table asks for.
Setup: a deterministic 409-record fixture built through the e2e-fixture scenario path (
settings-usage, fixed clock, 3 connections / 5 models spread: 399 model-call activities = 394 synthetic zero-tool turns + 5 manual, plus 10 tool activities - row counts probe-verified against the SQLite store), and a perf-tier spec (apps/desktop/perf/, real Electron window via_electron, single worker) that switches away from and back into the Usage tab and samples tab-entry inside the renderer (click timestamp -> rAF-settled table mount,performance.now()based).Measured on current main sources (Windows 11, Node 26.10.0, 12 rounds of warm re-entry):
USAGE_REQUESTS_PAGE_SIZE)activityTotal)Reading: the 409 rows are no longer mounted on each visit - exactly one 50-row page lands in the DOM while the badge carries the full total, so #4539's pagination holds under the real Electron + Host + storage path, and tab re-entry sits well inside the "no >50ms task" spirit at median with a conservative-bounded p95 (a 12-sample p95 is the max).
Honesty notes: these are warm re-entry numbers (snapshot already resident; cold entry not measured separately); no before-build comparison - #4539's parent predates the entire
apps/desktop/perf/tier, so porting the harness to the pre-pagination UI exceeded the timebox (the spec documents that 409 is the scale that would have mounted unpaginated); single machine, synthetic fixture, author-reported.Two side finds worth recording: (1) the fixture infra had a real bug -
catchUpModelCallProjectionfolds queued runs in a single limited pass, so 400 queued runs materialized only ~a dozen activities; looping topendingRuns === 0fixes it for any large canonical seed (diff archived). (2) During spec iteration, the settings surface's active section drifted to a different section within its wait window (an effect-driven focus migration; trigger not pinned down) - the spec was made immune to it, but if that drift exists for real users it is worth its own issue.The fixture diff and spec are archived and can land as a perf-spec PR (the #5042 pattern) if the tracker wants them reproducible.
ggbdpq commentedon Sep 28, 2026
Follow-up on the settings-drift side note in my item-4 comment above: a follow-up diagnosis did not reproduce the drift and found no real-user path. With every section write-entry in
settings-surface.tsxinstrumented, 35s of pure idle (and 35s after an explicit section switch) in a real Electron + fake-backend run produced zero section changes and zero remounts; the section state has exactly four write entries, all user-driven (initial mount,request.sectionchanges from open intents, navigation clicks, and amaka:jumpToSettingsSectionwindow event that has zero dispatchers in the repo - a dead listener). Update polling, menus, the e2e fixture, and the app-shell timer were all excluded.Strongest remaining hypothesis: the observation was measurement-environment-specific.
SettingsModalis conditionally rendered, so close/reopen remounts the surface, which restoresrequest.section ?? localStorage("maka-settings-section-v1")- a driver flow that once visited the About section would land there on any later intent-less reopen, which reads as "drift" to an observer. No issue filed; treating the original note as closed. One design sharp edge noted for awareness (not issue-worthy without a real repro): on remount,request.sectionpreempts the user's own in-session click choice.fix(desktop): carry the poll budget into the renderer and fix the eve…
ggbdpq commentedon Sep 29, 2026
Correction to the residual note in my item-2 inventory above:
desktop-transcript-range-store.test.tsis not a leftover. #5366 rewrote the module in place rather than deleting it - what that PR removed was the windowed range semantics (loadAround/loadLatest/hasNewer); the file survives as the renderer's whole-transcript store (loadEarlier, tail acknowledgement, cached fallback) with live consumers inapp-shell-effects.tsandcreate-workhub-services.ts, and the test continued to evolve after #5366 (#5471/#5494/#5566). Resolving the note as no-action.ggbdpq commentedon Sep 29, 2026
New measurement relevant to the "long Session @30ms RTT: open to visible tail p95 <= 800ms" budget - the session-SWITCH path at scale is a different, much larger cost than the initial open.
Setup: real Electron + Host + storage, a 4,000-turn Session (~70MiB transcript), switching away to a small Session and back to the large one (the "older -> newer -> latest navigation" shape), renderer-side sampling to visible tail (
[data-turn-id]rows + rAF settle), n=12. Two new sibling defect reports came out of the same investigation: #5843 (candidate election storms at larger total store) and #5844 (a 12,000-turn Session fails to open at all).Reading:
Caveats: n=12, single machine, synthetic 18KiB-per-turn fixture (a heavy session, plausibly reachable within days of heavy use); RTT injected as an env-gated transport decorator rather than real network; "visible" = rAF settle of tail rows, not a compositor-verified paint.
The two defect reports above may be upstream causes for part of this cost at even larger scales (#5843 makes the Host unavailable entirely at ~360MiB); the numbers here were taken at a scale where the Host is healthy - so the switch-path cost stands on its own.
ggbdpq commentedon Sep 29, 2026
Local evidence toward checklist item 1 - "hover gains and cold-scroll/AX validation" - now covering all three halves, with one new pathology found and filed as #5842.
All measurements are local and synthetic (Windows 11, Edge/Chromium headless via CDP against the Storybook surfaces, single machine, author-reported per the tracker's vocabulary). Three passes, newest findings included:
1. Hover on current main (containment ablation, 8 conditions x 10 sweeps + idle controls). Across an oversized fixture (1,813 elements) and a 300-small-Turn fixture: hover sweep frame p95 6.6-7.7ms, zero LoAFs >50ms in all 80 sweeps + 24 idle controls; the two-tier containment stacking is not more expensive than either single tier (differences within noise). The author-reported 59ms -> 9ms before/after remains author-reported: the public fixture is ~8x smaller than the original ~15k-element A/B and even all-off produces no long frames at this size.
2. Scaling up found a real pathology - filed as #5842. At a 360-step expanded process (14,919 elements, transcript ~103kpx), pointer movement inside the transcript produces ~100-110ms per frame, 86 LoAFs >50ms per sweep - and this is independent of containment (all-off identical). Root cause pinned with discriminating experiments: hover-chain switching triggers a near-full-document style recalc (
Document::recalcStyle, 109 hits / max 102ms per sweep); the sufficient condition is the 58 design-system hash-class:hoverrules (CSSOM-neutralizing them -> 0, the 29 app.maka-*rules only partially);contain: contentdoes not scope hover invalidation. Fix directions (product windowing for oversized processes / CSS bisect of the rule shape) are under discussion on #5842. A separate amplifier - Storybook's preview highlight tracker forcinggetBoundingClientRectevery frame even with empty boxes - is actionable upstream.3. Cold scroll. Unexpected anchor displacement per 240px scroll step: median 15.44px (n=24), an order of magnitude under the historical 239px anomaly; the 1px cold-scroll story assertions pass on both collapsed and live variants.
4. AX (first time this half has been run). Full Storybook AX audit: 438 stories / 475 renders, zero failures; the oversized-related stories (
OversizedTurnHoldsAReadingAnchorOnColdScrollcollapsed + live,Performance45Tools) show zero accessibility violations with the 1px cold-scroll assertions green. Caveat: local runs use the Edge channel (Playwright chromium download is broken on this machine) - same Blink engine, different binary than CI.What item 1 still needs for a full tick: a managed-CI run of
performance-frontend.ymlon main (35 runs to date are all on feature branches, latest 09-14; I cannot trigger it), and the #5842 fix - whose absorption into the oversized-Turn hover/cold-scroll numbers would be the natural re-measurement.ggbdpq commentedon Oct 3, 2026
Independent check on the hover-gains half of item 1, on current main (
229e1b466, after #5911/#5937): the #4259 hover amplifier is no longer reproducible — its trigger is gone, not merely contained.Measurement (dense oversized-Turn fixture, ~19–20k DOM nodes; 7+7 alternating rounds × 200 synthetic mousemoves through real hit-testing on headless Edge via CDP; A/B by injecting
contain: noneon the[data-maka-transcript-boundary]sub-turn rule while keeping turn-level containment, asserted via computed style each round):With the containment fully off, nothing pathological appears — the OFF arm is the #4259 "diseased arm", and it is indistinguishable from ON.
Why (archaeology): the失效 source was never the containment rule failing. Astryx's
:where(X:hover *)invalidation rules — checked in both 0.5.2 (the review-era version, from the tarball) and 0.6.3 — hang only on Overlay/Indicator/Switch/TabList marker classes. On current main none of those classes mount anywhere inside the oversized-Turn subtree (#5911 moved the turn chrome to the Astryx layout without them); the review-era whole-Turn invalidation came from old turn chrome that did mount such classes. The containment rules themselves (chat-message.css:96,:161) are untouched.Instrument validation: forcing a full-subtree recalc (wildcard descendant rule flip + sync style read) costs ~78 ms per invocation on the same fixture — the rig would clearly see the #4259 mechanism if it still fired. One caveat for future CI work: CDP
Performance.getMetrics.RecalcStyleDurationis blind to these recalcs (reads 0.2 ms under the positive control), so latency-p95 + LoAF + a forced-recalc positive control is the honest measurement triple.Implication for item 1: the hover-gains concern has no remaining object to validate on current main. This is not a case for removing the sub-turn containment CSS — its other duties stand and were not measured here; the regression risk to guard in future is Overlay-class chrome entering the Turn subtree, not the containment switch. Boundaries: synthetic sweep ≠ real pointer, headless Edge ≠ the Electron shell (same environment class as the #4259 review), absolute values are not cross-comparable — the comparable quantity is the ON/OFF delta (= 0). Harness and raw data available on request.
perf(runtime): batch Recall session reads (#5880)
perf(desktop): add a Usage tab-entry measurement spec and a 409-recor…
ci(perf): retire the broken transcript data-plane benchmark (#5805)
ci(perf): add an end-to-end hydration measurement for long Sessions (#…
ci(perf): add a Host startup profile measurement script (#5791)