fix(cmux-tui-core): link peers and host proxy authors are published; S1.1 review follow-ups (R-DAEMON-STATE S1 step 2)

Merged
LA
3d ago
+447-153

Summary

R-DAEMON-STATE stage S1 step 2 (handoff/rewrites/R-DAEMON-STATE/DESIGN.md, section 3 and Appendix A.2 steps 3, 7, 12, 13), plus the follow-ups of the #34014 review (comment https://github.com/manaflow-ai/cmux/pull/34014#issuecomment-6612546773). Stacked on #34146 (base fix/p0-typing-s1-admission, itself on #34014); it retargets to feat-cmux-next when they land. Everything is behind the same per-mux switch CMUX_TUI_RDS_INPUT (default off; the app knob CMUX_NEXT_TUI_RDS_INPUT from #34139).

Step 2. A person's key line asked two more shared locks: the link peers (RemoteRelayState.peers: the remote-client check and the request's actor) and the host proxy authors (AgentSessions.proxy_authors: the proxy-link check on the reader thread). Every remote bind, disconnect and revocation sweep holds the first; every proxy bind and every client's disconnect holds the second. The S1 census measured a full wait on each (300.5 ms and 300.4 ms, hosted run 41648095321).

  • published.rs moves to cmux-tui-util (daemon primitives, no daemon state), so cmux-tui-remote-access can use it.
  • RemoteRelayState.peers becomes a Published copy of the records. peer_checked reads it with no lock when the value publishes (Published::publishing, fixed from the mux's switch); a poisoned map still fails closed. AgentSessions.proxy_authors publishes the same way; proxy::author reads it.
  • Writers stay where they are. A disconnect of a client without a record (every local one) changes nothing, so it publishes nothing.

#34014 review follow-ups (each with its red test below):

  1. RouteTable::try_reserve copies a map that a published snapshot shares, before the durable commit, so the insert after the commit allocates nothing (ResourceMutationPlan::apply: "Plan builders reserve all needed capacities before returning"). The plan reserves and applies under one state guard, so no publication shares the map again in between.
  2. A change that a panic cuts short is never published, by the state guard (routes) or by a PublishGuard. Drop skips the publication when a panic began while the guard held the lock (the test std makes to poison a mutex), so no reader sees half-made tables, not even in the moment before the mutex is poisoned.
  3. A PublishGuard frees the projection it replaced after the unlock, as the state guard does.
  4. The two relay poison tests run on both arms (lane off and on).
  5. ClientFacts and types_into move to server/client_registry/facts.rs (god-file warning on client_registry.rs).
  6. Kept as is, with the reason: the test settle helper polls try_pop every 1 ms, because BoundedOutbound has no timed receive and a blocking recv would hang a failing test instead of failing it after 5 s.

Testing

Focused command: ./scripts/verify-cmux-tui-hosted.sh --filter <filter> (Linux test (linux) job).

  • Step 2, red at 154730a175d (test/rds-s12-red-never-merge), hosted run https://github.com/manaflow-ai/cmux/actions/runs/41691094153: a_key_waits_for_neither_the_link_peers_nor_the_proxy_authors_lock FAILED. Controls (lane off) 300.32 ms and 300.29 ms; lane 300.34 ms (link peers) and 300.24 ms (proxy authors).
  • Follow-ups 1 and 2, red at 44623898e7f (same branch), hosted run https://github.com/manaflow-ai/cmux/actions/runs/41698188517 (filter published): FAILED a_reservation_unshares_a_published_map_so_the_insert_after_the_commit_allocates_nothing ("the insert after the commit copied the map"), a_change_cut_short_by_a_panic_is_never_published ("the half-made change was published": 9), routes_of_a_change_cut_short_by_a_panic_are_never_published ("the routes of the half-made change were published").
  • Green at the head 8f7d40500e8, three hosted runs, Linux test (linux) all passed:

Compile: fleet job 8fc861788dd09c7da81638b3 at 8f7d40500e8 passed (CmuxNext 295 s, app 96 s, cmux-tui 64 s).

Observed / Not run

  • Observed: the hosted runs and the fleet compile above.
  • Not run: the full cmux-tui suite with the switch off on this head (next, after the stack is merged with feat, so the old base's acpmux reds do not hide results); macOS execution of the focused tests (the macOS job stops at the old base's acpmux unused-import red first); the real-app A/B (after S1 lands).

Review round 2 (head 0fb7c43a810)

The review at 8f7d40500e8 (comment 6614044759, FIX) found two defects; both are fixed, with the notes taken too:

  1. mux/tests/signaled_mutex.rs:120: the unnecessary qualification (clippy unused_qualifications, -D warnings) is removed (10f16693a03).
  2. published.rs: poison_for_test is test code again: a private helper in the published tests and one in the relay tests, with plain panic! (no panic_any respelling) (bb0265f43d5, 0fb7c43a810).
  3. Note taken: Mux::surface on the lane reads the published routes only while the session state is not poisoned; a poisoned state takes the old read and fails as it does (StateMutex::is_poisoned). Red first: 690b82fb3b8 (test/rds-s12b-red-never-merge), hosted run https://github.com/manaflow-ai/cmux/actions/runs/41710119273: a_poisoned_session_state_never_routes_by_the_published_tables FAILED.
  4. Note taken: Published::load debug-asserts that the value publishes; the module doc says what load gives on a poisoned value and that the caller chooses fail-closed or recover.

Green at 0fb7c43a810 (Linux test (linux) passed): https://github.com/manaflow-ai/cmux/actions/runs/41713629272 (filter a_poisoned: every relay poison test, the new one included) and https://github.com/manaflow-ai/cmux/actions/runs/41713669636 (filter published). Its lint (linux) job now fails only on base counts: acpmux/src/login_env/watch.rs:15 (fixed on feat by #33664/#33690) and the panic ratchet's acpmux / cmux-host rows; no cmux-tui-core, cmux-tui-util or cmux-tui-remote-access error. Compile at bb0265f43d5: fleet job 1aabe5e67ecd7db5b0083eb9 passed (CmuxNext 390 s, app 100 s, cmux-tui 60 s); 0fb7c43a810 only changes one test line after it.

Changelog

none

Proof

No capture: daemon-only change behind a default-off switch, no UI.