Skip to content

cmux NEXT: host pressure indicator and popover in the top row, off by default (part 2) - #24507

Merged
teamleaderleo merged 20 commits into
feat-cmux-nextfrom
app-eff/host-pressure-indicator
Oct 23, 2026
Merged

teamleaderleo merged 20 commits into
feat-cmux-nextfrom
app-eff/host-pressure-indicator

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

cmux NEXT gets a host pressure indicator in the window's top row, after the toolbar band and the incognito badge, with a popover. It's part 2 of cmuxterm-hq#2995, on the monitor that #24298 landed. While the host is normal it shows nothing. At warning or critical it shows a still glyph in the theme's attention color, with no pulse or animation. Clicking it opens a popover with the load against its limit, acpmux's other reasons, its turns and processes, its busiest sessions with Stop (it asks first, and the session stays to resume), and Open Agent Activity.

It ships off by default behind Debug toggle hostPressure.enabled (cmux#22662). Release and RC never activate the tunable store, so they keep it off.

coord-deputy's order, quoted:

"the indicator plus popover, with one 15 s timer that stops when the window is hidden and states its cleanup."
"Split HostBudget.swift for the god-file warning."
"It's a new dev surface, so both ship off by default behind a Debug/Labs toggle (cmux#22662)."
"Codex review at the exact head, green compile, before/after numbers for the timer's cost."

Off means inert

With hostPressure.enabled off (the default), the indicator never creates HostPressureService. That means no monitor, no memory pressure source, no 15 s timer and no sysctl or acpmux reads. The only thing it keeps is an Observation of that one tunable key, which is event-driven and costs no wakeups. HostPressureForce (the hostPressure.force Debug Settings choice for captures) does nothing while the toggle is off.

The timer: stop condition and cleanup

There is one 15 s timer (2 s leeway) for the whole app: HostPressureMonitor's DispatchSourceTimer, not one per window. It runs only while at least one window's indicator is subscribed. An indicator is subscribed while HostPressureSampling.samples is true, meaning the toggle is on and its window can be seen: the app isn't hidden, and the window is isVisible, not minimized, and occlusionState.contains(.visible).

  • Stop condition: an indicator unsubscribes when the toggle goes off, or when its window hides (app hidden or another Space), minimizes, is fully occluded or closes. It hears about these through didChangeOcclusionState, didMiniaturize, didDeminiaturize, willClose, the app's didHide and didUnhide, and the toggle's Observation. When the last indicator unsubscribes, HostPressureService calls HostPressureMonitor.stop(). App quit calls it too.
  • Cleanup: stop() cancels the memory pressure source, the timer and any read in flight, and drops a level change that is still queued. Its window and app notifications (through NotificationCenter.notifications), the toggle Observation and the level Observation are tasks held in HostPressureTasks bags, and each body returns at once if its task was cancelled. A window change, willClose and the nonisolated deinit cancel them on whatever thread they run, and the indicator unsubscribes. Its subscription is a HostPressureSubscription token: if the token is released without cancel() (an indicator freed off the main thread), it unsubscribes on the main actor, so a window never leaves a subscriber that would keep the timer running (aSubscriptionReleasedWithoutCancelStillUnsubscribes).
  • plans/cmux-next/idle-wakeups.md has the same row.
  • HostPressureIndicatorTests covers the stop condition. theToggleShipsOffAndOffNeverMakesTheService checks that the default is off and that, with the toggle off and the window visible, the indicator never creates a service. itSamplesOnlyWhileOnAndVisible checks that with the toggle on and the window visible the monitor runs, that it stops when the window becomes invisible, that it runs again when the window is visible again, and that it stops when the toggle goes off. theGateIsTheToggleAndTheWindow checks the gate's truth table.

Timer cost (one harness, fleet mini)

scripts/cmux-next/bench_idle.py on fleet mini cmux20-bench (M-series, 12 cores, macOS 27, logged-in console). Each run is one tagged DEV build launched clean, with 30 s settle and then 300 s measured per scenario. The app's CPU and wakeups come from proc_pid_rusage at the start and end of each window. Base is c7e203d361 and head is 9a9b4d7dc8, each with one measurement-only commit (an hp-on scenario that sets hostPressure.enabled through debug.tunables; branches app-eff/hpi-bench-base and app-eff/hpi-bench, not for merge). The later review fixes change when a window subscribes and guard the start, not the timer's interval.

build scenario app CPU % app wakeups/s app wakeups/min
base window visible (no indicator code) 0.74 251.8 15,109
base window minimized 0.66 280.1 16,807
head toggle off (default), window visible 1.13 251.6 15,098
head toggle on, window visible 0.65 284.4 17,065
head toggle on, window minimized 0.12 5.1 304

What this shows: off = no change. Head with the toggle off measures 251.6/s against base's 251.8/s in the same scenario. The timer's expected cost when on is 4 wakeups/min (0.07/s), which is far below this harness's run-to-run noise. Base alone moves 28/s between its two scenarios, and almost all of the app's ~250/s idle wakeups come from outside this code (the WakeupLedger shows CEFMessagePump at about 0.7/s and BusyWatchdog at 0.1/s; the rest isn't attributed). So the on-visible (+33/s) and minimized (-275/s) rows are noise around a large baseline, not this timer. The timer's cost and its stop come from the code and its tests instead: one DispatchSourceTimer at 15 s with 2 s leeway, so 4 fires/min while running. itSamplesOnlyWhileOnAndVisible shows isMonitoring going false (timer cancelled) on hide and on toggle-off, and theToggleShipsOffAndOffNeverMakesTheService shows no service, and so no timer, while off.

Size

About 1,050 changed lines, over the ~800 target. The popover, indicator, service and their tests are one feature behind one toggle, and the parts that could stand alone (the HostBudget.swift split and the 21-locale catalog) already landed as #24506 and #24508.

Split into PRs that each land on their own

The Codex review took six passes. They found and fixed these: app hide wasn't observed; an off-main deinit left observers, tasks or a subscriber running (fixed with HostPressureTasks and HostPressureSubscription); a start hop overtaken by the last leave still started the timer (fixed with HostPressureMonitor.start(while:), which checks on the monitor actor before it builds the timer, so this PR touches the part-1 library by 5 lines); a callback queued before cancellation could still resubscribe; a newly shown indicator didn't get laid out; and a forced level's sample sessions showed a Stop that did nothing (now hidden). The tests await the monitor's own isRunning (aStartOvertakenByTheLastLeaveStartsNothing, aStartNoLongerWantedStartsNothing, windowAndAppNotificationsStartAndStopSampling with occlusion, hide, unhide and close posted to an injected center). This PR also fixes a compiler crash on the branch ("failed to produce diagnostic" at HostPressureService.swift:53). The acpmux reader is now a plain closure instead of Optional.map returning a closure.

Observed / Not run

  • Ran: prepush-gate.py (no new violations), cmux-ci compile-check --app and the HostPressureIndicatorTests,HostPressureMonitorTests,HostPressureTrackerTests suites on the fleet at the head (results in comments), and the idle bench above.
  • Not run: a capture of the popover in this description. The host-pressure tour (scripts/cmux-next/media/tours/host-pressure.json) now turns the toggle on first.

No capture: a Debug-only surface that is off by default (hostPressure.enabled); the host-pressure tour drives it for design review.

Takes back #24298: only its plans/cmux-next/idle-wakeups.md row, which part 1 wrote and this part 2 extends with the toggle and window stop condition, and the 5-line HostPressureMonitor.start(while:) guard; part 1's behaviour is otherwise unchanged.

Fast gates note: its Sidebar-Look finding names 163 CmuxNextSidebar/Views files this PR never touches. The job checks out at --depth=2, so the head commit's parent is missing, and git diff-tree --root lists the whole tree as that one commit's change. It's a shallow-checkout artifact of the gate, not this diff.

Leo-ask: ask-427cc7d8f5

Changelog

none (Debug-only, off by default)

Agent session: cosmic-gray

🤖 Generated with Claude Code

teamleaderleo and others added 15 commits October 22, 2026 00:46
A CmuxNextHostPressure package: the host-budget contract's formula and
override file, acpmux's `host_pressure` verdict (else the same formula
on this Mac's own numbers), and a tracker that turns verdicts into a
normal / warning / critical level with hysteresis. Memory pressure comes
from DispatchSource.makeMemoryPressureSource; load, swap and acpmux are
read on one 15 s timer off the main thread. stop() cancels the source,
the timer and any read in flight. No UI yet (the indicator is the next PR).

Refs manaflow-ai/cmuxterm-hq#2995

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1628e-a7d3-7161-ae27-95145ca65e93&host=Air-Blue
…h gates

kern.hostname instead of a blocking name lookup, the override file read
lazily inside the actor, an optional acpmux reader instead of an async
default closure, and the 15 s read timer reviewed in idle-wakeups.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1628e-a7d3-7161-ae27-95145ca65e93&host=Air-Blue
over is one phrase per reason (load, memory pressure, available RAM,
swap), load1 and swap_mb_per_min may be null, pressure may be unknown,
and it carries local_turns, background_processes and top for the popover.
The local verdict uses the same phrases and tests (swap strictly over).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1628e-a7d3-7161-ae27-95145ca65e93&host=Air-Blue
Review (codex xhigh) BLOCKs on #24298:
- the local verdict adds acpmux's available-RAM reason
  (kern.memorystatus_level under min_available_ram_fraction);
- memory pressure is judged against the formula's pressure allowance,
  sampled and from events, and a decoded verdict keeps acpmux's;
- start() and stop() each begin a run; a source hop or a main-actor
  delivery queued from an ended run is dropped.
Also: one cached host port instead of a mach_host_self() per read, and
cores "logical" as acpmux names it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1628e-a7d3-7161-ae27-95145ca65e93&host=Air-Blue
Review (codex xhigh) BLOCKs on #24298: min_available_ram_fraction takes
[0, 1] (0 turns the RAM reason off), and hosts are keyed by the trimmed,
lowercased short name as acpmux's host_name() does. The CPU reason names
the core kind (P-cores, else cores) as acpmux does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1628e-a7d3-7161-ae27-95145ca65e93&host=Air-Blue
…s it

vm_kernel_page_size is shared mutable state to Swift 6 (the fast tier's
test build failed); the swap counter uses getpagesize(). CmuxNextApp
depends on CmuxNextHostPressure (its indicator comes next), so the app
compile covers it and the canary list needs no entry; the generated
target graph is left to the base autofix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1628e-a7d3-7161-ae27-95145ca65e93&host=Air-Blue
The host-budget contract's fix (deputy-2): on M5 and M6, hw.perflevel0 is
only the Super tier, so cosmic-gray (Super 5 + Performance 10) read 5
cores and was always over. Performance cores are now the sum of
hw.perflevelN.physicalcpu for every level not named Efficiency, else
hw.physicalcpu. Fixtures: cosmic-gray 15, air-blue 4, cmux16 6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1628e-a7d3-7161-ae27-95145ca65e93&host=Air-Blue
…d of blocking

The fast tier refused DispatchSemaphore.wait in an async test. The monitor
takes its main-actor hop as an injectable Delivery (a Task hop by
default); the test holds the queued change, stops the run, then runs it.
The generated target graph matches the merge base again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1628e-a7d3-7161-ae27-95145ca65e93&host=Air-Blue
A still glyph after the toolbar band and badge (never the sidebar), in the
theme's attention color, shown only at warning or critical. Its popover
shows the load against its limit and acpmux's other reasons, acpmux's
turns and background processes, the busiest sessions with Stop (asked
first; `_acpmux/kill` without purge, so the session resumes), and Open
Agent Activity. Debug Settings > Host Pressure > Force level shows a
level with the cosmic-gray incident's numbers for captures.

The monitor runs while a window's indicator subscribes and stops with the
last window and at quit.

Refs manaflow-ai/cmuxterm-hq#2995

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1628e-a7d3-7161-ae27-95145ca65e93&host=Air-Blue
…ur, no assumeIsolated

debug.host_pressure opens and closes the popover for the host-pressure
tour; the service follows the quit notification as an async sequence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1628e-a7d3-7161-ae27-95145ca65e93&host=Air-Blue
…t-pressure-indicator

# Conflicts:
#	Packages/macOS/CmuxNext/Sources/CmuxNextApp/Settings/DebugSettingsService.swift
…ile its window shows

A Debug Settings toggle, hostPressure.enabled, default off (cmux#22662: a
new dev surface ships off). Off: the indicator never makes the service, so
no monitor, no 15 s timer and no reads. On: each window's indicator
subscribes only while its window can be seen, and unsubscribes when the
toggle goes off or the window hides, minimizes, is fully occluded or
closes; the last unsubscribe stops the app's one monitor and its timer.
Leaving the window and deinit remove the window observers and cancel the
toggle and level observations.

The 21-locale HostPressure.xcstrings moves to its own follow-up PR; the
English text stays as the strings' default values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16162-34d9-7263-ad98-cd9522abca42&host=cosmic-gray
@teamleaderleo teamleaderleo added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 23, 2026
@cursor

cursor Bot commented Oct 23, 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.

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

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

Review 6bddc84: 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=pr24507 -f ref=app-eff/host-pressure-indicator -f platform=macos -f backend_mode=local

red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 166b27f to compare; do not merge until green; see lane-rules

Tour of 6bddc84f33 (run)

The path-selected recorder failed for core-after, core-before; see the run artifact and failed manifests.

Path-selected interactions

Interaction Changed paths
agent-pane Packages/macOS/CmuxNext/Sources/CmuxNextAgentPane/AcpmuxEnvironment\+HostPressure.swift
core Packages/macOS/CmuxNext/Sources/CmuxNextApp/HostPressure/HostPressureIndicatorView\+Debug.swift
Packages/macOS/CmuxNext/Sources/CmuxNextApp/HostPressure/HostPressureIndicatorView.swift
Packages/macOS/CmuxNext/Sources/CmuxNextApp/HostPressure/HostPressurePopover.swift
Packages/macOS/CmuxNext/Sources/CmuxNextApp/HostPressure/HostPressureSampling.swift
Packages/macOS/CmuxNext/Sources/CmuxNextApp/HostPressure/HostPressureService.swift
Packages/macOS/CmuxNext/Sources/CmuxNextApp/HostPressure/HostPressureStrings.swift
Packages/macOS/CmuxNext/Sources/CmuxNextApp/HostPressure/HostPressureTunables.swift
Packages/macOS/CmuxNext/Sources/CmuxNextApp/Settings/DebugSettings.swift
Packages/macOS/CmuxNext/Sources/CmuxNextApp/Settings/DebugSettingsService.swift
Packages/macOS/CmuxNext/Sources/CmuxNextApp/WindowRootView\+TitlebarControls.swift
Packages/macOS/CmuxNext/Sources/CmuxNextApp/WindowRootView.swift
Packages/macOS/CmuxNext/Sources/CmuxNextApp/Windows/WindowController\+Sidebar.swift
Packages/macOS/CmuxNext/Sources/CmuxNextHostPressure/HostPressureMonitor.swift
Packages/macOS/CmuxNext/Tests/CmuxNextAppTests/HostPressureIndicatorTests.swift
Packages/macOS/CmuxNext/Tests/CmuxNextHostPressureTests/HostPressureMonitorTests.swift
host-pressure scripts/cmux\-next/media/tours/host\-pressure.json

agent-pane-before: the media could not be published (refused 3 file(s) that show private names: 24507/6bddc84f/next-agent-pane-before/shots/02-open-agent-chat.png (fleet host name, fleet Mac mini name); 24507/6bddc84f/next-agent-pane-before/shots/03-que)

agent-pane-after: the media could not be published (refused 3 file(s) that show private names: 24507/6bddc84f/next-agent-pane-after/shots/02-open-agent-chat.png (fleet host name, fleet Mac mini name); 24507/6bddc84f/next-agent-pane-after/shots/03-queue)

Core UI (before): FAILED — 16 ok, 3 failed, 1 unavailable

tour

Video (mp4)

# Step Result Command
1 Launch ok
2 New workspace ok cmux workspace new --name Tour
3 Type in the terminal ok cmux workspace name:Tour screen current pane current tab current terminal current write --text "echo hello from the cmux-next tour\r"
4 A command reports progress: tab loading spinner ok cmux workspace name:Tour screen current pane current tab current terminal current write --text "clear; printf '\\033]9;4;3\\007'; sleep 900\r"
5 Split right failed: exited 1 cmux action run splitRight
6 Split down failed: exited 1 cmux action run splitDown
7 New terminal tab failed: exited 1 cmux action run newSurface
8 Browser tab ok cmux tab new-browser --url https://example.com
9 Hide the sidebar ok cmux action run toggleSidebar
10 Show the sidebar ok cmux action run toggleSidebar
11 Notification ok cmux notify --title Tour --body "Hello from CI"
12 Notifications panel ok cmux action run showNotifications
13 Agent chat ok cmux agent new-chat
14 Agent workspace ok cmux workspace new --name Agent
15 Agent starts ok cmux workspace name:Agent screen current pane current tab current terminal current write --text "clear; printf '\\033]7501;state=working\\033\\\\'; sleep 8; printf '\\033]7501;state=done\\033\\\\'; sleep 900\r"
16 An agent works: row working spinner ok cmux workspace new --name Notes
17 The agent finishes: done mark in the spinner's place ok
18 Session tree: keycaps on the first rows ok cmux settings set sidebar.sessionTree true
19 Session tree back off for later tours ok cmux settings set sidebar.sessionTree false
20 Profile menu unavailable: exited 1 (the menu shot needs a screen capture route) cmux action run sidebar.profileMenu

Failed steps:

5. Split right
Split right

6. Split down
Split down

7. New terminal tab
New terminal tab

Screenshots (12)

1. Launch
Launch

2. New workspace
New workspace

3. Type in the terminal
Type in the terminal

4. A command reports progress: tab loading spinner
A command reports progress: tab loading spinner

8. Browser tab
Browser tab

9. Hide the sidebar
Hide the sidebar

11. Notification
Notification

12. Notifications panel
Notifications panel

13. Agent chat
Agent chat

16. An agent works: row working spinner
An agent works: row working spinner

17. The agent finishes: done mark in the spinner's place
The agent finishes: done mark in the spinner's place

18. Session tree: keycaps on the first rows
Session tree: keycaps on the first rows

### Core UI \(after\): FAILED — 16 ok, 3 failed, 1 unavailable

tour

Video (mp4)

# Step Result Command
1 Launch ok
2 New workspace ok cmux workspace new --name Tour
3 Type in the terminal ok cmux workspace name:Tour screen current pane current tab current terminal current write --text "echo hello from the cmux-next tour\r"
4 A command reports progress: tab loading spinner ok cmux workspace name:Tour screen current pane current tab current terminal current write --text "clear; printf '\\033]9;4;3\\007'; sleep 900\r"
5 Split right failed: exited 1 cmux action run splitRight
6 Split down failed: exited 1 cmux action run splitDown
7 New terminal tab failed: exited 1 cmux action run newSurface
8 Browser tab ok cmux tab new-browser --url https://example.com
9 Hide the sidebar ok cmux action run toggleSidebar
10 Show the sidebar ok cmux action run toggleSidebar
11 Notification ok cmux notify --title Tour --body "Hello from CI"
12 Notifications panel ok cmux action run showNotifications
13 Agent chat ok cmux agent new-chat
14 Agent workspace ok cmux workspace new --name Agent
15 Agent starts ok cmux workspace name:Agent screen current pane current tab current terminal current write --text "clear; printf '\\033]7501;state=working\\033\\\\'; sleep 8; printf '\\033]7501;state=done\\033\\\\'; sleep 900\r"
16 An agent works: row working spinner ok cmux workspace new --name Notes
17 The agent finishes: done mark in the spinner's place ok
18 Session tree: keycaps on the first rows ok cmux settings set sidebar.sessionTree true
19 Session tree back off for later tours ok cmux settings set sidebar.sessionTree false
20 Profile menu unavailable: exited 1 (the menu shot needs a screen capture route) cmux action run sidebar.profileMenu

Failed steps:

5. Split right
Split right

6. Split down
Split down

7. New terminal tab
New terminal tab

Screenshots (12)

1. Launch
Launch

2. New workspace
New workspace

3. Type in the terminal
Type in the terminal

4. A command reports progress: tab loading spinner
A command reports progress: tab loading spinner

8. Browser tab
Browser tab

9. Hide the sidebar
Hide the sidebar

11. Notification
Notification

12. Notifications panel
Notifications panel

13. Agent chat
Agent chat

16. An agent works: row working spinner
An agent works: row working spinner

17. The agent finishes: done mark in the spinner's place
The agent finishes: done mark in the spinner's place

18. Session tree: keycaps on the first rows
Session tree: keycaps on the first rows

### Host pressure indicator and popover \(before\): DEGRADED — 1 ok, 8 unavailable

tour

Video (mp4)

# Step Result Command
1 Launch: the indicator ships off (Debug toggle hostPressure.enabled) ok
2 Indicator on: a normal host still shows nothing unavailable: debug.tunables: unknown key (debug.tunables is DEBUG only)
3 Warning: the still gauge after the toolbar band unavailable: debug.tunables: unknown key (debug.tunables is DEBUG only)
4 The warning's popover: the load against its limit, turns, processes and the busiest sessions unavailable: debug.host_pressure: debug.host_pressure: {'code': 'method_not_found', 'data': {'app_cli_path': '/Users/cmux/Library/Developer/Xcode/DerivedData/cmux-ci-media-slot0-base/Build/Products/Debug/cmux DEV ci-media-slot0-base.app/Contents/Resources/bin/cmux', 'method': 'debug.host_pressure'}, 'message': "Unknown method debug.host_pressure. A cmux CLI that is older than this app (or from another cmux app) sends methods this app does not have; this app's CLI is /Users/cmux/Library/Developer/Xcode/Derive
5 Closed unavailable: debug.host_pressure: debug.host_pressure: {'code': 'method_not_found', 'data': {'app_cli_path': '/Users/cmux/Library/Developer/Xcode/DerivedData/cmux-ci-media-slot0-base/Build/Products/Debug/cmux DEV ci-media-slot0-base.app/Contents/Resources/bin/cmux', 'method': 'debug.host_pressure'}, 'message': "Unknown method debug.host_pressure. A cmux CLI that is older than this app (or from another cmux app) sends methods this app does not have; this app's CLI is /Users/cmux/Library/Developer/Xcode/Derive
6 Critical: the triangle, with the cosmic-gray incident's numbers unavailable: debug.tunables: unknown key (debug.tunables is DEBUG only)
7 The critical popover: acpmux's reasons and the busiest sessions with Stop unavailable: debug.host_pressure: debug.host_pressure: {'code': 'method_not_found', 'data': {'app_cli_path': '/Users/cmux/Library/Developer/Xcode/DerivedData/cmux-ci-media-slot0-base/Build/Products/Debug/cmux DEV ci-media-slot0-base.app/Contents/Resources/bin/cmux', 'method': 'debug.host_pressure'}, 'message': "Unknown method debug.host_pressure. A cmux CLI that is older than this app (or from another cmux app) sends methods this app does not have; this app's CLI is /Users/cmux/Library/Developer/Xcode/Derive
8 Back to the host's real level unavailable: debug.tunables: unknown key (debug.tunables is DEBUG only)
9 Indicator off again: no timer, no reads unavailable: debug.tunables: unknown key (debug.tunables is DEBUG only)
Screenshots (5)

1. Launch: the indicator ships off (Debug toggle hostPressure.enabled)
Launch: the indicator ships off (Debug toggle hostPressure.enabled)

3. Warning: the still gauge after the toolbar band
Warning: the still gauge after the toolbar band

4. The warning's popover: the load against its limit, turns, processes and the busiest sessions
The warning's popover: the load against its limit, turns, processes and the busiest sessions

6. Critical: the triangle, with the cosmic-gray incident's numbers
Critical: the triangle, with the cosmic-gray incident's numbers

7. The critical popover: acpmux's reasons and the busiest sessions with Stop
The critical popover: acpmux's reasons and the busiest sessions with Stop

### Host pressure indicator and popover \(after\): PASS — 9 ok

tour

Video (mp4)

# Step Result Command
1 Launch: the indicator ships off (Debug toggle hostPressure.enabled) ok
2 Indicator on: a normal host still shows nothing ok
3 Warning: the still gauge after the toolbar band ok
4 The warning's popover: the load against its limit, turns, processes and the busiest sessions ok
5 Closed ok
6 Critical: the triangle, with the cosmic-gray incident's numbers ok
7 The critical popover: acpmux's reasons and the busiest sessions with Stop ok
8 Back to the host's real level ok
9 Indicator off again: no timer, no reads ok
Screenshots (5)

1. Launch: the indicator ships off (Debug toggle hostPressure.enabled)
Launch: the indicator ships off (Debug toggle hostPressure.enabled)

3. Warning: the still gauge after the toolbar band
Warning: the still gauge after the toolbar band

4. The warning's popover: the load against its limit, turns, processes and the busiest sessions
The warning's popover: the load against its limit, turns, processes and the busiest sessions

6. Critical: the triangle, with the cosmic-gray incident's numbers
Critical: the triangle, with the cosmic-gray incident's numbers

7. The critical popover: acpmux's reasons and the busiest sessions with Stop
The critical popover: acpmux's reasons and the busiest sessions with Stop

Tours are data in scripts/cmux-next/media/tours: add a step or a tour file to show your feature.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by app-efficiency on cosmic-gray · session

@blacksmith-sh

blacksmith-sh Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Found 9 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmpb_r1yu6m/summary-missing.json (live):/summary-missing.json (live): View Logs
/tmp/tmpoo1hj5l3/summary-fail.json (live):/summary-fail.json (live): View Logs
[tabs] debug.tab_switch timed 0 of 40 switches/
[tabs] debug.tab_switch timed 0 of 40 switches
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
[tabs] the window draws no frames/[tabs] the window draws no frames View Logs
test_base_passes (main.NoticesPairTests.test_base_passes)/
test_base_passes (main.NoticesPairTests.test_base_passes)
View Logs
test_targets_outside_the_app_go_to_the_mac_canary (main.SwiftCanaryFleetCoverage.te
st_targets_outside_the_app_go_to_the_mac_canary)/
test_targets_outside_the_app_go_to_the_mac_canary (main.SwiftCanaryFleetCoverage.te
st_targets_outside_the_app_go_to_the_mac_canary)
View Logs
the committed export failed: check-daemon-capabilities-fresh: plans/cmux-next/
daemon-capabilities.json is stale:
View Logs

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

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-99wyb created for this PR by the cmux coordinator.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

rust workspaces / plan (changed Cargo workspaces) is red on 14 of 15 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

…or; app hide stops sampling

From the Codex review of #24507:
- A HostPressureSubscription token holds the window's subscription.
  cancel() ends it at once; released without one (the indicator freed off
  the main thread, where its deinit cannot touch main-actor state) it ends
  on the main actor, so no subscriber is left to keep the timer running.
- The indicator also reconciles on NSApplication didHide / didUnhide.
- The debug RPC passes Double frame values; a forced level's Stop asks
  acpmux nothing (its sessions are samples).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16162-34d9-7263-ad98-cd9522abca42&host=cosmic-gray
From the second Codex pass on #24507: the deinit off the main thread
skipped removing observers and cancelling tasks. The window and app
notifications are now tasks (NotificationCenter.notifications), and they,
the toggle and the level observations live in Sendable task bags that
the nonisolated deinit cancels on whatever thread it runs; willClose
cancels them too. HostPressureSampling is marked @mainactor explicitly
(the target's default already made it so). A test drives the real
occlusion, unhide and close notifications.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16162-34d9-7263-ad98-cd9522abca42&host=cosmic-gray
…essure timer; showing the indicator lays out the top row

From the third Codex pass on #24507:
- Joining and leaving in one main-actor turn queued a start hop and then a
  stop hop, and the start still ran the monitor (timer and first read)
  before the stop. Each start and stop now bumps a generation, and a start
  hop that is no longer current starts nothing.
- The indicator's visibility callback now sets the root's needsLayout
  before laying out, so a newly shown indicator gets its frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16162-34d9-7263-ad98-cd9522abca42&host=cosmic-gray
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next guards / nightly-guards / workflow-guard-tests / release-notary is red on 16 of 18 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next / cmux-next checks (god files, concurrency, crash safety, l10n) › Checks job structure is red on 13 of 14 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next / cmux-next checks (god files, concurrency, crash safety, l10n) › No new SwiftUI (macOS UI is AppKit) is red on 12 of 13 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

From the fourth Codex pass on #24507:
- HostPressureMonitor.start(while:) checks on the actor, right before it
  builds the timer, that its caller still wants it; the service passes a
  lock-held generation that each stop bumps, so a stop overtaking a start
  hop wins.
- Every observation body returns when its task was cancelled, so a
  notification or level value queued before willClose, a window change
  or leave() does nothing.
- The visibility gate also needs the app not hidden (didHide).
- A forced level's sample sessions get no Stop button.
- Tests await the monitor's own isRunning, and drive didHide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16162-34d9-7263-ad98-cd9522abca42&host=cosmic-gray
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next fast gates / fast gates is red on 12 of 14 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol xhigh): SHIP at 6bddc84

Diff-only review (gh pr diff 24507, no checkout) on cmux16, the sixth pass; earlier passes' BLOCKs are fixed (see the description). Its one NOTE is a tour step title that still says "with Stop" for a forced level, which hides Stop; it's left for a follow-up. At this head the fleet ran cmux-ci compile-check --app (passed, job e01cd3d5516370f165afdafb) and HostPressureIndicatorTests,HostPressureMonitorTests,HostPressureTrackerTests (all 3 suites passed).

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Non-green checks at 6bddc84, classified:

  • cmux-next checks: the reds are No new SwiftUI, Script tests, Checks job structure and Daemon capabilities export. All four are red on base feat-cmux-next 1549981 too (run 39956788032).
  • cmux-next swift test: "no Test run with summary line ... tests started and never finished", the same crash pattern as base 1549981 (job 120424728095). The HostPressure suites passed in this run and on the fleet.
  • fast gates / cmux-next fast tier: Sidebar-Look names 163 CmuxNextSidebar/Views files this PR never touches. The same prepush-gate.py --base a30e861 --head <merge> on a full clone reports no new violations, so it's an artifact of the shallow CI checkout.
  • release-notary and Guard status: base reds.
  • risk evidence: the newest run passes after the Takes back #24298 line.

@teamleaderleo
teamleaderleo merged commit cfa4d89 into feat-cmux-next Oct 23, 2026
134 of 143 checks passed
@teamleaderleo
teamleaderleo deleted the app-eff/host-pressure-indicator branch October 23, 2026 13:09
@github-actions

Copy link
Copy Markdown
Contributor

The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/39958936605 at cfa4d89 failed: cmux-next crash ends the app.
Those jobs last passed at c13e800. This pull request is one of 1 merged since: #24507.
If the failure is in your change, fix forward on feat-cmux-next. Pull requests run only the tiers their paths reach (docs/ci/cmux-next-tiers.md); label a batch PR full-ci to run them all before merging.

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

lawrencecchen added a commit that referenced this pull request Nov 4, 2026
…move 11-04)

Prove-or-remove step 3 (deletion-wave-list.md, p12-perf-process). Row p12-18 is the
switch hostPressure that p12-perf-process-103 (a06867b, db70c38) made from the
Debug toggle hostPressure.enabled. No A/B was planned; it has no proof. The host
pressure gauge itself (monitor, service, indicator, popover, banner) came from feat
(#24298, #24507, #24518) and stays.

Removed: the switch json and its generated registry entry, its dogfood-set name, its
feature-switch-table row, HostPressureAndSnapshotFeatureTests (it tested only the two
removed switches) and the switch inputs of HostPressureIndicatorTests. The indicator
reads its Debug toggle again, as before the row and as on feat: enabled and the forced
level are one observation, so turning the toggle on or off applies live; the toggle
help and the host-pressure media tour are back to the toggle.

Default behavior: the switch was off in every channel, so DEV, NIGHTLY and Release do
not change (no gauge, no 15 s host read). It was on in the chrome-parity dogfood set:
a dogfood build now shows no gauge unless a person turns the toggle on, which is feat's
behavior since #32374 (Lawrence 2026-11-02). Red test:
HostPressureDogfoodDefaultTests (previous commit), red on the base, green here (fleet).

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 6bddc84f Deployed Oct 23, 2026 by teamleaderleo via namespace autofix #1915
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.

1 participant