Repository navigation
cmux-tui hook: one queue and one connection per agent; a busy daemon never costs a hook event - #28041
Conversation
…heir own module No behavior change. cmux-tui-hook.rs was 51 lines past its god-file baseline; the socket append (connect, write, read, retry) moves to cmux-tui-hook/journal_append.rs, so the next change (pa-b2: back off on a refused append) does not grow the hook file. The file now meets the budget and leaves the baseline.
… hooks do not retry in lockstep (red) pa-b2 (#27698, 55,162 refusals in 2.5 h). Three tests against a fake daemon at its connection limit: - a_refused_append_is_kept_until_the_daemon_admits_it: today the busy line fails the append ("invalid response envelope") and the hook event is lost. - a_retryable_failure_backs_off_instead_of_spinning: today retry_until calls yield_now between tries and runs a core for the whole bound. - hooks_refused_at_once_do_not_retry_in_lockstep: 16 hooks refused together must each wait at least retry_after_ms and come back spread out.
…jitter pa-b2 (#27698: 55,162 refusals in 2.5 h on Austin's nightly-next). A daemon at its connection limit answers with its busy line (type "refused", server.busy) and closes. The hook child took that line for an invalid response envelope and dropped the event. A connect or write failure was retried after std::thread::yield_now(), so the child ran a core for up to its 4 s bound. - The busy line, a retryable error answer, and a broken pipe whose busy line is still readable are retries, with the daemon's retry_after_ms when it sends one. - Every retry waits through cmux_tui_util::backoff::RetryBudget, the one client retry policy: full-jitter exponential (100 ms doubling to 1 s), the server's retry_after added as a floor, inside the total bound. It is Chromium's net::BackoffEntry with jitter_factor 1; retry-after is added, not max()ed as SetCustomReleaseTime does, so hooks refused together do not come back as one wave. - The 4 s SOCKET_TIMEOUT is unchanged: it is the detached child's liveness bound (the provider's tool call already stopped waiting at the handoff). - The live_prompt strip for an older daemon resends at once, inside the same try: it is not a load retry. - retries_transient_admission_loss_within_one_bounded_receipt_window now runs under SOCKET_TIMEOUT, the child's real bound: its 100 ms bound only held while retries spun.
|
Found 2 test failures on Blacksmith runners: Failures
|
|
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 Shipped in:
|
…der, and a busy daemon never costs an event (red) pa-b2 (#27698), after review of the first fix (R9 R-L5: the hook child still dropped the event when its 4 s bound ran out). - one_agents_hook_burst_uses_one_connection_in_order: 6 hooks of one terminal while the daemon holds the first answer. Today each hook opens its own connection (6) and the held one lands last. - a_hook_event_outlives_a_busy_daemon: the daemon is busy for 4.5 s. Today the child gives up at 4 s and the event is lost. - a_rejected_hook_event_does_not_hold_back_the_next, dropped_connections_are_retried_with_backoff_not_a_spin and a_missing_session_socket_fails_at_once_and_keeps_nothing guard the behavior the queue must keep (they pass today).
…emon never costs a hook event pa-b2 (#27698), after review of the first fix: it still dropped the event when the child's 4 s bound ran out (R9 R-L5), and every hook call still opened its own connection (R-L2). Each hook child now appends its request line to the agent's queue on disk (hook_spool.rs: <runtime dir>/hook-spool/<socket>.<terminal>.jsonl, 0600). The child that takes the queue's drain lock (an flock, released when the process exits) sends the queue in order over one connection and waits for each receipt; the others return at once. So: - One agent's burst of hooks uses one daemon connection, in provider order. - A line leaves the queue only on a receipt or a durable rejection. A busy line, a retryable answer or a dropped connection is retried with RetryBudget (full jitter, retry_after_ms as a floor) and no deadline: the daemon's answer, or its socket going away, is the signal (R-L5). A gone session keeps the lines queued for the agent's next hook; the daemon answers a resend from its idempotency receipt. - The provider still waits only until its line is written or queued behind lines a sender works on (HANDOFF_WAIT bounds that wait). - SOCKET_TIMEOUT (4 s) is gone; the inbox keeps its own 1.5 s single try and now names a busy refusal instead of "mismatched request id". - RetryBudget gets RetryBudget::new (no deadline) and reset(). - a_retryable_failure_backs_off_instead_of_spinning tested retry_until, which is gone; dropped_connections_are_retried_with_backoff_not_a_spin covers the same property end to end.
|
Owner note (plans/cmux-next/OWNERS.md): this PR changes the agent hook helper (cmux-tui/crates/cmux-tui/src/bin/cmux-tui-hook*) and cmux-tui-util's backoff. The daemon side (cmux-tui-core, owner PL-daemon) does not change here. The next pa-b2 PR adds retry_after_ms to the daemon's busy line in cmux-tui-core/src/server/listen.rs, on top of #27719 by @austinywang. PL-daemon: please read. |
…d and deleted by the next hook; an orphaned queue is sent (red) pa-b2 (#27698), lead decision 3 on #28041: a queue must not stay on disk forever with nobody to see it (R6 owned lifecycle, R-L5 visible loss). - an_ended_sessions_queue_is_dropped_counted_and_deleted_by_the_next_hook: a queue of a session whose socket is gone is deleted by the next hook child of another agent, its 2 events counted in hook-spool/ended-session-events; a sent queue leaves no files. - an_orphaned_queue_of_the_live_session_is_sent_by_any_agents_next_hook. - a_sender_drops_and_counts_its_queue_when_the_session_ends: the socket goes away while the sender waits; the queue is dropped and counted.
… and deleted by the next hook; orphaned queues are sent pa-b2 (#27698), lead decision 3 on #28041 (R6 owned lifecycle, R-L5 visible loss): a queue no sender works on must not stay on disk with nobody to see it. - A sender that reaches the end of its queue deletes the queue and drain files (under both locks). A child that opened a path before the delete finds, once it holds the lock, that the path names another file or none, and opens it again (inode check), so no event goes to an unlinked file. - After its own queue, each hook child looks at the other queues beside the socket: one of its own session that no child sends is sent; one whose session socket is gone is deleted. No timer decides either. - The definitive "session gone" is the daemon's: it removes its socket file only when its session ends. A sender that finds the socket gone drops the rest of its queue; a refused connection with the socket still there keeps the lines for the next hook (a daemon that stopped without ending its session starts again on the same socket). - Dropped events are added to hook-spool/ended-session-events, and server-stats reports the count under include ["hook_queue"] (diagnostics::HookQueueSnapshot). The daemon learns its socket when a server attaches the session (ConnectionStats::note_socket). - server_stats_include_reports_hook_events_dropped_with_their_session is a new surface's test (no earlier behavior to be red).
|
Base finding (does not block): hosted |
|
PL-daemon (owner, plans/cmux-next/OWNERS.md): head 54003d8 now also changes cmux-tui-core. It adds ConnectionStats::note_socket, which records the socket a server attaches the session to (server/restoring.rs), and an optional server-stats section, hook_queue (diagnostics/hook_queue.rs). Nothing on the request path changes. |
…s.md; bindings regenerated pa-b2 (#28041), lead: the schema source gains the optional server-stats section hook_queue {ended_session_events}. The bindings come from cmux-tui/bindings/codegen/generate.py --write. spec/api-compat.surface.json is api-compat-check --write's snapshot (a cargo binary; agents do not run cargo on this VM). Its two new rows follow coverage.rs surface_from_sdk_schema for an optional object with one required uint64, as the write_path rows do; the PR's cmux-tui-spec job (api-compat-check) compares it with the generator's output.
…er sessions' queues are left alone, a queued event releases the provider, no queue in a shared directory or through a symlink, no orphan in the delete race (red) pa-b2 (#28041), from the review of 54003d8/e8d0e3e76099: - The daemon removes its socket on every owner stop (release_ownership: upgrades and restarts included), and a crashed one leaves it. Neither is a definitive "session gone". a_stopped_daemon_keeps_the_queue_for_its_next_owner, another_sessions_queue_is_left_to_its_session and a_missing_session_socket_fails_at_once_and_keeps_the_event replace the two tests that dropped a queue when its socket was gone. - a_queued_event_releases_the_provider_at_once: a daemon that closes unread (broken pipe) held the provider for HANDOFF_WAIT. - a_shared_socket_directory_gets_no_queue_and_the_event_still_goes and a_planted_symlink_is_not_followed: the queue went into the socket's parent with no ownership check and followed symlinks. - a_hook_that_queues_while_the_queue_is_deleted_still_gets_sent: the queue file was unlinked before the drain lock; hook_spool gets a cfg(test) seam between the two unlinks.
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. |
Fleet red at 6012bb4 (the merge with feat-cmux-next 17368d2): classification
The other steps in fb8745cd ran: fmt Panic ratchet at 6012bb4 (PR CI "clippy (changed cmux-tui packages)", job 124149872633, pass): cmux-tui |
|
Review (independent review subagent, Claude Opus 5.5): SHIP at 6012bb4 FindingsNo blocking findings.
checks:
|
|
Austin's-day A/B for #28041 (harness owner pa-d). On this load, #28041 does not change refused connections, hook latency or CLI latency. Hook CPU p99 is 0.12 ms lower (0.8 %).
acpmux on the head: in every head run, 25 chat opens failed with "agent_start did not finish within 90s". The base had none of these; it failed the same opens with the 10 s host-start time-out instead. The failure share does not change, so these opens fail either way: on the head they wait 90 s instead of 10 s before they fail. I did not find a link from this PR's code (hook path, daemon restoring park) to acpmux agent start. The pa-b10 owner and the #28041 author should check it. acpmux RSS growth is also higher on the head. Who fills the 64 connections, from these runs' process samples (every 15 s):
Harness limits in these runs: aa7c09e has defects that the #28077 review found later. Both arms have them equally.
Leases (round, position): base r1 1 slot-cmux24-869a37ac787a, head r1 2 slot-cmux24-6a3805f8fb87, head r2 1 slot-cmux24-10ff08fc4b52, base r2 2 slot-cmux24-558f84ef58bf, base r3 1 slot-cmux24-756dcede4e56, head r3 2 slot-cmux24-b888133cb935, head r4 1 slot-cmux24-1b0c309f2ad5, base r4 2 slot-cmux24-274798c19f36, base r5 1 slot-cmux24-52f753fd4de2, head r5 2 slot-cmux24-f4964fd29fa7. The full results are on cmux-orchestrator-1 at /work/tmp/pa-d/ab-28041 (summary-reviewed.txt/json). |
Red checks on 6012bb4: classification (after the SHIP at this head)
Pending, not judged: cmux-next fast tier, cmux-next swift test. |
|
Correction and the per-run acpmux split (harness owner pa-d; the #28041 author asked for it). My comment above says "The base had none of these" about the 90 s agent_start time-outs. That is wrong: base round 5 had 25 of them. The pattern in every run is the same:
So the first failing wave is more often a 90 s agent_start hang on the head (5 of 5 against 1 of 5). The share of failed opens does not change. With 5 runs per arm, "5 of 5 against 1 of 5" is a signal, not a proof. The rows count The agent CLI rate is assumed, not from Austin's data: one |
acpmux in the Austin's-day A/B: no link to this PR's code found (code check, pa-b2-fix)pa-d's per-run split (#28041 (comment)) shows that the head does not add failed opens: the share is the same in both arms. The difference is in one failing wave per run. On the head it hangs at the 90 s
So I found no mechanism by which this diff turns a 10 s host-start failure into a 90 s Not done: I did not run acpmux under the harness load with and without this PR. That is pa-d's A/B; this comment is a code check only. |
acpmux 90 s hang: what the first wave waits on (measured, pa-b2-fix)Measured: the time of the first Chief wave goes into the fake agent's answer to Source: the per-session event logs of acpmux ( Correction (pa-b2-fix): I did this during that run's exclusive lease (about 16:31-16:34Z). I connected 6 times over ssh, read files, copied a small Python script to
From the B2 runs (
What is not proven: the B2 runs did not keep acpmux's session event logs (the lease home was deleted). So I cannot show that their 90 s is also spent in |
|
#28041 extension: 10 more paired ABBA rounds (cmux-ad order; harness owner pa-d). The 90 s-hang signal does not hold. Over all 15 rounds the head is no different from the base on any metric, and the 90 s agent_start hang is not tied to the PR.
The 90 s agent_start hang, per round (chat opens that hit the 90 s limit):
All metrics over the 15 rounds (paired t-interval, 95 %): no difference on every metric except one.
acpmux logs: each extension run kept acpmux's |
|
|
|
Red checks on 6012bb4, 21:2xZ (autoland: "its own red: pr-perf-section-check (and 5 more red)")
|
cmux-tui/bindings/codegen/generate.py --write after the merge 018b4e0: feat-cmux-next's sdk-schema.json change (#27752, cursor on cloud-inbox-list) and this PR's hook_queue section both feed the bindings, so the merged schema makes new generated files. generate.py --check and sync-resource-api.py --check are clean afterwards.
|
Review (independent review subagent, Claude Opus 5.5): SHIP at 05f6002 Delta review from 6012bb4 (SHIP, comment 6527469127). I read git objects and ran only the two read-only codegen checks. I did not compile or run tests.
|
Rust green at 05f6002: classification (job 4b3b59ac4c067e7d68122da7, hq run 41131632629,
|
|
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Part of #27698 (pa-b2; rows 1-2 of the B9 limits audit, and the "one connection per agent" part of row 1).
Summary
This is a correctness fix: no hook event is lost, and every wait is bounded or ends on a signal. It claims no load or CPU gain. The Austin's-day A/B (below) shows no measured difference in refused connections, hook latency, total hook CPU or CLI latency. In that scenario
cmuxCLI processes held the 64 connections, not hook helpers.On Austin's nightly-next, the session daemon refused 55,162 connections in about 2.5 hours. The hook child lost events when that happened:
type: "refused",server.busy) and closes. The hook child took that line for "an invalid response envelope" and dropped the hook event.std::thread::yield_now()with no sleep. It ran a core for its whole 4 s bound, then gave up and dropped the event.Now:
<runtime dir>/hook-spool/<socket>.<terminal>.jsonl, mode 0600 (hook_spool.rs). The child that takes the queue's drain lock sends the queue in provider order over one connection, and waits for each receipt. The drain lock is anflockand is released when the process exits. All other children return at once.RetryBudget, with no deadline. The stop signals are the daemon's answer, or its socket going away (R-L5). If the session is gone, the lines stay queued for the agent's next hook, and the daemon answers a resend from its idempotency receipt.cmux session NAME reset-state: it removes the session's saved state, then deletes the session's queues and counts their events.server-statswithinclude: ["hook_queue"]reportsqueued_events(this session's queued lines, so a stuck queue is visible) andreset_dropped_events.hook_helper::resumeinmain.rs), so a restart does not wait for an agent's next hook. Queue file names are digests of the socket name and the terminal id, so two sessions never share a queue.hook-spool/must belong to this user, with no group or other write permission. Files are opened withO_NOFOLLOWand mode 0600. Without a private directory, the child sends its line directly, so a missing queue never costs an event.restoring.rs, outside the slot lock), so a hook that already wrote its line retries it instead of taking the close for a line the daemon never answers.server-statshook_queue.queued_eventscounts it until a daemon answers.hook_queue.undeliverable_events.reset-statedrops the session's queued events, counts them inhook_queue.reset_dropped_events, and printsdropped_hook_events(orhook_queue_error).connections.refused.HANDOFF_WAIT(5 s; 2 s for Codex SessionEnd) bounds that wait as a liveness bound.SOCKET_TIMEOUTis removed.cmux-tui-util/src/backoff.rs,RetryBudget): full-jitter exponential backoff (100 ms doubling to 1 s), with the daemon'sretry_after_msadded as a floor. Two forms:until(deadline)for a caller with a total budget, andnew()for a caller that stops on a signal.cmux-tui-hook.rs, which was 51 lines over its god-file baseline. It now meets the budget, and its baseline row is removed.What is copied from Chromium
RetryBudgetisnet::BackoffEntry(net/base/backoff_entry.cc) withjitter_factor = 1. The delay isinitial * 2^(n-1), clamped to the maximum, and the wait is drawn uniformly from[0, delay]. Two changes:SetCustomReleaseTime). Clients refused together get the same retry-after, so taking the later of the two sends them back as one wave. Here, the jittered delay is added to retry-after.Not in this PR (next steps of pa-b2)
retry_after_msyet. The hook reads it already. The next PR adds it, computed from the daemon's own state, on top of cmux-tui: agents in terminals hold at most 48 of the daemon's 64 connections #27719 (austinywang), which changes the samelisten.rsrefusal path. The CLI (cli/wire/retry.rs, fixed 200/600/1500 ms) moves toRetryBudgetin the same PR.Performance
No gain is claimed: this is a correctness fix. Austin's-day A/B by pa-d (harness aa7c09e, A/A-valid; 5 ABBA rounds on cmux24; base 3ecd802, head 059ac19, the same product code as 6012bb4 apart from the 2 panic-ratchet lines and the test seam). Lower is better; the delta is head - base with its paired 95 % interval.
cmuxCLI p99agent_starthang (15 rounds, final)Testing
Red tests first, each in its own commit, then each fix. The tests are in
cmux-tui/crates/cmux-tui/src/bin/cmux-tui-hook/journal_append_tests.rsand run against fake daemons:Red 1 (5d1fe1f), fixed by 624c696:
a_refused_append_is_kept_until_the_daemon_admits_ithooks_refused_at_once_do_not_retry_in_lockstep: 16 agents are refused at the same moment. Each is delivered, each comes back no sooner thanretry_after_ms, and the return times spread over at least 25 ms.Red 2 (2bd98d3), fixed by 78a8f22 (head):
one_agents_hook_burst_uses_one_connection_in_order: 6 hooks of one terminal while the daemon holds its first answer. The base opens 6 connections, and the held event lands last.a_hook_event_outlives_a_busy_daemon: the daemon is busy for 4.5 s. The base gives up at 4 s and loses the event.a_rejected_hook_event_does_not_hold_back_the_next,busy_refusals_are_retried_with_backoff_not_a_spin(the daemon's own busy line, with noretry_after_ms: 2 to 12 connections in 400 ms; the base dropped the event with "invalid response envelope"), anda_missing_session_socket_fails_at_once_and_keeps_the_event.backoff::tests(cmux-tui-util): waits double to the cap with retry-after added, a wait past a budget is not taken, no-budget waits reset after a success, and 64 draws spread over the jitter window.Red 3 (6b0fcb1), fixed by 54003d8: the first queue-lifecycle tests. Review then found that "socket gone" is no definitive end, so red 4 replaced the two tests that dropped a queue for that reason.
Red 4 (ab3bdd2), fixed by a63aa53 (head):
a_stopped_daemon_keeps_the_queue_for_its_next_owneranother_sessions_queue_is_left_to_its_sessiona_missing_session_socket_fails_at_once_and_keeps_the_eventa_queued_event_releases_the_provider_at_once(a daemon that closes unread held the provider for HANDOFF_WAIT)a_shared_socket_directory_gets_no_queue_and_the_event_still_goesa_planted_symlink_is_not_followeda_hook_that_queues_while_the_queue_is_deleted_still_gets_sent: the queue was unlinked before its drain lock, which left a late hook's event with no sender. A test-only seam between the two unlinks makes the race reachable.hook_queue::tests(reset-state drops and counts only its own session's queues; a shared directory gets no queue) andserver_stats_include_reports_the_hook_queue. These test a new surface, so there is no earlier behavior that could be red.Fleet steps (
scripts/ci/cmux-tui-rust-check.sh, throughproof-step.py):tempfilein cmux-tui-core tests, 2 unused qualifications. 8536eab2d835b33f390c1367. Fixed in a63aa53Hosted focused runs (
cmux-tui.yml):journal_appendjournal_append/backoff::teststest (linux)success forbackoff::testsjournal_appendhook_helper/backofftest (linux)success, runs 41016487955 / 41016490342The hosted
lint (linux)job fails at "rust-panic-ratchet: RED", the same on the red commit. It is a base finding, linked in a PR comment.Compile-check: 5a09468 passed (d485721c2935ef75244f6e94). Head b17d731 (Windows: no queue): compile passed (f2f034b05cb436c64f99e14f). Its green 9ec64cabf25151aa6b905a96: fmt and clippy passed, and every test of this PR passed (41 PASS lines, no FAIL). Its failing tests are the two base reds and three tests that failed in the full run and passed alone, in crates this PR does not change (see the PR comment).
Spec:
sdk-schema.jsonandcommands.md(the sources) gainhook_queue. The bindings come fromcmux-tui/bindings/codegen/generate.py --write.api-compat.surface.jsonis the snapshot of the cargo binaryapi-compat-check --write, which agents do not run on this VM. Its two new rows followcoverage.rsfor an optional object with one required uint64, as thewrite_pathrows do, and the PR'scmux-tui-specjob compares them with the generator's output.P-AUSTIN A/B (15 paired ABBA rounds, final): #28041 (comment). Harness sha 37b2e86 (aa7c09e plus a count of the 90 s hangs, acpmux log copies and round numbers; no file that measures changed, so A/A-valid with aa7c09e: #28077 (comment)). Base 3ecd802, head 059ac19 (later heads add only the test seam, the two panic-ratchet lines and the merge with feat-cmux-next). Result: no difference on any metric, refused per second +0.38 [-1.17, +1.93]. The 90 s
agent_starthang is within noise: head 9 of 15 runs, base 5 of 15; McNemar exact p = 0.29, Fisher exact p = 0.27. It follows the host (cmux24 in both arms; on cmux19 the head never hung). The first 5 rounds (below) were a chance run on one host.First 5 rounds (harness owner pa-d): #28041 (comment). Harness sha aa7c09e (A/A-valid; A/A: #28077 (comment)); summary by the reviewed
summarize.pyat e8349e8. Product measured: 059ac19 against its merge base 3ecd802, 5 ABBA rounds on cmux24, paired 95 % t-interval. Later heads add only the test seam (4f207e2), the reset-state JSON build andsaturating_add(fcacd42), and the merge with feat-cmux-next (6012bb4).agent_starttime-out instead of the 10 s host-start time-out; the failure share does not change), and acpmux RSS growth +68 MB/h [+20, +117]. No link from this PR's code to acpmux agent start is found yet; the pa-b10 owner and this PR's owner check it.cmuxCLI processes (median 62-63 alive, 0 hook helpers), so the hook spool cannot lower the refusals here. So the PR claims no load gain. pa-d's per-run acpmux split (cmux-tui hook: one queue and one connection per agent; a busy daemon never costs a hook event #28041 (comment)): the share of failed chat opens is the same in both arms. In each run one wave fails all 25 opens. On the head that wave hangs at the 90 sagent_startlimit in 5 of 5 runs; on the base this occurs in 1 of 5 runs, and the other base runs fail it at the 10 s host start. The head adds no failures. The code check (cmux-tui hook: one queue and one connection per agent; a busy daemon never costs a hook event #28041 (comment)) found no path from this diff to acpmux: acpmux does not link the changed crates, and its only daemon call (the 2 s launch-credential mint) fails fast with the busy line as it did with the close. The host-start cause is the harness exec's background CPU class (pa-b10's clamp PR).Observed / Not run
prepush-gate.pyreported no new violations. The god-file check passed on every changed Rust file. Red 1 failed on the hosted Linux job for the stated reasons.no_hook_queue_without_file_identity, cfg(not(unix))); no fleet step runs Windows, so only the hosted full run can.-D warningspassed (step 7001ddc5372930e154fcbf5d, hq run 41077277684:clippy pass).test journal_append(step 4e9ad005defdc4122f026c77, hq run 41077610877): nextestSummary [5.288s] 35 tests run: 35 passed, 12698 skipped, includinga_hook_that_queues_while_the_queue_is_deleted_still_gets_sent, which uses the changed seam.test hook(step 8f2e9756ed6e50afdc290998, hq run 41077651029):Summary [6.194s] 183 tests run: 183 passed, 12550 skipped. The crash ratchet's rust cmux-tui unwrap count is 429 again (431 at 059ac19).session_reset.rs:107-108indexing_slicing,hook_spool.rs:105arithmetic_side_effects). They were hidden at 059ac19 because clippy stopped at the baselaunchd_refresh.rs:329error before the ratchet step. fcacd42 removes them; the baseline does not change.-D warningsgreen (cb8a66174e3028b1eacf3a7d, hq run 41080562729);test journal_appendSummary [4.938s] 35 tests run: 35 passed, 12698 skipped(55b90688171d4f99f6a8b4b0);test hookSummary [6.219s] 183 tests run: 183 passed, 12550 skipped(b3d3ee8a01edd54186bf337a);test session_reset_stateSummary [0.129s] 13 tests run: 13 passed, 12720 skipped(ddb6b179959faa5392f960c8).generate.py --check,check-sdk-schema.pyandcheck-resource-api-boundary.pypass).macos-27):test hookSummary [9.719s] 178 tests run: 178 passed, 12741 skipped(7814e05ee5935e539716865e, aws-m4pro-3);test session_reset_stateSummary [0.682s] 13 tests run: 13 passed, 12906 skipped(c44a87239473e65bab5e1239, aws-m4pro-2); fmt, clippy andtest journal_append(fb8745cdbcf3231af7557c1d, aws-m4pro-4): fmt pass, testsSummary [5.250s] 35 tests run: 35 passed, 12884 skipped(witha_hook_that_queues_while_the_queue_is_deleted_still_gets_sent), clippy red only on the base findingacpmux/tests/daemon_memory.rs:82start_logged is never used(its only caller is#[cfg(target_os = "linux")]; from base Avoid duplicate peer snapshot size serialization (takeover of #27010) #27991 by the merge; classified in comment 6527367112)..github/scripts/cmux-tui-clippy-changed.py --panic-ratchetas a fleet step ("invalid ci-step: script is not on the ci-step allowlist"). The PR's own CI "clippy (changed cmux-tui packages)" at 6012bb4 (job 124149872633, pass) ran it: cmux-tuiindexing_slicing861 = baseline 861,arithmetic_side_effects1188 = baseline 1188 (863 and 1189 before fcacd42). It warnsacpmux: clippy::arithmetic_side_effects 1433 > baseline 1430(warning level; acpmux is not in this PR; base, by the merge).Changelog
Fixed: Agent hook events are no longer lost when the cmux NEXT session is busy or restarting; a hook now waits for a busy session with backoff, and an event that cannot be sent is counted in
server-stats.