NEXT: accept phone uploads of any size in the mobile host

TE
9d ago
+44-38

Leo's standing order: "Attachments take arbitrarily large files of any type; there is no size cap" (Leo, 2026-10-26: "WHY THE FUCK SHOULD THERE BE A FUCKING SIZE CAP ANYWAYS ... I ALREADY SAID WE NEED ARBITARRILY LARGE FILES OF ANY TYPE").

Lands with #26959 (order: this PR first, then #26959)

This PR is the Mac (host) half. #26959 removes the iPhone client's caps: LinkUpload.swift (100 MiB maxBytes, refused before the channel opens), ChatComposer.swift readFiles and TerminalComposer.swift loadFiles (the same cap at pick time). Until #26959 lands, a real phone upload over 100 MiB can't reach this host code. Order: this PR lands first, because alone it only accepts more. #26959 alone would send files over 100 MiB to a host that still answers too_large. The proof for the pair is an iPhone-to-host upload over 100 MiB on the simulator, run on the fleet.

The cap

cmux-next-ios/rust/crates/cmux-mobile-host/src/services.rs:1283 (base 3a7653b054e), in receive_upload for the hostd upload service that the iPhone chat and terminal composers use to put an attachment into <cwd>/.cmux/attachments/phone-<session>/:

if size > config.upload_max_bytes {
    return Err(Refusal::new("too_large", format!("the file is larger than {} MB", ...)));
}

upload_max_bytes came from CMUX_MOBILE_UPLOAD_MAX_BYTES, default DEFAULT_UPLOAD_MAX_BYTES = 100 MiB (config.rs:69). Any phone attachment over 100 MiB was refused before a byte was read.

The fix

The receive loop already streams each data frame into a .part file, so the cap only refused. This removes the check, the upload_max_bytes config field, the env var, the default constant, and their mentions in PROTOCOL.md, SECURITY.md and rust/README.md. Any declared size is accepted and streamed. The integrity checks stay: more bytes than declared is refused, a short upload is refused, and either leaves no file.

The iOS LinkUpload client's own pre-check is a separate change and is not touched here.

Red / green

  • Red f7eed9548f99aca47032c778040418bfd3979919: an_upload_past_the_old_100_mib_cap_is_saved_whole in tests/host.rs streams 100 MiB + 1 byte in 256 KiB chunks over the WireGuard link and checks the saved file's length. cmux-ci test -- cargo test -p cmux-mobile-host --test host an_upload_past_the_old_100_mib_cap (run 40767397481) failed: {"error":"too_large","message":"the file is larger than 1 MB"}, left: "too_large" right: "eof" (the test fixture set the cap to 1 MiB; production defaulted to 100 MiB).
  • Green f3d13e25a42a5c0c2f1da66082b483d52195a717: cmux-ci test -- cargo test -p cmux-mobile-host -p cmux-mobile-link-ffi (run 40771627741) passed, exit 0. That covers the new test, the services_over_* upload cases and the link-ffi browser tests that build ServiceConfig.

Changelog

  • The iPhone app can attach files of any size to a Mac chat or terminal; the Mac no longer refuses ones over 100 MB.

Observed / Not run

  • Observed: the red and green runs above, on the org's Linux runners at each commit.
  • Not changed: the iOS LinkUpload client's own 100 MB pre-check and LiveTests.swift, which only parses a canned too_large reply. A separate change handles the client.
  • Other too_large refusals in this crate stay. They limit single protocol messages (the 4 MiB daemon line, the 32 MiB acpmux message) and the 64 MiB file preview read, not attachment uploads.

Agent session: agent session

🤖 Generated with Claude Code