acpmux: CLI sessions from an interactive Mac go to a fleet host; held hosts never placed; session stop --id without --mesh
On 2026-10-29 cosmic-gray (Leo's interactive Mac) beachballed: an agent broadcast woke about 64 idle sessions at once, and the coordinator stopped 94 idle sessions with Leo's OK. The coordinator's order, which Leo approved ("Yes, do both"):
a resumed session restarts on cosmic-gray, and new lanes still default here. Fix both in your lane. A resume or new session from an interactive Mac (cosmic-gray, air-blue) should be placed on a fleet host through host place, unless the user opened it in the GUI. A host that sits idle for more than about 10 minutes should stop on its own, and the session stays resumable. Also: session stop with --id demands --mesh, and only the positional form works. That's a CLI papercut; fix it too.
And Leo: "lawrence is currently usign 16-24 for a bit".
What
- New sessions from an interactive machine go to a fleet host (
cli/place.rsnew_target,server/place.rs). On a machine the fleet registry marks interactive,acpmux newwith no--hostnow places the session the way--host autodoes. The placement leaves out every interactive machine, this one included (_acpmux/placewithoffInteractive).- The interactive check comes from the registry (
placement::interactive): a machine is interactive if its entry hasinteractive: true, or if it holds the registry's role for a person's own machine (leo-macorattended). Today that is cosmic-gray and air-blue. No host names are written into the code. --host localkeeps the session on this machine.- A launch that names a local folder (
--cwdor-w) stays here and prints a warning saying how to place it. A fleet host refuses a folder on this machine: a peer may use only a known project or its webRoots (remote_guard.rs). - If no fleet host takes it, a
newthat named no host starts here with a warning, since placement never refuses a launch for load. The exception is when the registry holds this machine; then it stops. An explicit--host autostill stops when nothing is picked, as before. - Chats opened in the app are not affected. The app creates them over its own connection (
session/new) and never goes through the CLI'snew.
- The interactive check comes from the registry (
- Held and reserved hosts are never placement candidates (
placement.rshold,held_at). A registry machine entry withhold, or a top-levelreservationsentry naming the machine, means it takes no new work. It is skipped even as the fallback when no other host has room.holdcan betrue, a reason, or{reason|why, owner, until}. This covers the per-machineholdfield a sibling lane is adding to fleet-registry.json, so it works as soon as that lands.- A reservation is active from its
fromto itsuntil. cmux16 to cmux24 are reserved for Lawrence today. - A hold or reservation whose time cannot be read still holds.
- Without this, the new default placement could send sessions from cosmic-gray to Lawrence's minis.
- #27662 carries its own copy of the reservation reader. Whichever PR lands second drops its copy.
- The idle stop already ends the agent host, not only the harness. The idle pass terminates the hosted child (
Terminate). The harness exits, and the agent host leaves its loop once its exit entry is acked. The session stays resumable. The default bound is 120 s (hub::IDLE_CHILD), well under 10 minutes.an_idle_hosted_agent_is_terminated_and_the_session_resumesnow also checks that the agent host process exits and that its record is gone before the session resumes.hub/idle_census.rs(why some harnesses stay up) is left to the sibling lane. session stop --id IDworks without--mesh(cli/mesh_control.rs).--idno longer requires--mesh. Without--mesh, an id already resolves as an id, sostop --idandresume --idnow run the same as the positional forms.--idempotency-keyis still mesh-only.
Not in this PR: a CLI resume of a stopped session on an interactive Mac still restarts it here. Placing a resumed session elsewhere means moving its history, which is the session move --host auto path in #27662. That resume routing follows once #27662 lands.
Tests
placement_tests:a_reserved_host_is_never_a_placement_candidatecovers the active window, lapsing beforefromand afteruntil, an unreadable time and lookup by alias.a_held_host_is_never_a_placement_candidatecovers every form ofhold, the overloaded fallback, a lapsed hold, an unreadableuntiland lookup by alias.interactive_machines_come_from_the_registrycovers theinteractivefield, theleo-mac/attendedroles, aliases and having no registry.server::place:off_interactive_drops_the_machines_people_work_at.cli::place:a_new_from_an_interactive_machine_is_placed_unless_a_host_is_namedalso covers the no-pick case: an explicitautostill stops, an implicit one starts here, and a held machine stops.cli::mesh_control:id_without_mesh_runs_the_local_command.session_control_peer_cli(integration): stops a peer session withsession stop --id IDand no--mesh.durable_agents(integration): the idle agent host exits and the session resumes.
Risk
Medium. This changes the default for a command-line new on cosmic-gray and air-blue: such a session now runs on a fleet host, in that host's scratch folder. --host local restores the old behavior. The app's chats and every other machine are unchanged.
Overlap: #27662 (session move) also edits placement.rs. It adds reservations in place, while this PR touches only lane_hosts/weigh, so their hunks do not overlap. The duplicate reservation reader goes in whichever PR lands second.
Review: Codex gpt-6-astra (high, fast) via review-router. The first pass found three blocking issues: an explicit --host auto fell back to this machine, a held machine could still take sessions through that fallback, and reservations were not enforced. All three are fixed in the second commit. The second pass found that unreadable hold or reservations data failed open; the third commit makes it fail closed (unreadable_holds_and_reservations_hold). The third pass returned SHIP at 55dc06bfc2bc.
Agent session: agent session
š¤ Generated with Claude Code