cmux-tui: an identical frontend projection save writes nothing and wakes no one; a session registration reads only its row (idle CPU)
Merged
TE
2d ago+168+168+012345678901234567890123456789-31-31-01234567890123456789
The app's headless cmux-tui owner idles at 29-84% CPU on a nightly with nobody using the app. A full 10 s sample of it at 29% puts the time in app-driven writes and reads, not in a loop of the daemon's own:
- one app connection (
mux-control-dispatch):WorkspaceRegistry::put_session(SQLite) andMux::personal_snapshot(list-personal), about 3100 of 5052 samples, most of the latter blocked on the registry mutex; mux-launch-snapshot:Mux::personal_snapshot, about 1870 of 5052, rebuilding after each change event;mux-connthreads:put_frontend_projection(SQLiteexecute_batch).
This PR makes the daemon side cheap whatever the app sends. A follow-up fixes the app's re-registration ping-pong (SessionRegistrar).
Changes
put_frontend_projectionwith an identical body is no change. The app saves its window and sidebar documents again on many events with nothing changed. Each save under a new mutation id bumpedprojection_revision, wrote the row and a ledger row, and emittedFrontendProjectionChanged. That woke every subscriber and the launch snapshot writer, which rebuilds the personal snapshot under the registry lock. Now the stored schema version and canonical payload are compared in SQL, without loading the row. If they match, the stored revision comes back withreplayed: true: nothing is written and no event is emitted, the same way a repeated agent report already behaves. The expected-revision check still runs first, so a stale client still gets its conflict.- A session registration reads only its own row.
read_sessionused to read and parse every session row, each with its capability list (several KB), to find one. It now does a keyed lookup. An identicalput-sessionalready wrote nothing and emitted nothing (#30457); it now costs one row read instead of O(sessions) JSON parses.
No new timers, threads or observers.
Tests
workspace_registry::tests::an_identical_frontend_projection_under_a_new_mutation_writes_nothing. It fails on base, where the second save gets revision 2 andreplayed: false, and passes on head. It covers key order, the ledger row count, a matching and a stale expected revision, and that a new body or schema version is still a change.- The existing frontend projection, personal and
put-sessiontests are unchanged.
Performance
| metric | before | after | delta | harness or run link |
|---|---|---|---|---|
| writes per identical projection save | 2 rows (projection and ledger) plus 1 change event | 0 | -100% | an_identical_frontend_projection_under_a_new_mutation_writes_nothing |
rows parsed per identical put-session | every session (with capabilities) | 1 | O(sessions) to O(1) | read_session |
| app headless owner idle CPU on an idle nightly | 29-84% (sample: put-session, list-personal, put-frontend-projection) | to be read after the next nightly | sample after the next nightly |
Observed / Not run
- Observed: the samples of the idle nightly owner (above). The new test fails on base and passes on head (run with cmux-ci; see the PR comments).
- Not run: an end-to-end idle measurement. That waits for a nightly with this change.
Changelog
none
Agent session: agent session
š¤ Generated with Claude Code