Repository navigation
acpmux: under MDM's forced off, agents already in full access end (#23322 b) - #25539
teamleaderleo wants to merge 34 commits into
Conversation
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
Owned by an agent session · session |
cc85593 to
2ffe473
Compare
|
Bead |
1cf4f25 to
44feabb
Compare
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
web and size checks: green |
…se per form the reviews found (#23322 b; red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ns true for it (#23322 b) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… at a later MDM push, and a subagent mode does not hide it (#23322 b, review 27; red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the log, a subagent's mode is not its session's, and ending is bounded (#23322 b, review 27) The push and the background check read back the mode a harness that declares no modes reported, before the in-memory check, for a host a restart left. The readback skips updates the tap marked as a subagent's (on another thread than the session's own), as on_update does live. The child's terminate is bounded; a host that never answers is ended by its nonce. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both set CMUX_NEXT_CONFIG_FILE; run in parallel, one table's daemon read the
other's settings file ("MDM unset changes nothing" failed one run in four).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…off push an unset push follows (#23322 b, review 36; red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ted with, and each off push ends what runs in full access before the next push lands (#23322 b, review 36) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…b, review 44) `spawn_argv` was set in memory before the spawn and written by whichever save came next. On a cold start that is the folder check's (`revive_folder`), which saves only when its git read answers within 2 s; past that, a daemon that died while the agent initialized left a host the next daemon judged by the old argv, and under MDM's off adopted it. The start now saves the argv itself when it changed. durable_agents a_host_a_daemon_left_while_it_started_ends_under_mdm_off_by_the_argv_it_ran covers the crash and restart. It passes on the previous head too, because there the folder check's save lands in time; no test seam makes the git read slow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s, and one whose end failed (#23322 b, review 51; red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and one whose end failed is never reached (#23322 b, review 51) The bound read back only a no-modes harness's current_mode_update, and only when the saved chat had no modes; it now reads back every mode and option the left host reported since it started (start answers, set_mode and set_config_option answers, its own updates), once per host. A host whose end by nonce fails keeps what says it runs in full access, is not adopted, and its chat is refused until it ends. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
…the off (#23322 b, review 68; red) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… is not heard (#23322 b, review 68) Adoption and re-adoption carry MDM's off as an OffLatch (the state with the count of offs, read once where they begin), so an off pushed while a left host is adopted still judges what its replay says before the agent is handed out. A host reader that stops for any reason marks its agent not alive before it tells the hub, so a failed acknowledgement with the socket still open counts as unheard under the off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review (codex gpt-6-astra xhigh, next-review): BLOCK at a53707b
|
What (part b of #23322)
This is part b of #23322 (sessions.allowFullAccess under MDM). It was stacked on #23322 (a1); a1 has landed on
feat-cmux-next(33db003), and b is rebased onto it, so its base isfeat-cmux-next. The rebase kept both sides of the two conflicts: a1'srefuse_started_in_full_accessnext to b'sfull_access_turned_off(changed), and both sets of test profiles infull_access_managed.It builds the decision on #23322, quoted word for word:
"Full access is unavailable" also covers agents already running in it. Under MDM's off, an agent ends wherever
runs_full_access(a1's one predicate) turns true for it.end_if_runs_full_accessalways runs under the session's spawn lock. It ends the live child and any host a restart left, and it nulls a full-access option value, so the next start doesn't replay it. The places it runs:full_access_turned_offcallsend_every_managed_full_accesson every session. A turn in progress ends with it.ensure_childchecks first.child_fornever hands out such an agent, and the idle-reuse path skips it.web_controlwakes the hub's background task (idle.rs), which ends the agent under the spawn lock.end_if_runs_full_access.adopt_agent_hostsends a host left in full access instead of adopting it, so its turn is not resumed. For a harness that declared no modes, it first reads back from the log the mode the harness last reported (read_back_undeclared_mode). A live host this build can't read (another record version) ends too.The readback skips a
current_mode_updatethe tap marked as a subagent's (SubagentTree::annotatemarks only another thread than the session's own), ason_updateskips it live; a mark on the session's own thread does not hide its mode. Ending a live child is bounded (twiceSHUTDOWN_GRACE), and a host that never answers is ended by its nonce.Past review findings, each now a case or a unit test of the predicate:
--yolo) started anyway; thestart_modeanswer was staleBOUND"round 1 and 2: a profile pinning full access in argv does not start"; "the off holds across a restart"--permission-mode=bypassPermissions,-sdanger-full-access,-csandbox_mode=...,-y,--approval-mode yolo); agents already running or adoptedBOUNDpinned profiles (all spellings); bRUNNING"round 2: an agent running in full access takes no more work"child_for)full_access_guards); b:child_forand the start path callend_if_runs_full_accessunder the spawn lockadopt_agent_hostsends it (durable_agentsa_retained_full_access_host_ends_once_mdm_turns_full_access_off); a switch re-checks after it writes its modeUndeclaredModeandOption; bRUNNINGround 5 cases;durable_agentsan_unadoptable_full_access_host_ends_once_mdm_turns_full_access_offfull_access_turned_offwaits on everysession.permissionslock; bread_back_undeclared_mode(durable_agentsa_retained_host_that_moved_itself_into_full_access_ends_once_mdm_turns_it_off); a2 probe ticketsmodeconfig option saying full access whilemodes.currentModeIdasksOptionincludes themodeoption; bRUNNING"round 8: a harness whose mode option says full access while its mode asks ends"; uniteach_form_of_full_access_is_foundreplay_configread the setting onceBOUND"round 9: a switch into full access that the push overtakes is refused";spawn_pooledrefuses and the push drains the pool;replay_configis base's per-step read again; a4 (#25549) "round 9: a profile pinning full access is not probed under the off"end_managed_full_accessbounds it to twice the grace, then ends the host by its nonce (no deterministic test: the stuck link has no seam); (2)durable_agentsan_adopted_host_that_moved_itself_into_full_access_ends_when_mdm_turns_it_off; (3)durable_agentsa_subagents_mode_does_not_hide_its_sessions_full_access_across_a_restart; (4) a4 (#25549)SessionMeta::spawn_argv, set inensure_child, kept across a restart) andFullAccessView::of_sessionreads it, falling back to the creation's before any start:RUNNING"review 36: an agent a config reload respawned with a pinned argv ends at the push"; (2) pushes run one at a time through their teardown (Hub::full_access_pushes), and every off push ends what runs in full access, only the changing one draining the pool:RUNNING"review 36: an off push ends every full-access agent, also when an unset push follows"spawn_argvwas set in memory before the spawn but written by whichever save came next, so a daemon that died while the agent started could leave a host the next daemon judged by the old argv and, under MDM's off, adoptedensure_childsaves the argv itself before the agent starts, when it changed:durable_agentsa_host_a_daemon_left_while_it_started_ends_under_mdm_off_by_the_argv_it_ran(a model pick restarts the chat on a profile a reload pinned to--yolo, the daemon is killed while the agent initializes, and the next daemon under MDM's off ends that host)current_mode_update, and not at all when the saved chat had modes, so saved metadata older than the host's reports (a crash before the save) hid a full-access mode or option and the host was adopted under MDM's off; (2) a failed end by nonce was ignored: the evidence was scrubbed and the host could be adopted or reached againreported_by_left_hostrebuilds the host's modes and options from its log sincehost_started(start answers,set_modeandset_config_optionanswers, its own updates; a subagent's skipped), whatever was saved, once per host; (2)end_managed_full_accessreturnsStillRunningand keeps the evidence while the host may run: adoption skips it and a start is refused withfull_access_offuntil it ends. Tests:durable_agentsa_left_host_ends_under_mdm_off_by_the_modes_it_reported_not_the_saved_ones(mode and mode option) anda_full_access_host_whose_end_failed_is_never_reached_under_mdm_off(debug seamACPMUX_TEST_HOST_END_FAILS)set_config_optionthe harness answered without its options was not counted, so a full-access value it took looked askinghost_adopted, and hands nothing out when it ends or cannot end; (2) the value a bare answer took is kept (FloorState::asked_options, read by the bound, replaced by the next options the harness reports, gone when the agent exits or ends) and the left-host readback takes the request's value when the logged answer has no options. Tests:durable_agentsa_full_access_option_answered_without_options_ends_under_mdm_off(live push and restart) anda_mode_a_left_host_replays_is_judged_before_its_agent_is_reached_under_mdm_off(the harness changes mode outside any turn while no daemon is attached; debug seamACPMUX_TEST_UPDATE_DELAY_MSholds each update before the inbound loop applies it)host_started. Tests:durable_agentsnull cases ofa_full_access_option_answered_without_options_ends_under_mdm_off(after an off and an unset push),a_left_host_whose_log_cannot_be_read_ends_under_mdm_off(debug seamACPMUX_TEST_LEFT_HOST_SCAN_FAILS),a_left_host_whose_replay_is_incomplete_ends_under_mdm_off(debug seamACPMUX_TEST_REPLAY_INCOMPLETE).replayrecords) was not read back; (3) a fork's answer (the new chat's defaults) was read as this chat's statehost_startedand needs every record after it inseqorder; a gap, a missing start or a read error counts as full access under MDM's off; (2).replayupdates count as their live kinds, ason_updatewrites them; (3) a fork's answer is not read. Tests:durable_agentsa_left_host_whose_log_lost_a_record_ends_under_mdm_off,a_full_access_mode_reported_during_a_load_ends_a_left_host_under_mdm_off,a_forks_answer_does_not_hide_its_parents_full_access_under_mdm_offseq; (2) a link that broke while its host ran was reattached and handed out before what the host kept meanwhile was judgedStore::scan_strict: an unreadable line is an error, counted as full access under MDM's off); (2) under MDM's off a reattached agent waits for its host's replay and is judged again before it is handed out, and ends when it runs in full access or the replay did not complete. Tests:durable_agentsa_mode_a_reattached_host_replays_is_judged_before_its_agent_is_reached_under_mdm_off(debug seamACPMUX_TEST_UNLOGGED_ONCEfails to log one host entry, which breaks the link) anda_left_host_whose_log_ends_in_a_torn_record_ends_under_mdm_offdurable_agentsa_host_whose_link_broke_ends_when_mdm_turns_full_access_offInbound::LinkBroken), which runs the full-access check at once under MDM's off; (2) a failed end is kept (full_access_end_pending) until an end succeeds or a new host starts, and every check counts it as full access; (3) the end answers what waited on the agent and cancels its pending permissions. Tests:durable_agentsa_link_that_breaks_under_mdm_off_ends_its_agent_at_once,a_failed_end_of_an_unheard_agent_is_tried_again_by_the_next_push,a_prompt_on_an_unheard_agent_settles_when_mdm_ends_ithost_record_gone), else it stays pending. Tests:durable_agentsa_link_lost_under_mdm_off_ends_its_agent_at_once,an_end_that_could_not_read_the_host_records_is_tried_againhost_record_gone). Test:durable_agentsan_adopted_host_in_full_access_ends_under_mdm_off_though_its_records_cannot_be_readOffLatch), so an off pushed meanwhile judges the replay; (2) a reader that stops marks its agent not alive before it tells the hub. Tests:durable_agentsan_off_pushed_while_a_left_host_is_adopted_judges_its_replay,an_agent_whose_ack_failed_ends_under_mdm_offTests
tests/full_access_managed.rsunder_an_mdm_off_what_runs_in_full_access_endsruns theRUNNINGcase table:modeoption says full access while its mode asks ends;tests/durable_agents.rs:a_retained_full_access_host_ends_once_mdm_turns_full_access_off;a_retained_host_that_moved_itself_into_full_access_ends_once_mdm_turns_it_off;an_unadoptable_full_access_host_ends_once_mdm_turns_full_access_off.Red at fe91440 (a1's code with these tests, run 40370601829): all four
RUNNINGcases and the three durable tests fail.Green at 740fd4f (run 40370601422). fmt and clippy are clean,
full_access_managedpasses 2/2, anddurable_agentspasses 56/56. Besides a1's base reds, twohub_integrationtests failed in the full run:stop::a_cancel_ends_an_honouring_agents_turn_within_the_budgetandsubagent_retry::the_retry_queues_behind_a_running_turn. Run alone three times, both pass on this head and on base (runs 40372489684 and 40372489383), so they are timing flakes under the full run's load.Review 27 round: red at eb44da3 (b's code with the two new
durable_agentstests; run 40380501478 on the same tree: the adopted agent ran on after the push; run 40379138809 on 8f95c07, the same subagent test: the subagent's mode hid it). Green at 2ffe473 (rebased on a1 e70c3d8; run 40379138660 on 01a1bc3: fmt and clippy clean, lib 1101/1102 with only base's red,full_access_managed2/2,durable_agents58/58,hub_integrationfull_access14/14; run 40381441370 on cc85593, the same tree as 2ffe473). aa5bc58 makes the two case tables run one at a time: both setCMUX_NEXT_CONFIG_FILE, and run side by side "MDM unset changes nothing" read the other table's settings file once in four runs (run 40381990458). At aa5bc58 five runs pass, with fmt and clippy clean (run 40382894202).Old code: the pre-restructure head with the full case table is 64e5662 (run 40365300783). There, the round-8 case fails.
Review 36 round: red at 5d59ab8 (the two new
RUNNINGcases on aa5bc58; run 40393100527: "the respawned pinned agent ran on after the push" and an agent "ran on after the off push"). Green at 1cf4f25 (run 40393298206:full_access_managed2/2,session_pool17/17,durable_agents57/58; run 40393298519: fmt and clippy-D warningsclean, lib 1101/1102 with only base's red; run 40393298156:hub_integration490/491). The two failures are the known flakesdurable_agentsstalled_turn::an_adopted_turn_whose_model_went_quiet_ends_as_stalled_and_frees_its_agentandhub_integrationstalled_turn::a_turn_counts_from_its_prompt_being_written; both pass alone at 1cf4f25 (run 40393818409).Review 44 round (rebased onto
feat-cmux-nextwith a1): the newdurable_agentstest does not fail on the previous head, so there is no red run. A save-site probe (run 40404365364) found that on a cold start the folder check (revive_folder,worktree_care/revive.rs) saves the chat afterspawn_argvis set and before the spawn, but only when its git read answers within 2 s. The fix makes the save independent of that read; the test covers the crash and restart and guards against that save going away. No test seam makes the git read slow. Green at 44feabb: run 40405195004 (fmt and clippy-D warningsclean; lib 1142/1143 with only base's redown_servers_run_under_the_daemon_prefix), run 40405199026 (durable_agents63/63,full_access_managed2/2,session_pool16/17 with only base's redpooled_sessions_end_with_the_daemon_and_after_a_crash), run 40405201915 (hub_integration497/497).Review 51 round (rebased onto
feat-cmux-next3e72956): red at db599af (run 40411599957: both newdurable_agentstests fail; the next daemon adopted the full-access agent on its saved modes, and a prompt reached the host whose end failed). Green at 4b9443e: run 40411974631 (fmt and clippy-D warningsclean; lib 1164/1165 with only base's redown_servers_run_under_the_daemon_prefix), run 40412437781 (durable_agents65/65,full_access_managed2/2), run 40411974621 (session_pool16/17 with only base's redpooled_sessions_end_with_the_daemon_and_after_a_crash), run 40411974764 (hub_integration497/497). The diff is about 880 changed lines, some 550 of them tests; the code part stays near 330.Review 60 round: red at 7e2954b (run 40420750440: the bare-answer test fails, the agent ran on under the off) and dfe9e5d (run 40422629526: "a prompt reached the full-access agent the host replayed"). Green at 2bd9843: run 40422935460 (fmt and clippy
-D warningsclean; lib 1164/1165 with only base's redown_servers_run_under_the_daemon_prefix), run 40422935087 (durable_agents67/67,full_access_managed2/2,session_pool17/17), run 40422935074 (hub_integration497/497).Review 61 round: red at 3549eb4 (run 40428603661: the three tests fail; the null-answer agent ran on, and the next daemon adopted both left hosts). Green at da67daa: run 40428603664 (fmt and clippy
-D warningsclean; lib 1164/1165 with only base's red), run 40428603691 (durable_agents69/69,full_access_managed2/2,session_pool16/17 with only base's red), run 40428603706 (hub_integration497/497).Review 62 round: red at 2b17332 (run 40435892213: the three tests fail; the next daemon adopted each host). Green at 7d65e3f: run 40436061104 (fmt and clippy
-D warningsclean; lib 1164/1165 with only base's red), run 40436061303 (durable_agents72/72,full_access_managed2/2,session_pool17/17), run 40436061120 (hub_integration497/497). Known cost: under MDM's off, a log a crash tore mid-write ends the host the restart left, since what it reported cannot be ruled out.Review 63 round: red at dc30179 (run 40441769368: the reattach test fails, "the full-access agent a reattached host replayed answered a prompt"). The torn-record test passes on the previous head too: there the next daemon also ended that host by another path, so the test guards the strict read rather than proving a red. Green at aad7934: run 40441769314 (fmt and clippy
-D warningsclean,durable_agents74/74); e8dc375 has the same code and only differs in that test: run 40440768263 (lib 1164/1165 with only base's red), run 40440768387 (full_access_managed2/2,session_pool17/17,stats11/11,prompt_images29/29), run 40440768868 (hub_integration497/497).Review 64 round: red at 4b4d2d7 (run 40451136699: "an agent whose link broke ran on after MDM turned full access off"). Green at 522d78e: run 40451136658 (fmt and clippy
-D warningsclean,durable_agents75/75); 7038765 has the same code: run 40450081606 (lib 1164/1165 with only base's red), run 40450081231 (full_access_managed2/2,session_pool17/17,stats11/11,prompt_images29/29), run 40450081188 (hub_integration497/497).Review 65 round: red at 30b2910 (run 40453253479: the three tests fail). Green at 5f9aabf: run 40453375422 (fmt and clippy
-D warningsclean; lib 1164/1165 with only base's red), run 40453375230 (durable_agents78/78,full_access_managed2/2,session_pool17/17,stats11/11,prompt_images29/29), run 40453375339 (hub_integration497/497).Review 66 round: red at f235570 (run 40454765151: both tests fail). The fix 654effc, then feat-cmux-next merged in (a3 and a4 landed) with the off read once per operation and passed down, and session ids read through one blank-to-None normalizer (
known_id). Green at 81d6df6: run 40456355829 (fmt and clippy-D warningsclean; lib 1318/1319 with only base's red), run 40456355928 (full_access_managed2/2); at d79ba80 (the same code before a clippy fix): run 40455737157 (durable_agents84/84,session_pool26/26,stats29/29,prompt_images11/11,web_mode_current13/13), run 40455737258 (hub_integration507/507).Review 67 round: red at de54566 (run 40457941135: the test fails). Green at 5ec5de1: run 40458211283 (fmt and clippy
-D warningsclean; lib 1318/1319 with only base's red), run 40458611259 (durable_agents85/85), run 40458211274 (full_access_managed2/2,stats29/29,prompt_images11/11,web_mode_current13/13,session_pool25/26 with onlypooled_sessions_end_with_the_daemon_and_after_a_crash, which fails the same way on base: run 40458862075), run 40458211223 (hub_integration507/507).Review 68 round: red at cab0e08 (run 40460850011: both tests fail). Green at a53707b: run 40462536166 (fmt and clippy
-D warningsclean; lib 1318/1319 with only base's red), run 40462536156 (durable_agents87/87,full_access_managed2/2,stats29/29,prompt_images11/11,web_mode_current13/13,session_pool25/26 with only base's red), run 40462536120 (hub_integration507/507).Size: about 2030 changed lines: some 1210 in tests (
durable_agents,full_access_managed, the fake agent) and some 820 in code. It stays one PR because each review round's fix and its red test belong to the same bound.No capture: no UI changes.
Review: review 69 (Codex gpt-6-astra xhigh) at a53707b is BLOCK with three findings not yet fixed: (1) a pooled entry claimed before an off push keeps no count of offs, so after an unset it can be handed out though it ran during the off; (2) records that cannot be read can let a stale clean log read be cached in
left_host_read; (3)child_for's fast path reads only what the inbound loop has applied, so a prompt can reach an agent whose full-access update is logged but not applied yet.Agent session: agent session
🤖 Generated with Claude Code