fix(cmux-tui-core): the public fold compares a restated tab decorated, as the journal writes it
Summary
Base red on feat-cmux-next (Linux, in full runs): cmux-tui-core state::group_update_latency_tests::a_persons_requests_answer_while_busy_sessions_saturate_the_registry fails in 9 of 31 full runs I have logs of: "a person's request waited behind the busy sessions: new-conversation-tab ... p95=209 to 368 ms" (budget 200 ms). Only the chat tab misses its budget.
Cause (product): a chat tab create journaled every other chat tab of its pane again. The public fold holds the decorated values the journal states (99e3260e974: the journal decorates every upsert with its state rows, so the fold folds the same decorated values). The projection restates a pane's browser tabs raw, and prune_stated_topology_deltas compared them raw: a chat tab's stored value has content_kind: conversation and extra.conversation / extra.browser_profile_id, its raw restatement content_kind: browser and neither, so it never matched and was never pruned. A probe on the shrunk case showed it: with 100 restated rows in, about 20 tab upserts kept per create, each an unchanged chat tab (stored conversation, restated browser, all else equal). Every create then paid the journal append, its subject index rows and the fold's decoration for every chat tab of the pane, under the registry lock that a person's next click waits on, and the 4 cmux agent open callers of the test each grew their own pane. (Workspaces already had a special case for the same mismatch: without_workspace_key.)
Fix: an upsert that the raw compare keeps and the fold holds is decorated with state::values::decorate_value (as the journal append decorates it) and compared again. The kept changes are journaled raw as before (the append decorates them). All callers take the registry connection after the prune.
Measured (probe, a pane grown to 400 chat tabs, 850 creates, Linux): journaled changes per create mean 108 -> 4 (max 402 -> 64), journal step mean 8.3 -> 2.5 ms (max 41 -> 10 ms), whole commit mean 12.9 -> 6.8 ms (max 59 -> 28 ms); a chat tab in the 400-tab pane 117 -> 92 ms. The rest of the per-pane cost is the per-tab validation of the pane's order, fixed in its own PR (linked below), and the tab-added entity build.
Commits: (1) red test state::group_update_latency_tests::a_chat_tab_create_restates_no_other_chat_tab_of_its_pane (31 tabs restated by one create on the base); (2) the fix.
Testing
- Deterministic red, test commit 9da5a5a9f1b: Linux (job
dd4f43c0dc7ae07c66e38059) and macOS (jobbc1ebe45e05038393031a24b): "one chat tab create restated 31 tabs". - Green at 83bc15f0600: Linux
allfilterstate::(job3a4db4b216c59e96d3c88332): 295 of 295 pass, fmt pass, clippy pass; macOS filterstate::(job6a59e6ca2ab921260dbac0b7): 295 of 295; panic ratchet (jobcbd24ba1cd0028736e4c4107) pass; projection tests filterprojection(job4a3f4afaae3b4182445e1c7a) 111 of 111, the debug cross-check included. - Full Linux (job
b8986116df12ab276fdb86b4): the latency test passes; 4 reds outside this change (acpmux::session_pool a_dead_pooled_host...,acpmux::subsessions_safety ..., and the twomachine_update_journeyreds that #36151 fixes). More full runs for the latency test are in a comment below. python3 scripts/cmux-next/prepush-gate.py: no new violations.
Observed / Not run
- Observed: the results above and the probes (branches
diag/brs-busy-nomerge,diag/brs-busy-fix-nomerge, not for merge). - Not run: a bench outside the test suite. 8 parallel copies of the latency test at once are red at base and head alike (base 12 of 24, head 7 of 24): 8 copies of 52 threads saturate the runner, so that is not this test's real load; full-suite runs are the load it is red under.
Changelog
Fixed: Opening a chat tab no longer slows down as its pane fills with chat tabs, and a busy session's writes keep less of the agent daemon's store lock.
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes a latency regression where each chat tab create in a pane re-journaled every other chat tab of that pane, adding the journal and fold decoration cost for all of them under the registry lock.
The public fold holds decorated values, but the projection restated tabs raw, so upserts never matched and were never pruned. Kept upserts are now decorated before comparison, as the journal would write them, and journaled raw as before. Decoration only runs when it alone could make the value stated — a tab, screen, or workspace differing at most in content_kind and extra; values that differ elsewhere are kept without a query. Adds a regression test asserting one chat tab create restates at most its own tabs.