Skip to content

cmux-app-ffi links the host budget C ABI; dispatch pressure flags read worst first (step A of the host pressure FFI move) - #31937

Open
lawrencecchen wants to merge 13 commits into
feat-cmux-nextfrom
rust-migration/host-pressure-ffi-a
Open

lawrencecchen wants to merge 13 commits into
feat-cmux-nextfrom
rust-migration/host-pressure-ffi-a

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Step A of the two-step FFI move of the app's host pressure copy (backlog A10). The host CPU/RAM budget crate from #31799 (cmux-host-budget, which acpmux's daemon already uses) is linked into cmux-app-ffi, so the next CCmuxAppFFI release carries its C ABI. No Swift change and no behavior change: nothing in the app calls the new symbols until step B.

Check the app FFI pin: expected, step A of a two-step FFI move.

Takes back #28790: #28790 reverted one entry of headers_in in scripts/cmux-next/build-app-ffi.sh (the chat index mirror header, which had landed without its release and pin). This PR does not add that entry back: it adds a different header, cmux-host-budget/include/cmux_host_budget_ffi.h, as the next entry of the same list, and lands it by the two-step FFI order (step A here, then the bot's release and re-pin, then step B), which is the order #28790 asked for.

What changes

  • cmux-app-ffi depends on cmux-host-budget with default-features = false (no tokio; its Cargo.lock gains no tokio) and re-exports its C ABI as host_budget, as it does the palette ranker.
  • scripts/cmux-next/build-app-ffi.sh ships cmux-tui/crates/cmux-host-budget/include/cmux_host_budget_ffi.h as the module CCmuxHostBudgetFFI; its cmux_* functions join the export list.
  • .github/workflows/app-ffi-release.yml: cmux-tui/crates/cmux-host-budget/** joins the push paths. The crate is now an FFI input (check-app-ffi-pin.sh --list-inputs lists it), and without the path a change to it would publish no release. scripts/cmux-next/tests/app-ffi-release-paths.test.sh passes. This is the only workflow change; no step, job or trigger changes.
  • The fix the cmux-host-budget: the host CPU/RAM budget in one Rust crate, with the app's level rules and their C ABI (no FFI input yet) #31799 review asked for before any caller: cmux_host_budget_with_pressure_json now takes the dispatch source's DISPATCH_MEMORYPRESSURE_* flags as they come and reads them worst first (4 critical, then 2 warn, then 1 normal, else unknown), as the Swift monitor (HostPressureMonitor.swift) does. One difference from Swift stays: an event with none of the three flags reads unknown here and .normal in Swift. That case cannot happen, because the source's event mask is [.normal, .warning, .critical]; step B lists it with the other differences. Before, it read one exact level, so a combined event of 6 read "unknown" and dropped the memory reason. The sysctl mapping in evaluate (pressure_word) is unchanged, so acpmux's verdicts are the same.
  • No dirs in the crate: dirs brings option-ext (MPL-2.0) into the app library, and the app crate license gate does not allow MPL-2.0. src/home.rs keeps the rule of dirs::home_dir (dirs-sys 0.5): first $HOME when it is set and not empty; else the passwd entry of the real user (getuid, getpwuid_r, a buffer of _SC_GETPW_R_SIZE_MAX bytes or 512, no retry); else none. Android, iOS and Emscripten read no passwd entry. home_tests.rs tests a set HOME, an unset HOME and an empty HOME. cmux-app-ffi/Cargo.lock loses dirs, dirs-sys, option-ext and the crates they brought in.
  • scripts/cmux-next/check_app_crate_licenses.py names cmux-host-budget as a first-party GPL crate of the app closure, so the real gate does not report it. The gate also reports cmux-motion. That is a base finding, and the follow-up PR fixes it.
  • The async meter tests are behind the tokio feature, so the crate's tests also build without default features (the configuration cmux-app-ffi links).

Step B, after the re-pin is on feat: CmuxNextHostPressure calls this ABI and its Swift formula, sampler, verdict init, with(pressure:) and tracker are deleted; Swift keeps the dispatch source, the 15 s timer, the daemon read, the last verdict and the views. Step B lists the verdict differences between the Swift copy and the daemon's code.

Risk: high (touches app-ffi-release.yml). Lands on an independent Review (<reviewer>): SHIP at <head> receipt.

Changelog

none

Observed / Not run

Observed at the head 515c0b9. This is my plain merge of feat-cmux-next. It brings in #31927 (the hover C ABI in cmux-app-ffi) and #32374 (the host pressure warning is off by default, with a palette toggle). The only conflict was the module doc in cmux-app-ffi/src/lib.rs, and I kept both sides. The Swift files are the same as on feat:

  • Panic ratchet 34d49d140856819bc09dfb75 and clippy 47247376426894db2734ca75: PENDING.

At 12232b6 these passed: panic ceedc091d22484e704d9e818 and clippy 50ecb9b70b3061cb96ea16c4. The PR comment issuecomment-6581650029 classifies the two red checks at that head: "Check the app FFI pin" is the expected step A red, and the daemon test is a load timeout in SnapshotSessionBarrierTests.

Observed at the head 12232b6. This is my plain merge of feat-cmux-next. It brings in #32282, the fix for the read_paths.rs clippy base red, and cmux-cloud-start-core, which joins the app FFI:

  • Panic ratchet ceedc091d22484e704d9e818 and clippy 50ecb9b70b3061cb96ea16c4: PENDING.
  • Lockfiles: the cmux-tui/crates/cmux-app-ffi PR check at this head and the fleet clippy, both with --locked.

At bf3bd79 (cmux-bot's merge; an independent SHIP was given there), clippy 6ca0c072d77b9feff4d3504a was red only on the base red in cmux-tui-core/src/mux/tests/read_paths.rs (lines 201, 244, 249 and 237). #32177 added it, and #32282 fixes it. The PR comment classifies it.

Observed at 3aa5af9 (the PR's own last commit; an independent SHIP was given there):

Observed earlier (fleet, Linux), for the change that has not changed since:

Review: independent SHIP at bda755a (the bot's merge of feat a7f48bb). cmux-bot merged feat again at 09:56Z (head 5937437, feat 7ea60b1); neither merge changes this PR's files, and the head gets its own review receipt. Its non-blocking notes go to step B so that this head stays the reviewed one: the pressure_word doc still names the dispatch flags, and with --no-default-features meter_tests.rs imports incident but does not use it (a warning, not an error).

The configuration the app links (cmux-host-budget without default features, inside cmux-app-ffi):

  • The PR check cmux-tui/crates/cmux-app-ffi (workflow "rust workspaces", run 41416238787, at bda755a, Linux) ran cargo clippy --locked --workspace --all-targets -- -D warnings and cargo test --locked --workspace in cmux-app-ffi. It compiled cmux-host-budget with default features off, and both passed.
  • macOS compile and the C ABI tests of the crate: test ffi::tests --os macos, job 3a62fddc76e968d8a2aa2ca3 on aws-m4pro-3: passed.

Not run:

  • The release recipe itself (scripts/cmux-next/build-app-ffi.sh: the release slices, the prelink with the export list, xcodebuild -create-xcframework). The fleet refuses it: the script is not on the controller's ci-step allowlist ("invalid ci-step: script is not on the ci-step allowlist"). app-ffi-release.yml runs it after landing. Anything in Swift.

The review of #31799 found that cmux_host_budget_with_pressure_json reads
its argument as one level (1, 2 or 4) and anything else as unknown. The
app's dispatch source gives bit flags, and the Swift monitor reads them
worst first: an event of 6 (warn and critical) is critical. Passed raw,
a critical event would read unknown and drop the memory reason.

These tests ask for the Swift reading (6 and 7 critical, 3 warn, 0 and
8 unknown) through the JSON call and the C ABI. Red step: they fail on
the current exact-level mapping. The async meter tests now build only
with the `tokio` feature, so the crate's tests also run with
--no-default-features (the configuration cmux-app-ffi links).
Step A of the two-step FFI move of the app's host pressure copy
(CmuxNextHostPressure). No Swift change: the app keeps its Swift copy
until the re-pin lands and step B calls this ABI.

- cmux-app-ffi depends on cmux-host-budget without its `tokio` feature
  and re-exports its C ABI as `host_budget` (as it does the palette
  ranker); its Cargo.lock gains no tokio.
- build-app-ffi.sh ships include/cmux_host_budget_ffi.h as the module
  CCmuxHostBudgetFFI.
- app-ffi-release.yml publishes on a change to the crate, which is now
  an FFI input (check-app-ffi-pin.sh --list-inputs lists it;
  app-ffi-release-paths.test.sh: ok).
- cmux_host_budget_with_pressure_json takes the dispatch source's
  flags as they come and reads them worst first (4, then 2, then 1, else
  unknown), as the Swift monitor does: 6 is critical, 3 is warn. The
  sysctl level keeps its exact mapping (pressure_word), so acpmux's
  verdicts do not change.
@lawrencecchen lawrencecchen added the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

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

Review 515c0b9: 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=pr31937 -f ref=rust-migration/host-pressure-ffi-a -f platform=macos -f backend_mode=local

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

@blacksmith-sh

blacksmith-sh Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Found 6 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmp3qkr3b6_/summary-missing.json (live):/summary-missing.json (live): View Logs
/tmp/tmpeltkl67p/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

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

@teamleaderleo

Copy link
Copy Markdown
Collaborator

Review (codex gpt-6.1-sol xhigh, next-review): SHIP at 9e29d1c

SHIP at 9e29d1c
Visual verdict: no images; Leo tries the build

No correctness findings. Release-path test, shell checks, and C-header syntax check passed; Rust tests and the macOS xcframework build could not run here.

Follow-ups: none

@teamleaderleo teamleaderleo removed the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@github-actions github-actions Bot added the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator

Review (codex gpt-6-astra high, next-review): SHIP at bda755a

SHIP at bda755a

Visual verdict: unchanged by this diff

Reviewed the FFI, feature gating, lockfile, export packaging, pressure flag mapping, and release paths. app-ffi-release-paths.test.sh passes; Rust tests were unavailable because Cargo is not installed.

Follow-ups: none

@teamleaderleo teamleaderleo removed the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Review (claude-review-subagent): SHIP at bda755a

Checked: the merge leaves the PR paths unchanged; dispatch_pressure_word reads 4, then 2, then 1, like HostPressureMonitor.swift:133 (one difference: an event with no known bit is unknown here and normal in Swift, which cannot happen with that event mask); pressure_word and evaluate are unchanged; both new json tests and the ffi loop fail on the old exact-level mapping. Nothing outside cfg(feature = "tokio") needs tokio; the 10 header functions match ffi.rs and are the only names the export grep picks up, with no collision with the other four headers; the cmux-app-ffi Cargo.lock adds cmux-host-budget, dirs, tracing and their dependencies, and no tokio.
Workflow: one push path is added, with no trigger, permission, step or secret change; app-ffi-release-paths.test.sh is ok; rustfmt --check is clean. The red 'Check the app FFI pin' is this step A's expected red (as with #31925, then #31974) until the re-pin lands. I did not compile or run any tests.

@github-actions github-actions Bot added the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@lawrencecchen lawrencecchen added ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds and removed ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds labels Nov 2, 2026
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 2, 2026 09:56 Inactive
@lawrencecchen lawrencecchen removed the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Nov 2, 2026
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Review (subagent, correctness first): SHIP at 5937437

Checked: the merges bda755a and 5937437 leave the PR's files the same as 9e29d1c (the diff is empty), and the diff from the merge-base 7ea60b1 contains only the 15 PR files. feat a7f48bb..7ea60b1 changes nothing in cmux-host-budget, cmux-app-ffi, build-app-ffi.sh, app-ffi-release.yml or acpmux host_pressure. The newer feat tip f22cb91 (#31945) merges cleanly with git merge-tree. app-ffi-release-paths.test.sh passes and rustfmt --check passes. #28790's chat-mirror entry does not come back, so the Takes back line is true.
The change is correct: the flags are read worst first (4, then 2, then 1, else unknown), the same as HostPressureMonitor.swift, and pressure_word for the sysctl does not change. The 10 header functions equal the 10 no_mangle exports and do not collide with the other headers. The lock has no tokio.
Non-blocking, for step B: check_app_crate_licenses.py FIRST_PARTY_GPL does not list cmux-host-budget (cmux-motion is missing too), and dirs brings option-ext (MPL-2.0) into the app FFI closure. CI runs only the unit tests of that gate, so no check is red; a manual run of the gate would flag both.

@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Classification, added at 515c0b9: clippy 47247376426894db2734ca75 failed only on cmux-tui/crates/cmux-tui-core/src/server/capabilities.rs:324 (unused_qualifications). This is a base red from #32380, in a file this PR does not touch. The SWITCH FRAMES owner is fixing it. The crates of this PR (cmux-host-budget, cmux-app-ffi) are clean in this run.

@teamleaderleo

Copy link
Copy Markdown
Collaborator

Review (codex gpt-6-astra high, next-review): SHIP at d7b04a5

SHIP at d7b04a5

Visual verdict: no images; Leo tries the build

  1. [P2][follow-up] ffi.rs: cmux_host_budget_with_pressure_json changed from a level to bitmask semantics, but the ABI version remains 1. Bump the version so consumers can detect this contract change.

  2. [P2][follow-up] app-ffi-release.yml: the release smoke link and cross-build header parity check omit the new CCmuxHostBudgetFFI header and symbols, so packaging errors in this ABI can pass CI until Swift uses them.

Follow-ups:

  • [P2][follow-up] Bump the host-budget ABI version for the changed pressure argument semantics.
  • [P2][follow-up] Add CCmuxHostBudgetFFI to the release smoke and parity checks.

@teamleaderleo teamleaderleo removed the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@github-actions github-actions Bot added the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator

Review (codex gpt-6-astra high, next-review): SHIP at 74798fc

SHIP at 74798fc
Visual verdict: no images; Leo tries the build

Focused release-path and license tests pass; supplied CI covers compilation and tests. No correctness findings.

Follow-ups: none

@teamleaderleo teamleaderleo removed the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@github-actions github-actions Bot added the risk:high Risk tier (docs/ci/risk-tiers.md) label Nov 2, 2026
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 2, 2026 21:42 Inactive
@teamleaderleo

Copy link
Copy Markdown
Collaborator

Review (codex gpt-6.1-sol xhigh, next-review): SHIP at ec1ad74

SHIP at ec1ad74

Visual verdict: no images; Leo tries the build

Focused workflow, license, release-path, and C-header checks passed. No correctness findings.

Follow-ups:

  • [P2] [follow-up] No after-image artifact was available for this head, so visual comparison remains unverified.

This branch was previously deployed

3 inactive deployments
ci-routing-agent — ec1ad747 Deployed Nov 2, 2026 by github-actions[bot] via cmux-next macOS placement #63817
artifacts — ec1ad747 Deployed Nov 2, 2026 by cmux-bot[bot] via publish tree-addressed cmux-tui #102709
sentry-dsyms — ec1ad747 Deployed Nov 2, 2026 by cmux-bot[bot] via upload cmux-tui dSYMs to Sentry #102709
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants