Skip to content

acpmux: host load sample and a muted host notice for Cloud right-sizing - #30437

Merged
teamleaderleo merged 5 commits into
feat-cmux-nextfrom
lane/acpmux-host-load-notice
Nov 1, 2026
Merged

teamleaderleo merged 5 commits into
feat-cmux-nextfrom
lane/acpmux-host-load-notice

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

What and why

cmux NEXT Cloud machines (Linux VMs running the acpmux daemon) get right-sized automatically by the server (manaflow-ai/cmux-platform). The server takes one load sample a minute by running a command on the machine through the provider's exec. After a resize it tells the chats with one muted line. This PR is the machine side of both.

Leo, 2026-10-31: "we ofc wanted to have the thing be having snapshots of whatever vms to do the right-sizing" and "this goes on automatically right?"

A. acpmux machine load --json (also acpmux host load)

Prints one JSON object with the machine's load now and exits 0. It only reads: it never starts a daemon. If the running daemon doesn't answer within 1.5 s, busy/localTurns are left out. Every field except at is left out when it can't be read. Off Linux it prints at, plus disk on any Unix.

{
  "at": 1793500000000,
  "cpuBusy": 0.62,
  "cpuSomeAvg60": 12.4,
  "memSomeAvg60": 3.1,
  "memFullAvg60": 0.2,
  "memAvailableFraction": 0.18,
  "swapUsedFraction": 0.4,
  "oomKills": 1,
  "diskFreeBytes": 21474836480,
  "diskFreeFraction": 0.31,
  "busy": true,
  "localTurns": 2,
  "heavy": { "kind": "build", "need": { "vcpu": 8, "memGiB": 15 } }
}
  • cpuBusy: two /proc/stat cpu reads 1 s apart (idle = idle + iowait).
  • cpuSomeAvg60, memSomeAvg60, memFullAvg60: PSI avg60 from /proc/pressure/{cpu,memory}.
  • memAvailableFraction, swapUsedFraction: /proc/meminfo. Swap is left out when SwapTotal is 0.
  • oomKills: /proc/vmstat oom_kill (cumulative).
  • diskFreeBytes, diskFreeFraction: statvfs of $HOME (space available to an unprivileged user, over the total).
  • busy, localTurns: daemon status host_pressure.local_turns.
  • heavy: one pass over /proc/*/comm and cmdline (argv[0..3]). The heaviest known build or test tool wins. The table is one declarative const (host_load.rs HEAVY) taken from cmux#26617's sizing model, and counts on top of the session's own 2 GiB / 2 cores: cargo build/clippy and rustc → build 15 GiB / 8 cores (cargo test → test); swift build/swift-frontend → 13 / 4, swift test → 11 / 6; go build/test, make, cmake, ninja, gcc/clang (and cc1/cc1plus) → 8 / 8; bun/npm/pnpm/yarn test, vitest, jest, playwright → test 2 / 6; tsc and vite build → build 2 / 6. A node or bun script counts as its tool (node …/vitest.mjs).

The new /proc parsers sit beside the existing ones in host_pressure_probe.rs and are pure functions tested on literal file text. The classifier is a pure function over (comm, argv).

B. acpmux machine notice --text "…" → muted notice in every live chat

  • New RPC _acpmux/host_notice {text} (server/host_notice.rs). It refuses Web clients, the same way vm_host does. The text is trimmed and must be one line of at most 300 characters. The handler appends the mux record host_notice {text, source: "cloud"} to every session on this daemon that isn't Closed, and returns {"appended": n}.
  • host_notice is added to TRANSCRIPT_MUX_KINDS, so clients attached to the transcript get it. It is also in docs/acpmux-schema.json (muxEventKinds, EventKinds, the record type and the method) and in the protocol IR (spec/acpmux-protocol.json, with the web methods.ts regenerated). It is excluded from peer session forwarding.
  • Webview (direct.ts): a host_notice record with non-empty text becomes the row {id: "host-notice-<seq>", kind: "notice", text}, which NoticeRow draws muted.
  • The CLI talks to the running daemon's socket and never starts a daemon (no daemon means no chats to tell).

Tests (cmux-ci, Linux pool)

  • cargo test --locked -p acpmux --lib -- host_pressure host_load host_notice hub::paging protocol:: help_examples command::tests: 53 passed, 0 failed. Fleet job 87a57c01da760559563011e1. This covers the new parsers, the classifier, the JSON shape, the host_notice journal and transcript test, the paging kinds, the protocol IR being current, and the help examples parsing.
  • cargo clippy --locked -p acpmux --all-targets -- -D warnings: clean. Fleet job dad636f773a4d2591aa2d586.
  • bun test test/agent-pane-host-notice.test.tsx test/agent-pane-policy-unenforced.test.tsx: 5 passed. Fleet job cd3366470d2327dfcdc850a7.

Size: about 700 changed lines, a bit over the ~600 target. Roughly half is tests, schema text and the regenerated protocol files. The two halves share the PR because Cloud's right-sizing loop needs both.

Risk: small and additive. There is a new read-only CLI and a new local-only RPC that appends one record per live chat. No Swift.

Agent session: agent session

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Adds the machine side of cmux Cloud's right-sizing loop: acpmux machine load --json takes one load sample a minute, and acpmux machine notice --text adds one muted line to every live chat after a resize.

Host load

  • machine load --json prints one JSON object with CPU busy share, PSI avg60, available memory, swap, OOM kills, free disk, and the heaviest running build or test; it reads /proc only and never starts a daemon.
  • Fields it can't read are left out; busy/localTurns come from a running daemon if it answers within 1.5 s.
  • The classifier reads comm and argv and counts bun x, bunx, and npx wrappers as the tool they run; a node or bun script counts as its tool.

Host notice

  • machine notice --text appends a host_notice transcript record to every non-closed session on the daemon via the new local-only _acpmux/host_notice RPC.
  • The agent pane draws it as a muted notice row; Web clients and peer forwarding are refused, and the text must be one line of at most 300 characters.
  • A notice that arrives mid-reply ends the current assistant or activity segment, so later lines sit below it.

Written for commit c559cd0. Summary will update on new commits.

View guided diff Turn on auto-fix

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 22 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="webviews/test/agent-pane-host-notice.test.tsx">

<violation number="1" location="webviews/test/agent-pane-host-notice.test.tsx:96">
P3: This test does not verify the muted pane rendering promised by its name. Render the pane and assert the host notice produces the muted notice element, or rename this test to make its reducer-only coverage explicit and add a separate UI assertion.</violation>
</file>

<file name="cmux-tui/crates/acpmux/src/host_load.rs">

<violation number="1" location="cmux-tui/crates/acpmux/src/host_load.rs:190">
P2: The disk sample ignores `ACPMUX_HOME` and stats `$HOME` instead. Use `crate::config::home()` so a custom acpmux state volume reports the disk that actually hosts the daemon's machine data.</violation>
</file>

<file name="cmux-tui/crates/acpmux/src/host_pressure_probe.rs">

<violation number="1" location="cmux-tui/crates/acpmux/src/host_pressure_probe.rs:79">
P2: `map_while` silently truncates at the first malformed CPU counter and still returns a partial sample. Reject the whole aggregate line when any counter cannot be parsed, otherwise a damaged or changed `/proc/stat` line produces a plausible but incorrect `cpuBusy` value.</violation>
</file>

<file name="cmux-tui/crates/acpmux/src/server/host_notice.rs">

<violation number="1" location="cmux-tui/crates/acpmux/src/server/host_notice.rs:46">
P2: `append_all` reports every selected session as appended even when persistence fails, so a notice can appear live but disappear from replay while the caller receives success. Use `append_stored` and count only successful writes.</violation>

<violation number="2" location="cmux-tui/crates/acpmux/src/server/host_notice.rs:52">
P1: This guard does not enforce the method's local-only contract: an authenticated peer can add a notice to every live session on this daemon. Require `Control::Local` so only the Unix socket and LocalApp can invoke it.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

}

pub(super) async fn handle(hub: &Arc<Hub>, conn: &Conn, params: &Value) -> Result<Value, RpcError> {
if super::remote_guard::control_of(conn.origin, conn.auth, params) == Control::Web {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: This guard does not enforce the method's local-only contract: an authenticated peer can add a notice to every live session on this daemon. Require Control::Local so only the Unix socket and LocalApp can invoke it.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At cmux-tui/crates/acpmux/src/server/host_notice.rs, line 52:

<comment>This guard does not enforce the method's local-only contract: an authenticated peer can add a notice to every live session on this daemon. Require `Control::Local` so only the Unix socket and LocalApp can invoke it.</comment>

<file context>
@@ -0,0 +1,81 @@
+}
+
+pub(super) async fn handle(hub: &Arc<Hub>, conn: &Conn, params: &Value) -> Result<Value, RpcError> {
+    if super::remote_guard::control_of(conn.origin, conn.auth, params) == Control::Web {
+        return Err(RpcError::new(-32000, "a host notice is added only from this machine"));
+    }
</file context>

/// `idle` and `iowait`; `guest` and `guest_nice` are already inside `user` and `nice`.
pub fn parse_proc_stat_cpu(text: &str) -> Option<(u64, u64)> {
let line = text.lines().find(|l| l.split_whitespace().next() == Some("cpu"))?;
let n: Vec<u64> = line.split_whitespace().skip(1).map_while(|w| w.parse().ok()).collect();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: map_while silently truncates at the first malformed CPU counter and still returns a partial sample. Reject the whole aggregate line when any counter cannot be parsed, otherwise a damaged or changed /proc/stat line produces a plausible but incorrect cpuBusy value.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At cmux-tui/crates/acpmux/src/host_pressure_probe.rs, line 79:

<comment>`map_while` silently truncates at the first malformed CPU counter and still returns a partial sample. Reject the whole aggregate line when any counter cannot be parsed, otherwise a damaged or changed `/proc/stat` line produces a plausible but incorrect `cpuBusy` value.</comment>

<file context>
@@ -50,6 +50,45 @@ pub fn parse_vmstat_pswpout(text: &str) -> Option<u64> {
+/// `idle` and `iowait`; `guest` and `guest_nice` are already inside `user` and `nice`.
+pub fn parse_proc_stat_cpu(text: &str) -> Option<(u64, u64)> {
+    let line = text.lines().find(|l| l.split_whitespace().next() == Some("cpu"))?;
+    let n: Vec<u64> = line.split_whitespace().skip(1).map_while(|w| w.parse().ok()).collect();
+    let idle = n.get(3)?.saturating_add(n.get(4).copied().unwrap_or(0));
+    let total = n.iter().take(8).fold(0u64, |sum, j| sum.saturating_add(*j));
</file context>
Suggested change
let n: Vec<u64> = line.split_whitespace().skip(1).map_while(|w| w.parse().ok()).collect();
let n: Vec<u64> = line.split_whitespace().skip(1).map(|w| w.parse().ok()).collect::<Option<_>>()?;

Comment thread cmux-tui/crates/acpmux/src/host_load.rs Resolved
Comment on lines +46 to +49
hub.append(s, "mux", KIND, json!({"text": text, "source": "cloud"}));
}
live.len()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: append_all reports every selected session as appended even when persistence fails, so a notice can appear live but disappear from replay while the caller receives success. Use append_stored and count only successful writes.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At cmux-tui/crates/acpmux/src/server/host_notice.rs, line 46:

<comment>`append_all` reports every selected session as appended even when persistence fails, so a notice can appear live but disappear from replay while the caller receives success. Use `append_stored` and count only successful writes.</comment>

<file context>
@@ -0,0 +1,81 @@
+    let live: Vec<_> =
+        hub.sessions().into_iter().filter(|s| s.meta().status != SessionStatus::Closed).collect();
+    for s in &live {
+        hub.append(s, "mux", KIND, json!({"text": text, "source": "cloud"}));
+    }
+    live.len()
</file context>
Suggested change
hub.append(s, "mux", KIND, json!({"text": text, "source": "cloud"}));
}
live.len()
}
live.iter()
.filter(|s| {
hub.append_stored(s, "mux", KIND, json!({"text": text, "source": "cloud"}))
})
.count()

#[cfg(unix)]
fn disk(load: &mut Load) {
use std::os::unix::ffi::OsStrExt;
let Some(home) = std::env::var_os("HOME") else { return };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The disk sample ignores ACPMUX_HOME and stats $HOME instead. Use crate::config::home() so a custom acpmux state volume reports the disk that actually hosts the daemon's machine data.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At cmux-tui/crates/acpmux/src/host_load.rs, line 190:

<comment>The disk sample ignores `ACPMUX_HOME` and stats `$HOME` instead. Use `crate::config::home()` so a custom acpmux state volume reports the disk that actually hosts the daemon's machine data.</comment>

<file context>
@@ -0,0 +1,327 @@
+#[cfg(unix)]
+fn disk(load: &mut Load) {
+    use std::os::unix::ffi::OsStrExt;
+    let Some(home) = std::env::var_os("HOME") else { return };
+    let Ok(path) = std::ffi::CString::new(home.as_bytes()) else { return };
+    // SAFETY: an all-zero statvfs is a valid value of this plain C struct.
</file context>


const GREW = "Machine grew to 4 vCPU / 8 GiB (it ran out of memory)";

test("a host notice is a muted notice row where acpmux logged it", async () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: This test does not verify the muted pane rendering promised by its name. Render the pane and assert the host notice produces the muted notice element, or rename this test to make its reducer-only coverage explicit and add a separate UI assertion.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/test/agent-pane-host-notice.test.tsx, line 96:

<comment>This test does not verify the muted pane rendering promised by its name. Render the pane and assert the host notice produces the muted notice element, or rename this test to make its reducer-only coverage explicit and add a separate UI assertion.</comment>

<file context>
@@ -0,0 +1,123 @@
+
+const GREW = "Machine grew to 4 vCPU / 8 GiB (it ran out of memory)";
+
+test("a host notice is a muted notice row where acpmux logged it", async () => {
+  const daemon = fakeDaemon(
+    record([
</file context>

@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Nov 1, 2026
@teamleaderleo
teamleaderleo force-pushed the lane/acpmux-host-load-notice branch from 47d10bd to 5b80715 Compare November 1, 2026 07:54
teamleaderleo and others added 5 commits November 1, 2026 01:23
`acpmux machine load --json` (also `host load`) prints one JSON object of this
machine's load now: CPU busy share over 1 s, CPU and memory PSI avg60, available
memory, swap used, OOM kills, free disk under $HOME, whether a turn runs on the
daemon, and a running build or test with what it needs. Reads only; never starts
a daemon; off Linux it prints what it can (always `at`).

`acpmux machine notice --text TEXT` asks the daemon (`_acpmux/host_notice`) to
append a mux `host_notice` record {text, source: "cloud"} to every live chat; it
is a transcript kind and the agent pane draws it as a muted notice row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-3bab30503f0b9a7059e5
…tice splits a reply

Review follow-ups at 5b80715: the two /proc/stat reads now bracket the
one-second sleep alone; `bun x TOOL`, `bunx` and `npx` count as TOOL; a
host notice that comes mid-reply ends the assistant segment, so later text
goes below it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-3bab30503f0b9a7059e5
…activity segment too

Review at 9c4a7c6 (gpt-6.1-sol xhigh): the constant is dead code off Linux,
which -D warnings refuses on macOS; a thought or tool call after a notice
joined the activity row above it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-3bab30503f0b9a7059e5
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol xhigh, router-review): SHIP at c559cd0

Visual verdict: no images supplied (range review); the visual verdict must come separately

  1. [P2] [follow-up] Recognize npm’s rewritten process title — host_load.rs:116. On Linux, running npm test exposes comm = "npm test" and one argv word, which this classifier misses. Tests using node --test also have no recognized child process, so heavy is omitted during active tests. Handle npm’s process title and cover this actual process shape.

  2. [P2] [follow-up] Keep host notices outside background-turn folds — direct.ts:5174. A notice received during a background turn inherits its inBackground tag. If that turn ends quiet, the notice remains hidden inside the collapsed background row. Confirmed using the existing ordering and folding code; exempt external host notices from that grouping.

Protocol generation matched and TypeScript syntax checks passed. Bun and Rust suites were unavailable.

Follow-ups:

  • Recognize npm’s rewritten process title.
  • Keep host notices visible outside background-turn folds.

@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review c559cd0: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr30437 -f ref=lane/acpmux-host-load-notice -f platform=macos -f backend_mode=local

Gallery before/after for c559cd0: 16 states rendered, 0 images differ, 2747 more touched states not rendered. Images are in the run's artifact, not on this public PR; the independent review of this head reads them on its own, so the PR needs no hand-made screenshots of these states.

gh run download 41289308325 -R manaflow-ai/cmux -n gallery-advisory-30437-c559cd0408a7ecba5d8576730afdba2f31263d6a (then read gallery-review.json)

States
State Theme Status Diff Picked by
agent-pane.live-chat-watch/choice-alone Apple System Colors Light unchanged 0% own direct.ts
agent-pane.live-chat-watch/choice-alone Apple System Colors unchanged 0% own direct.ts
agent-pane.live-chat-watch/view-only Apple System Colors Light unchanged 0% own direct.ts
agent-pane.live-chat-watch/view-only Apple System Colors unchanged 0% own direct.ts
agent-pane.live-chat-watch/take-over-refused Apple System Colors Light unchanged 0% own direct.ts
agent-pane.live-chat-watch/take-over-refused Apple System Colors unchanged 0% own direct.ts
agent-pane.approval-edits/single Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.approval-edits/single Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.approval-edits/grouped Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.approval-edits/grouped Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.approval-edits/single-multiedit Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.approval-edits/single-multiedit Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.approval-edits/grouped-multiedit Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.approval-edits/grouped-multiedit Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.approval-edits/single-long Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.approval-edits/single-long Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.approval-edits/grouped-long Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.approval-edits/grouped-long Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.auth-health/signed-in Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.auth-health/signed-in Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.auth-health/signed-out Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.auth-health/signed-out Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.auth-health/expired Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.auth-health/expired Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.auth-health/unknown Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.auth-health/unknown Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.chat-width/standard Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.chat-width/standard Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.chat-width/wide Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.chat-width/wide Apple System Colors unchanged 0% imports direct.ts (1 hops)
agent-pane.chat-width/wide-blocks Apple System Colors Light unchanged 0% imports direct.ts (1 hops)
agent-pane.chat-width/wide-blocks Apple System Colors unchanged 0% imports direct.ts (1 hops)

Pick other states with a Gallery: entry.id, entry.id/variant line in the PR body.

red: cmux-next checks (god files, concurrency, crash safety, l10n); NEW: red check: Daemon capabilities export is fresh (+4 more) is not red on the base ea7f00a; do not merge until green; see lane-rules

Shipped in:

@blacksmith-sh

blacksmith-sh Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Found 18 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmpe6tgi0fr/summary-missing.json (live):/summary-missing.json (live): View Logs
/tmp/tmprk8kd5ue/summary-fail.json (live):/summary-fail.json (live): View Logs
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows/
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows
View Logs
[new_workspaces] the window draws no frames/[new_workspaces] the window draws no frames View Logs
[tabs] debug.tab_switch timed 0 of 40 switches/
[tabs] debug.tab_switch timed 0 of 40 switches
View Logs
[tabs] the window draws no frames/[tabs] the window draws no frames View Logs
main.DeveloperIdAppTests.test_download_prints_the_active_profile_only/
test_download_prints_the_active_profile_only
View Logs
nightly must build and hand off the macOS 26 helper and Xcode 26.5 app before publishin
g/
nightly must build and hand off the macOS 26 helper and Xcode 26.5 app before publishin
g
View Logs
stubs: /System/Library/Frameworks/Security.framework/Versions/A/Security has no stub/
Security has no stub
View Logs
stubs: CoreFoundation.tbd: install-name /System/Library/Frameworks/
CoreFoundation.framework/Versions/A/CoreFoundation, missing 1: ['_CFRetain']/
CoreFoundation, missing 1: ['_CFRetain']
View Logs

...and 8 more test failures. View all on Blacksmith: run 41289308650, run 41289308372

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex, router-review): SHIP at 5b80715

Visual verdict: no images; Leo tries the build

  1. [P2][follow-up] host_load.rs:213-228: the CPU window includes PSI/memory reads and the full /proc process scan before the one-second sleep, so the two /proc/stat samples are more than one second apart and can skew cpuBusy.

  2. [P2][follow-up] host_load.rs:118-122: the classifier comment promises bun x tsc, but the implementation only treats argv[1] as the script, so bun x tsc is missed despite tsc being a known heavy tool.

  3. [P2][follow-up] direct.ts:5074-5079: a notice does not close the active assistant segment. If it arrives mid-stream, later assistant chunks remain in the earlier row, causing the muted notice to render before text generated after the notice.

  4. [P2][follow-up] host_notice.rs:43-48: the live-session snapshot races with session closure; a chat can close after filtering and still receive a host_notice record.

Focused local tests were unavailable because cargo is not installed in the review box.

Follow-ups:

  • [P2][follow-up] Correct the CPU sampling interval.
  • [P2][follow-up] Recognize bun x <tool> invocations.
  • [P2][follow-up] Split active transcript segments around host notices.
  • [P2][follow-up] Recheck session state while appending notices.

@teamleaderleo
teamleaderleo force-pushed the lane/acpmux-host-load-notice branch from 7e4772d to 9c4a7c6 Compare November 1, 2026 09:24
@lawrencecchen

Copy link
Copy Markdown
Contributor

Conflict wave: the branch now has a new history at 9c4a7c6 (rebased onto feat), so my merge 7e4772d is not on it and I stop work on this PR. Your head merges clean with feat-cmux-next.

One clippy red is this PR's own: cmux-tui/crates/acpmux/src/host_load.rs:15 constant CPU_WINDOW is never used on macOS (fleet clippy d949981d1a522a054039a07a). Its only use is in the #[cfg(target_os = "linux")] sampler (line 233 on your head). Suggested fix: put #[cfg(target_os = "linux")] on the constant.

The other errors in that clippy run are base findings on feat, not from this PR: cmux-host/src/identity.rs:61 (enrolled never used, #30362), cmux-host/src/github_repos_tests.rs:130 (very complex type), acpmux/src/agent_tools.rs:590, acpmux/src/cloud_repo_mcp.rs:155, cmux-tui-core/src/cloud_repos/engine.rs:241-242, cloud_repos/runtime.rs:150,279, server/agent_session_folders.rs:281. The lead has given them an owner.

@cursor

cursor Bot commented Nov 1, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot 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.

@lawrencecchen

Copy link
Copy Markdown
Contributor

For Leo (teamleaderleo): this PR made "No process scanning" in cmux-next checks red on feat-cmux-next (host_load.rs heavy_now walks /proc). Fix: #31652. The daemon now names heavy from the shell commands of its agents' tool calls in flight and running background processes (host_pressure.heavy), and machine load reads it there. Field and JSON shape are the same; what counts is now the agents' work, not every process on the machine. Found by agent tip-fix-0200.

lawrencecchen added a commit that referenced this pull request Nov 2, 2026
…nts run, not a /proc scan (#30437) (#31652)

#30437 (60b7d7d) found `heavy` (a running build or test and what it needs) by walking
/proc/*/comm and cmdline (host_load.rs:242 read_dir("/proc")), so "No process scanning" in
cmux-next checks fails on every push. cmux-next never scans processes
(plans/cmux-next/pty-holder.md 4): holders and agents report themselves.

The daemon already sees every command its agents run, so it names `heavy` itself:

- TurnActivity (hub/activity.rs) keeps, for each tool call in flight, the build or test its
  shell command runs (rawInput.command: Claude Code's Bash script or Codex's argv), from the
  call or a later update; it ends with the call.
- Hub::running_heavy_read (hub/processes.rs) reads the commands of the session's running
  background processes from the table it holds.
- daemon status's host_pressure gets `heavy`: the heaviest of those over the daemon's
  sessions (same HEAVY table, same heavier rule, same JSON shape).
- acpmux machine load takes `heavy` from the daemon status it already asks for `busy` and
  `localTurns`; host_load::classify_command reads a shell command's simple commands (cd ... &&,
  NAME=value, nice/env/time wrappers, sh -c SCRIPT) with the existing classify.

Behavior: the field and its values stay. What counts is now a build or test that the
daemon's agents run (in flight or in the background), not one any process on the machine
runs; on a Cloud machine those are the agents' work that right-sizing is for. It is now
also there off Linux, and left out when the daemon does not answer (as busy).

check-no-process-scan.py: red at origin/feat-cmux-next 60e7952 (host_load.rs 1 line,
baseline 0), ok here. Tests: host_load a_shell_command_is_known_from_its_simple_commands,
a_tool_call_runs_its_execute_command, heavy_comes_from_daemon_status; activity
a_build_in_flight_is_heavy_until_it_ends.

Co-authored-by: cmux-bot[bot] <348531757+cmux-bot[bot]@users.noreply.github.com>

This branch was successfully deployed

2 inactive deployments
artifacts — c559cd04 Deployed Nov 1, 2026 by teamleaderleo via publish to R2 #95027
sentry-dsyms — c559cd04 Deployed Nov 1, 2026 by teamleaderleo via upload cmux-tui dSYMs to Sentry #95027
ci-routing-agent — c559cd04 Deployed Nov 1, 2026 by teamleaderleo via cmux-tui tree preflight #95027
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants