acpmux: a sub-session answers to its short name; a miss names the close matches
Leo, 2026-10-30: "i feel like there's still a big mess of uncategorized stuff in the sidebar + various not as ergonomic/one-command-y as i'd liike set of commands for interacting with stuff" / "good intuitive stuff" / "and also docs!"
Part of HQ#5197.
Carried on top of #28000
This lane took this PR over: its first lane is gone, and it now builds on #28000 (one session-key rule in the daemon, hub/key_route.rs). The original commits keep their authorship. On top of them:
- The short name is
key_route's last tier. A bare key that no whole name or id prefix matches anywhere, and that no name here starts with, names the one sub-session on any host whose last name segment it is (lane-3forcoord/lane-3). Two such sub-sessions are refused with the samesession_ambiguousrefusal #28000 gives, which prints the exactHOST/NAMEcommand for each. A key with a/is a whole name only, never a short name. Hub::resolve,resolve_remote,locate::by_keyand the close-matches refusal are as below. They now serve the callers thatkey_routepasses over (web and peer connections, and keys that are exact already).- Test fixtures use neutral sample host names (fleet rule lint).
Original description
What was wrong
acpmux send lane-3 failed with no_session when the lane is really the coordinator's sub-session coord/lane-3 (a child is named PARENT/SHORT). acpmux ls shows the short name under the parent, but no resolver took it. The refusal then said only "run acpmux ls", which on a busy host means reading thousands of rows.
What changes
- One rule, in every resolver.
session_name::ends_with_segments(name, key):keyis the name's last/-separated segments (lane-3andcoord/lane-3namecoord/lane-3;ci-3does not). It is applied after an exact id or whole name misses and ahead of a prefix in:Hub::resolve(local sessions): whatsend,last,wait,info,watchand the other name-taking commands reach through_acpmux/info/ the send queue;Hub::resolve_remote/remote_matches(a peer's sessions, alsoPEER/SHORT);_acpmux/resolve(hub/locate.rs), used bysession resume|stop|cancelandretry.
- Precedence stays safe. A whole name always wins over a short name, including a peer's session with exactly that name (the local short-name match then gives way, as before). Two sessions with the same short name are refused with their names and ids, even if a third session has the key as a prefix.
- A miss names the close matches.
no session matches "lane"; close matches: coord/lane-3, hb/lane-30; use one of those names, or run acpmux ls. Also in--jsonaserror.data.candidates(at most 8). The refusal is stillno_session, exit 4, and it still starts withno session matches, whichcmux-tui-coreand the webview send parser read. Candidates are only given to local-socket callers. A peer connection gets the plain refusal it got before. - Hot path:
Hub::resolvestill reads each name once under its meta lock, in one pass now. The close-match scan runs only where a refusal goes back to a caller (Hub::resolve_told, the send queue's refusal,_acpmux/resolve's not-found), never when a request is just probed to see if it belongs to a peer. - README: the name forms now include the short name.
Tests
session_name::tests: segment boundary rules, candidate ranking/dedup, refusal text and data.hub::own_host::segment_tests: short name found locally; whole name beats short name here and on a peer; ties refused with names; peer short names (lane-3,PEER/lane-3);resolve_toldlists local and peer close matches, and a peer connection gets none.hub::locate::tests::a_sub_session_is_found_by_its_short_name: the control resolver, includingHOST/SHORT.cli::errors::typed_error_tests::a_no_session_refusal_names_the_close_matches: candidates reach message and envelope; stillno_sessionexit 4, so the send relay (sendRelay) still takes it.
Agent session: agent session
š¤ Generated with Claude Code