perf(acpmux): track only live process slots for idle census (SW-11)

Merged
TE
5d ago
+90-3

SW-11: keep an ordered set of live background processes for idle checks and host exit

Root cause

A daemon session's ProcessTable retains completed background-process history for its list/tail contract. The frequent running_processes_read census and any_process_running check still searched every retained entry to find active work; lose_running likewise scanned all entries whenever an agent host ended. At 3,000 historical processes with only 2 live tasks, idle checks did 3,000 status tests per request despite #29277's process-id and tool-call indexes.

Change

  • Add a per-session BTreeSet<usize> of running process slots. Slots refer to the existing append-ordered Vec<Process>; the process vector remains the authoritative record and keeps its original order.
  • Update the set on insert, live→terminal fold, replay/upsert (in either direction) and host exit. A new table reconstructed from its log rebuilds the active set automatically.
  • any_process_running now tests !running.is_empty(), and running_processes_read answers running.len(), both O(1) regardless of completed-history length.
  • lose_running visits only active slots, in original append order, preserving the order and content of emitted process_update notifications. No new background scan, timer, disk state or wire field.

Regression

The added Rust test module processes_active_tests.rs exercises 3,000 completed entries plus three live ones, out-of-order replay updates, live→completed→live transitions, lost-notification order and idempotent repeat host exits. Existing Claude/Codex hub_integration process tests remain the end-to-end contract.

Performance

No perf numbers: count/idle checks become O(1) reads instead of O(N) scans, and loss propagation visits only R live entries (BTreeSet lookup O(log R) when a state changes). The test verifies the 3,000-record scale and preserved identities, but same-host CPU/RSS/wakeup measurements have not run. The live index retains a small extra entry for each currently running process.

Validation and ownership

  • Source base: feat-cmux-next@fd34ef95aa2c8f741aa23da7789e0b564732087a, which already includes #29238 and #29277. This PR extends their daemon-owned process table and does not modify any other SW-11 worktree.
  • Two Rust files, no protocol/API/UI change. Draft: unit test and Cargo/Clippy/fmt verification still need CI; no local Cargo available in the connected environment.
  • Run cd cmux-tui && cargo test -p acpmux --lib process_active_tests, cargo test -p acpmux --lib process_index_tests, cargo test -p acpmux --test hub_integration -- process, cargo fmt --check, Clippy and the NEXT fast-tier gate before marking ready. Compare base/head at 1/100/3,000 historical entries with 0/1/30 live processes.
  • Any lost-process ordering or hibernation-status regression blocks landing.

Capture

No capture: daemon-only bookkeeping with identical process-list and status responses.

Changelog: Background-process idle checks use a live set, avoiding full-history scans and ending only currently running processes on host exit.

SW-11: HQ investigation.