Skip to content

NEXT: Cloud and peer chat uploads take files of any size - #27073

Closed
teamleaderleo wants to merge 17 commits into
feat-cmux-nextfrom
lane/attach-uncap-cloud-peer-stager
Closed

teamleaderleo wants to merge 17 commits into
feat-cmux-nextfrom
lane/attach-uncap-cloud-peer-stager

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Leo: "WHY THE F*** SHOULD THERE BE A F***ING SIZE CAP ANYWAYS ... I ALREADY SAID WE NEED ARBITARRILY LARGE FILES OF ANY TYPE" (2026-10-26).

Cloud and peer chat uploads accept arbitrary file sizes while keeping transfer memory bounded by chunks. This is a dependency of #26958 for attachment originals. Related admission work: #27016 and #26409. The local-chat stager remains outside this PR.

Behavior

  • Remove Cloud/peer native admission caps, the staged-request decoder's file/count caps, and the Cloud upload CLI's 1 GiB cap. Preserve valid names, nonnegative sizes, ordered manifest authorization, session/target binding, and 512 KiB staging chunks.
  • Stream staged peer files from disk and emit Cloud CLI progress after each remote write. Active uploads use bounded per-request or idle deadlines, with no fixed total transfer deadline.
  • Keep stages cancellable through remote finish and awaited terminal cleanup. Page removal reaches a pending finish; fresh-task peer cancellation and scoped Cloud upload-cancel remove transfer-owned state. Batch authorization remains owned during staging and finish, so a slow first file cannot expire permission for the next file.
  • Stop stage/batch timers, abort listeners, and subscriptions on their terminal paths. File cleanup is awaited on the file-work lane before cancellation returns.
  • Bound upload and upload-cancel stdout AND stderr capture to a 4 MiB tail before allocating returned output. The final JSON reply survives without materializing old heartbeat history. Other ProcessRunner callers retain their complete-output defaults.

Memory and scope

The staged path uses bounded chunks and disk-backed stages. Legacy inline fallback remains page-bounded at 24 MiB. Upload reply/diagnostic capture is bounded independently of file size and transfer duration; an oversized final JSON line fails existing reply parsing.

Anonymous output files still spool stdout/stderr during child execution and can grow with transfer duration. This repair bounds completion capture memory; it does not claim bounded temporary disk usage. No daemon behavior or feature defaults change.

This diff keeps the admission, progress, authorization, cancellation, and cleanup state machine together with its regressions because those paths jointly determine whether arbitrary uploads finish safely. The obsolete limit-specific localized string is removed; existing translated upload-failure text is reused.

Exact source verdict

Independent Astra high whole-diff static review: SHIP at 53c2aa1bf4a8ca61abc4f8f051a271cf5a17d4ee, tree 04c95c24627ce1bf3cfe4828a8232dc3fcddc022, against base 5eaa384b5266504fb36a013c79f131ca0bd5f1c9.

This is a source-only verdict. It does not establish native compilation, native runtime correctness, green required checks, or permission to merge while the native HOLD remains.

Observed validation

  • Final-head Swift syntax parsing and pre-push checks pass. Parsing is not typechecking or native execution.
  • Web timeout regression red: run 40877856149, predecessor 211f09 plus the regression, expected final path but received the old elapsed timeout.
  • Web green: run 40878361783, tree matching predecessor 280240: 22 tests, 427 assertions, full format/lint/typecheck passed. Web sources are unchanged at the final head; this is reused unchanged-source evidence, not final-tree native proof.
  • Rust upload tests, binary build, and process-cancellation proof: run 40873830359, predecessor 7db0550: sparse 1 GiB+1 admission and scoped cancellation/sibling isolation pass. A real CLI process is killed after its first 8 MiB write; scoped cancellation removes its partial transfer. The endpoint models remote filesystem state in a controlled map, not a live Cloud VM. Rust/proof sources are unchanged at the final head.
  • Earlier throttled transfer: run 40822935120, predecessor 4dc1c25: 1 GiB+1, 129 chunks/heartbeats, 130.77 seconds, passed. Reused evidence for unchanged transfer sources; it does not validate subsequent Swift lifecycle repairs.

Native UNEXECUTED / remaining work

Under #26809 HOLD, final native typecheck, compilation, app launch, and execution of the new Swift regressions remain UNEXECUTED. Added coverage includes cancellation from an already-cancelled task; >10-minute staging plus finish followed by the next batch begin; virtual progress beyond one hour, stall/cancel watchdog cleanup and preserved hard deadlines; many-heartbeat final-reply retention, sparse output over 1 GiB, bounded stdout/stderr, and unchanged complete-output defaults. Existing sparse 1 GiB+1 and Int.max cases remain.

After the named hold is released, the final-loop owner reconciles required checks and runs the necessary focused native suites before merging. No SHIP claim is transferred to another head.

No visual behavior changes; no screenshot capture applies.

Changelog

  • Fixed: Cloud and peer chat attachments accept files of any size with progress-aware transfer deadlines and cancellable cleanup.

Agent session: agent session

teamleaderleo and others added 2 commits October 28, 2026 22:04
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".

These fail on base, which caps Cloud uploads at 32 MiB a file and 64 MiB
a batch and peer uploads at 1 GiB:
- CloudUploadsTests: a staged Cloud begin past 32 MiB, and a batch past
  the 64 MiB total, are taken; no language of cloud.upload.failed or
  cloud.upload.refused carries a placeholder or a number.
- AgentPeerUploadsTests: an inline peer upload past 1 GiB is sent; a
  staged peer begin past 1 GiB, alone or as a batch's first file, and a
  batch past the 1 GiB total, are taken.
- AgentPaneFilePutTests: a chunked put past 1 GiB sends its begin.
Sizes are only declared (Data(count:) or a declared size); no bytes are
written.

To test the Cloud begin without a live Cloud machine, its admission
check moves, unchanged, into CloudUploads.beginRefusal(name:size:manifest:).
The old test that the refusal names the limits is dropped.

Split out of #27016 (Cloud and peer stager caps); the peer test drop
and the "refusal names no limit" idea come from #27016.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-3f783e95b72165fe52b9
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".

Cloud (CloudUploads): drop maximumFileBytes (32 MiB) and
maximumTotalBytes (64 MiB), the guard in upload(_:to:services:), and in
a staged begin the per-file size check, the manifest's per-file and
total checks and the per-session staged total. A begin still needs a
non-negative size and a manifest that starts with the file begun.

Peer (acpmux file_put): drop AgentPaneUpload.maximumFileBytes,
maximumTotalBytes and maximumPeerFileBytes (1 GiB), the four guards in
AgentPaneFilePut, the begin and manifest checks in AgentPeerUploads'
stager and the guard in AgentPeerUploads.upload, and the base64 and
total limits in AgentPaneUpload.files. A peer that refuses a file
(filePut.tooLarge) still says so.

The chunk bound in both stagers is written size - offset, so a huge
declared size cannot overflow it.

Localization: cloud.upload.refused named the limits ("up to %1$@ each,
%2$@ in all") in every locale. There are no limits to name, so the key
and CloudUploadStrings.refused are gone; a refusal from the machine
shows cloud.upload.failed ("Couldn't send the file to the Cloud
machine."), already translated in every locale, and keeps its
upload_refused code for the page.

Split out of #27016 (Cloud and peer stager caps).

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

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

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

Review ab48db1: 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=pr27073 -f ref=lane/attach-uncap-cloud-peer-stager -f platform=macos -f backend_mode=local

Unclear: web / react-apps-check failed: no known signature; failed step: Check webview test shards.

CI failed on ab48db17af (run 40996476609 attempt 1): 1 code, 1 unknown.

Job Verdict Why
web / react-apps-base-check (2) code a web test failed
web / react-apps-check unknown no known signature; failed step: Check webview test shards

Failures:

  • seen on other PRs composer-menu-dismiss.test.ts chromium: agent-pane.new-tab reasoning-chip at 760 px: picking a mode or a level hands the keyboard ...: failed (job)
  • seen on other PRs composer-menu-dismiss.test.ts chromium: agent-pane.new-tab reasoning-chip at 300 px: picking a mode or a level hands the keyboard ...: failed (job)
  • seen on other PRs composer-menu-dismiss.test.ts webkit: agent-pane.new-tab reasoning-chip at 760 px: picking a mode or a level hands the keyboard ba...: failed (job)
  • seen on other PRs composer-menu-dismiss.test.ts webkit: agent-pane.new-tab reasoning-chip at 300 px: picking a mode or a level hands the keyboard ba...: failed (job)
  • seen on other PRs reasoning-own-control.test.ts New Tab at 760 px: the model button opens its menu, whose Effort row lists live levels: failed (job)
  • seen on other PRs reasoning-own-control.test.ts New Tab at 400 px: the model button opens its menu, whose Effort row lists live levels: failed (job)
  • seen on other PRs reasoning-own-control.test.ts New Tab at 300 px: the model button opens its menu, whose Effort row lists live levels: failed (job)
  • seen on other PRs reasoning-own-control.test.ts live chat at 760 px: the model button opens its menu, whose Effort row lists live levels: failed (job)
Matched log lines
web / react-apps-base-check (2): (fail) chromium: agent-pane.new-tab reasoning-chip at 760 px: picking a mode or a level hands the keyboard back to the prompt [31018.38ms]

Not re-run automatically: web / react-apps-base-check (2), web / react-apps-check are not machine failures.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

red: web / Web status; base red: the same failure on the base e5ea466; does not block
red: web / react-apps-base-check (2); no finished base run on e5ea466 to compare; do not merge until green; see lane-rules
red: web / react-apps-check; base red: the same failure on the base e5ea466; does not block

Gallery before/after for ab48db1: 16 states rendered, 0 images differ, 984 more touched states not rendered. Images are in the run's artifact, not on this public PR.

gh run download 40975344946 -R manaflow-ai/cmux -n gallery-advisory-27073-ab48db17afd1749b96c823d8512274be0ad0ec13 (then read gallery-review.json)

States
State Theme Status Diff Picked by
agent-pane.chat-width/standard Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.chat-width/standard Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.chat-width/wide Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.chat-width/wide Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.chat-width/wide-blocks Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.chat-width/wide-blocks Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-chat-14 Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-chat-14 Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-new-chat-14 Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-new-chat-14 Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-new-tab-14 Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-new-tab-14 Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-chat-21 Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-chat-21 Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-new-chat-21 Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-new-chat-21 Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-new-tab-21 Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-new-tab-21 Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-chat-28 Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-chat-28 Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-new-chat-28 Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer/font-size-new-chat-28 Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer-edge/short-edge Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer-edge/short-edge Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer-edge/wide-edge Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer-edge/wide-edge Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer-edge/no-edge Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer-edge/no-edge Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer-floats/scrolled-to-end Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer-floats/scrolled-to-end Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer-floats/composer-grown Apple System Colors Light unchanged 0% imports cloudUploads.ts (1 hops)
agent-pane.composer-floats/composer-grown Apple System Colors unchanged 0% imports cloudUploads.ts (1 hops)

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

@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 28, 2026
@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Default changes

This pull request changes 10 defaults at ab48db17afd1 (what everyone gets without configuring anything):

  • tunable-source.CmuxNextAgentPane/AgentPaneUpload.swift:maximumFileBytes: "5cfe6f663ddb24fb569543534f2cbd74c553f8f92cf6874bfb767748df2bcafa" -> (none)
  • tunable-source.CmuxNextAgentPane/AgentPaneUpload.swift:maximumPeerFileBytes: "f443b2319209bbfd903588c5f99d77210a39372e5dc219dfb8d30b7a6794025c" -> (none)
  • tunable-source.CmuxNextAgentPane/AgentPaneUpload.swift:maximumTotalBytes: "b8451d4304fca51003d8eccf684b340a651b50f81c33bd4363271a84dd4dd1b0" -> (none)
  • tunable-source.CmuxNextApp/AgentPeerUploads.swift:armBatchExpiry: (none) -> "c66326dcbf174fc2ee112d23950754770d478059eef1df1b6e22ef24f8425c52"
  • tunable-source.CmuxNextApp/AgentPeerUploads.swift:armStageExpiry: (none) -> "876ecfdfe1392e0c77bea4eeb7564cdd3ca97ee0573a517df13bdeb07e2acf9a"
  • tunable-source.CmuxNextApp/AgentPeerUploads.swift:removeStage: (none) -> "f836a29f18ecac9f2dc1a424747e4bc8362420136fa1816c46b6e6a5e9c75875"
  • tunable-source.CmuxNextApp/AgentPeerUploads.swift:stager: "e3c5946322dd3a1b63caa0d83a239766454d8c135dc09e0becb1d2f1d47bf419" -> "5ac39bebb8d468568977d0b430a8748fe4d3b6e2bc613ee31ea798f8430ec980"
  • tunable-source.CmuxNextApp/AgentPeerUploads.swift:upload: "c7af7ac535582330be549b5e5ab78451ce34629192ef2633ba7d54fcb09822be" -> "9025075bf84cec29a8837f3390d5566a1529f482926c5e85dbfdc823026453e5"
  • tunable-source.CmuxNextDaemon/Launch/ProcessRunner.swift:run: "f891574345f07a4f24bf1153731fb2e1451a09f542e76a9b58c3e2a1230ef056" -> "3539cf2ed6ea8d407f087fc3b131d0804496d9b5a7f541aa5193b9956ac9fa48"
  • tunable-source.CmuxNextDaemon/Launch/ProcessRunner.swift:waitForDeadline: (none) -> "c0ed31c8684cda85a9e0020f9095b3eb222270881f8efca06d4aafeb324d1372"

Needs a review. It passes with an independent review receipt on this commit: a comment or review whose first line is Review (<reviewer>): SHIP at ab48db17afd1749b96c823d8512274be0ad0ec13, from a member, not a self-review (the newest verdict naming the head decides; a later BLOCK beats an earlier SHIP), or with an approving review on this commit from @lawrencecchen or @austinywang (the call owners in .github/defaults-call-owners.json, never the author). A receipt posted as a review re-runs this check; after a plain comment, re-run it. The needs a call label alone does not pass, and a new push needs a new receipt.

Regenerate the snapshot with python3 scripts/ci/defaults_guard.py snapshot.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-9xt119 created for this PR by the cmux coordinator.

teamleaderleo and others added 2 commits October 28, 2026 22:24
…eer (red)

Review of #27073: the request decoder (AgentPaneRequest+Decoding) still
refuses a staged begin, or a manifest entry, over 1 GiB, and a manifest
of more than 64 files, before CloudUploads or AgentPeerUploads see it.
The stager tests called the stagers directly and missed it.

These fail on this head:
- AgentPeerUploadsTests.aDecodedBeginOfAnySizeReachesThePeerStager and
  CloudUploadsTests.aDecodedBeginOfAnySizeReachesTheCloudStager (2 GiB
  and 8 GiB): a chat.upload.begin decoded through AgentPaneRequest(body:),
  the bridge's own decoding, alone, as a batch's first file, and as a
  small first file whose manifest names a file over 1 GiB, must decode
  into the staged begin and be taken by the peer stager and the Cloud
  stager's begin check (DecodedStagedBegins builds the requests).
- AgentPaneUploadTests.stagedUploadAcceptsAnyNonnegativeFileSize and
  stagedUploadAccepts65LargeFiles, with
  stagedUploadRejectsNegativeFileAndBatchSizes, taken verbatim from
  #26409 so the two PRs' test hunks are identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-3f783e95b72165fe52b9
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".

AgentPaneRequest+Decoding: drop maximumUploadStageFile (1 GiB) from a
chat.upload.begin's size and each manifest entry's size, and the
64-entry manifest limit. A begin still needs a file name and a
non-negative size; a manifest still needs one or more well-formed
entries. A chunk stays at most 512 KiB.

This is #26409's change to the same file, line for line (its
3813876 and 951315e), so whichever of #26409
and #27073 lands second merges it cleanly. Cloud and peer begins do not
pass through AgentChatUploads (CloudHandlers+Move tries Cloud, then
peer, then the local stager), so the local stager's caps stay #26409's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-3f783e95b72165fe52b9
`cmux link access upload` (the Cloud chat's finish step) still refuses a
file over 1 GiB, so a file the stager took whole fails at the end with
upload_refused. The test pastes a sparse 1 GiB + 1 byte file and uploads
it to a fake fs-v1 machine: it must be accepted and arrive whole, in
parts of at most 8 MiB (overwrite, then appends).

Leo: "Attachments take arbitrarily large files of any type; there is no
size cap".

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

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

`cmux link access upload` refused any file over 1 GiB (MAX_FILE_BYTES),
so a Cloud chat upload the stager took whole still failed at finish with
upload_refused. The cap is gone. The file was already streamed: copy_file
hands an open file to Remote::write, which reads and sends it in 8 MiB
fs.write parts (overwrite, then appends to a temporary name, then a
rename), so nothing reads the whole file into memory.

The uploads.rs change is taken byte-identical from #27016 (launch-polish),
so the two merge cleanly; credit to that PR.

Leo: "Attachments take arbitrarily large files of any type; there is no
size cap".

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

Copy link
Copy Markdown
Collaborator Author

Red/green on the fleet (Xcode 26.6, macos-27), scripts/ci/package-test-lane.sh suite Packages/macOS/CmuxNext over CloudUploadsTests, AgentPeerUploadsTests, AgentPaneFilePutTests, AgentPaneUploadTests and CloudHintCommandsTests.

  • RED 6d15ae7752e0c29e391f2a77f426481212406dde: cmux-ci step cf1cec1c88dc4e64ec8221b8, exit 1. It compiled and ran with no crash. Every failure is an #expect.
  • GREEN 3e713c19c27f64dc7aa26b5751ecf0fbd519e570: cmux-ci step 6c7a5a4330d477d6cbee0b99, passed. 27 tests in 5 suites pass.
Test RED GREEN
CloudUploadsTests.aDecodedBeginOfAnySizeReachesTheCloudStager(size: 2147483648) FAIL (DecodedStagedBegins.decode(...) → nil, CloudUploadsTests.swift:34) pass
CloudUploadsTests.aDecodedBeginOfAnySizeReachesTheCloudStager(size: 8589934592) FAIL (same) pass
AgentPeerUploadsTests.aDecodedBeginOfAnySizeReachesThePeerStager(size: 2147483648) FAIL (DecodedStagedBegins.decode(...) → nil, AgentPeerUploadsTests.swift:114) pass
AgentPeerUploadsTests.aDecodedBeginOfAnySizeReachesThePeerStager(size: 8589934592) FAIL (same) pass
AgentPaneUploadTests.stagedUploadAcceptsAnyNonnegativeFileSize(size: 1073741825) FAIL (request → unsupported, AgentPaneUploadTests.swift:20) pass
AgentPaneUploadTests.stagedUploadAcceptsAnyNonnegativeFileSize(size: 9223372036854775807) FAIL (same) pass
AgentPaneUploadTests.stagedUploadAcceptsAnyNonnegativeFileSize(size: 0) pass pass
AgentPaneUploadTests.stagedUploadAccepts65LargeFiles FAIL (request → unsupported, AgentPaneUploadTests.swift:32) pass

The other 23 tests pass at both commits: aBeginOfAnySizeIsTaken (3 cases), aBatchOfAnySizeIsTaken, aMalformedBatchIsStillRefused, noLanguagesUploadFailureNamesALimit, anInlinePeerUploadOfAnySizeIsSent, aStagedPeerBeginOfAnySizeIsTaken (2 cases), aStagedPeerBatchPastTheFormerTotalIsTaken, aPeerChatGetsThePeerUploaderAndItsDropsAreNeverThisMacsPaths, anOlderPeerAnswersThatTheChatTakesNoUploads, eachFileGoesInTurnAndTheReplyNamesItsPathOnThePeer, aChunkedPutOfAnySizeBegins, aFileIsSentOnlyAfterTheDaemonSaysItTakesFilesAndAnswersItsPathThere, aHostWithoutAnAcpmuxTakesNoFiles, anOlderAcpmuxHereOrOnThePeerTakesNoFiles, resumableUploadUsesBoundedChunksAndCommitsThePath, refusalsMapToWhatTheComposerSays, decodesStagedCloudUploadRequestsAndBoundsChunks, stagedUploadRejectsNegativeFileAndBatchSizes, acceptsMoreThanTenFilesWithinByteAndNameLimits, and the four CloudHintCommandsTests.

The RED failures are exactly the expected set: the two decoder-to-stager tests at both sizes, stagedUploadAcceptsAnyNonnegativeFileSize and stagedUploadAccepts65LargeFiles. Read the logs with cmux-ci log <step>.

…ncap-cloud-peer-stager

# Conflicts:
#	Packages/macOS/CmuxNext/Tests/CmuxNextAgentPaneTests/AgentPaneUploadTests.swift
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra high, next-review): BLOCK at ab48db1

  • AgentPeerUploads.swift:76: Stage initialization omits the required expiry and cleanup arguments. Its synthesized initializer has no defaults, so the Swift target cannot compile.
  • CloudUploads.swift:159: Stage initialization omits the required cleanup argument, causing the same compile failure.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex-review-box/gpt-6-astra high, lane-place): BLOCK at ab48db1

BLOCK

  1. [P1] fs-bucket.ts:345 — macOS cannot traverse /dev/fd/<directory>/child like Linux’s /proc/self/fd links. The new rename helper therefore fails with ENOTDIR, breaking attachment writes and multipart creation on supported macOS home-server installations. The removal helper repeats this problem. Use Darwin-compatible filesystem operations.

  2. [P2] cloud_join.rs:114 — Repeating acpmux host join on an already joined machine unconditionally replaces meshRelay, clearing configured controlFrom grants and resetting teamMessaging to false. These features silently stop after restart. Preserve existing settings when repairing the same enrollment.

@teamleaderleo teamleaderleo removed the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 30, 2026
@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 30, 2026
teamleaderleo added a commit that referenced this pull request Oct 30, 2026
#26953's squash already carries this PR's first pair: the
`dictation.recording.cancel {path}` op and the chip's x that sends it,
stopping the upload before its next chunk and cancelling the stage. Base's
code is kept for it, and this PR no longer carries #26966's changes (that
PR lands on its own).

What base lacked is kept, on base's code:
- A cancel while the stager's finish runs cancels the finish's own task
  (AgentPaneDictationUploads.finishing), so the transfer stops before it
  commits; the upload answers `cancelled`, and a cancelled upload is not
  given back for Retry.
- withAgentPaneDeadline runs its teardown when the caller is cancelled, so
  a peer call's NWConnection is closed; AcpmuxStatusClient.start refuses a
  cancelled caller.
- A chunked put's file_put_cancel runs in a fresh task, so a cancelled put
  still drops what the peer staged (the same helper #27073 carries).
- A composer that goes away while a host-made chip is still being made
  stops it.

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

Copy link
Copy Markdown
Collaborator Author

Orphaned: no activity for 32 h, and no lane holds a lease on it. The orphan sweep could not merge feat-cmux-next in: conflicts in Packages/macOS/CmuxNext/Sources/CmuxNextAgentPane/AgentPaneFilePut.swift, Packages/macOS/CmuxNext/Sources/CmuxNextDaemon/Launch/ProcessRunner.swift, Packages/macOS/CmuxNext/Tests/CmuxNextAgentPaneTests/AgentPaneFilePutTests.swift, webviews/src/agent-session/acpmux/composer/attachmentIntake.tsx, webviews/src/agent-session/acpmux/composer/intakeFiles.ts. Listed for a lane to resolve.

teamleaderleo added a commit that referenced this pull request Nov 1, 2026
…size (#28695)

* NEXT: tests for Cloud and peer chat uploads of any size (red)

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

These fail on base, which caps Cloud uploads at 32 MiB a file and 64 MiB
a batch and peer uploads at 1 GiB:
- CloudUploadsTests: a staged Cloud begin past 32 MiB, and a batch past
  the 64 MiB total, are taken; no language of cloud.upload.failed or
  cloud.upload.refused carries a placeholder or a number.
- AgentPeerUploadsTests: an inline peer upload past 1 GiB is sent; a
  staged peer begin past 1 GiB, alone or as a batch's first file, and a
  batch past the 1 GiB total, are taken.
- AgentPaneFilePutTests: a chunked put past 1 GiB sends its begin.
Sizes are only declared (Data(count:) or a declared size); no bytes are
written.

To test the Cloud begin without a live Cloud machine, its admission
check moves, unchanged, into CloudUploads.beginRefusal(name:size:manifest:).
The old test that the refusal names the limits is dropped.

Split out of #27016 (Cloud and peer stager caps); the peer test drop
and the "refusal names no limit" idea come from #27016.

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

* NEXT: Cloud and peer chat uploads take files of any size

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

Cloud (CloudUploads): drop maximumFileBytes (32 MiB) and
maximumTotalBytes (64 MiB), the guard in upload(_:to:services:), and in
a staged begin the per-file size check, the manifest's per-file and
total checks and the per-session staged total. A begin still needs a
non-negative size and a manifest that starts with the file begun.

Peer (acpmux file_put): drop AgentPaneUpload.maximumFileBytes,
maximumTotalBytes and maximumPeerFileBytes (1 GiB), the four guards in
AgentPaneFilePut, the begin and manifest checks in AgentPeerUploads'
stager and the guard in AgentPeerUploads.upload, and the base64 and
total limits in AgentPaneUpload.files. A peer that refuses a file
(filePut.tooLarge) still says so.

The chunk bound in both stagers is written size - offset, so a huge
declared size cannot overflow it.

Localization: cloud.upload.refused named the limits ("up to %1$@ each,
%2$@ in all") in every locale. There are no limits to name, so the key
and CloudUploadStrings.refused are gone; a refusal from the machine
shows cloud.upload.failed ("Couldn't send the file to the Cloud
machine."), already translated in every locale, and keeps its
upload_refused code for the page.

Split out of #27016 (Cloud and peer stager caps).

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

* NEXT: tests for page-decoded uploads of any size reaching Cloud and peer (red)

Review of #27073: the request decoder (AgentPaneRequest+Decoding) still
refuses a staged begin, or a manifest entry, over 1 GiB, and a manifest
of more than 64 files, before CloudUploads or AgentPeerUploads see it.
The stager tests called the stagers directly and missed it.

These fail on this head:
- AgentPeerUploadsTests.aDecodedBeginOfAnySizeReachesThePeerStager and
  CloudUploadsTests.aDecodedBeginOfAnySizeReachesTheCloudStager (2 GiB
  and 8 GiB): a chat.upload.begin decoded through AgentPaneRequest(body:),
  the bridge's own decoding, alone, as a batch's first file, and as a
  small first file whose manifest names a file over 1 GiB, must decode
  into the staged begin and be taken by the peer stager and the Cloud
  stager's begin check (DecodedStagedBegins builds the requests).
- AgentPaneUploadTests.stagedUploadAcceptsAnyNonnegativeFileSize and
  stagedUploadAccepts65LargeFiles, with
  stagedUploadRejectsNegativeFileAndBatchSizes, taken verbatim from
  #26409 so the two PRs' test hunks are identical.

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

* NEXT: the request decoder takes a staged upload of any size

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

AgentPaneRequest+Decoding: drop maximumUploadStageFile (1 GiB) from a
chat.upload.begin's size and each manifest entry's size, and the
64-entry manifest limit. A begin still needs a file name and a
non-negative size; a manifest still needs one or more well-formed
entries. A chunk stays at most 512 KiB.

This is #26409's change to the same file, line for line (its
3813876 and 951315e), so whichever of #26409
and #27073 lands second merges it cleanly. Cloud and peer begins do not
pass through AgentChatUploads (CloudHandlers+Move tries Cloud, then
peer, then the local stager), so the local stager's caps stay #26409's.

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

* cmux link access: test a sparse upload over 1 GiB in bounded parts (red)

`cmux link access upload` (the Cloud chat's finish step) still refuses a
file over 1 GiB, so a file the stager took whole fails at the end with
upload_refused. The test pastes a sparse 1 GiB + 1 byte file and uploads
it to a fake fs-v1 machine: it must be accepted and arrive whole, in
parts of at most 8 MiB (overwrite, then appends).

Leo: "Attachments take arbitrarily large files of any type; there is no
size cap".

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

* cmux link access: an upload takes a file of any size

`cmux link access upload` refused any file over 1 GiB (MAX_FILE_BYTES),
so a Cloud chat upload the stager took whole still failed at finish with
upload_refused. The cap is gone. The file was already streamed: copy_file
hands an open file to Remote::write, which reads and sends it in 8 MiB
fs.write parts (overwrite, then appends to a temporary name, then a
rename), so nothing reads the whole file into memory.

The uploads.rs change is taken byte-identical from #27016 (launch-polish),
so the two merge cleanly; credit to that PR.

Leo: "Attachments take arbitrarily large files of any type; there is no
size cap".

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

* Keep staged uploads cancellable through transfer

Agent-Session: https://cmux.com/deeplink/agent?id=aid-330ba9006c9e47d455e5

* Keep peer cancellation test on main actor

Agent-Session: https://cmux.com/deeplink/agent?id=aid-330ba9006c9e47d455e5

* Allow staged cancellation test to overlap finish

Agent-Session: https://cmux.com/deeplink/agent?id=aid-330ba9006c9e47d455e5

* Keep peer transfer task with its stage

Agent-Session: https://cmux.com/deeplink/agent?id=aid-330ba9006c9e47d455e5

* Cancel active staged uploads through terminal cleanup

Agent-Session: https://cmux.com/deeplink/agent?id=aid-330ba9006c9e47d455e5

* Retain batch authorization through upload cleanup

Agent-Session: https://cmux.com/deeplink/agent?id=aid-330ba9006c9e47d455e5

* Stop stage expiry while terminal cleanup owns it

Agent-Session: https://cmux.com/deeplink/agent?id=aid-330ba9006c9e47d455e5

* Keep active uploads bounded by idle progress

Agent-Session: https://cmux.com/deeplink/agent?id=aid-330ba9006c9e47d455e5

* Bound upload reply and diagnostic capture

Agent-Session: https://cmux.com/deeplink/agent?id=aid-330ba9006c9e47d455e5

* Fix upload regression test isolation and macro mutation

Agent-Session: https://cmux.com/deeplink/agent?id=aid-b14e80c6998b6f900360

* Attachment cap guard: an exemption names only a cap its file still declares (red)

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

* Attachment cap guard: drop the exemptions of caps that are gone

Cloud and peer uploads no longer declare their file and batch caps, nor the
CLI its MAX_FILE_BYTES, so their exemptions go; AgentPaneDraftAttachments'
maximumBytes was already gone on base.

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

* NEXT: a pinned recording keeps its own in-memory budget; stages name every field

Base's #24473 read AgentPaneUpload.maximumFileBytes and maximumTotalBytes for
the macOS capture-thumbnail recording snapshot, which this branch removes, so
the merged tree did not compile. The snapshot reads the recording into memory
before saving it, so it keeps the same 1 GiB as its own named budget
(AgentPaneRecordingSnapshot.maximumPinnedBytes / maximumPinnedTotalBytes).
The Cloud and peer Stage initializers name expiry and cleanup explicitly.

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

* NEXT: Cloud and peer staged uploads share one store in CmuxNextAgentPane

The two App stagers each kept their own stages, batches, expiry deadlines and
cleanup tasks (+131 CmuxNextApp lines, which the arch ratchet refuses).
AgentPaneStagedUploads<Target> now owns that once: a stage of any size, a
batch authorized while its stages live, one DemandTimer for abandoned stages
and batches (the peer stager no longer sleeps a task per stage), a transfer
that owns its file until it returns, and a cancel that stops the transfer
before the staged file is removed. Each App stager keeps only its own target
checks, file layout and transfer. AgentPaneStagedUploadsTests covers begin of
any size, batch order, chunk ownership, and cancel during the transfer.

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

* NEXT: Cloud uploads go one file per call; a late cancel takes a delivered file back

Review of the carry (Astra, BLOCK at 6ff0fa8):
- The older one-frame upload sent every file in one CLI call, under no upload
  id: more than 64 files were refused, and a failed or cancelled call left its
  partial file and the files already sent on the machine. CloudAccessCLI.upload
  now sends each file in its own call under an id of the app's, and a failure or
  a cancel removes every file of the upload (removeUploads) before it answers.
- A cancel that came after the transfer delivered the file (the chip's x while
  the answer was on its way) found no stage and left the file on the machine.
  AgentPaneStagedUploads keeps a finished stage's undo for its lifetime; the
  Cloud stager's undo removes that upload id. Peers have no remote delete yet.
- CloudBringBackTests expects the upload id on the CLI call (the original
  already sent it for one file).

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

* NEXT: a Cloud upload's cleanup tries every file; the undo test compares before and after

Review of the carry (Astra, BLOCK at f6edd0e): removeUploads stopped at the
first failed removal, leaving later files on the machine; it now tries every
id and throws after. The late-cancel test expected no undo at all on its
second file, though the first had rightly been undone.

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

* NEXT: removeUploads' doc says once that every id is tried

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

* NEXT: intake's batch upload call keeps one formatter-stable line

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

* NEXT: the staged-upload undo test logs on a main-actor class; package-only imports

The fleet test compile refused the test's undo closure that appended to a
captured var (converting non-Sendable function value). AgentPaneStagedUploads
is package, so its imports need not be public.

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

* fix(attachments): drop the stale MAX_FILE_BYTES cap exemption

Base removed MAX_FILE_BYTES from access_cli/uploads.rs, so the guard's
exemption named a cap that no longer exists and
tests/test_attachment_caps_guard.py failed (1 of 19).
python3 -I tests/test_attachment_caps_guard.py: 19 OK.

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

* test(upload): a part in flight reports progress before its answer (red)

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

* fix(upload): report progress while a part is in flight; idle outlasts the socket deadline

Codex BLOCK on #28695: the 30 s upload idle only heard a heartbeat after a
whole 8 MiB fs.write returned, so a healthy slow link was killed. The Rust
Remote now writes a request line in 256 KiB slices and reports progress after
each slice and on each answer; the app's upload idle is 90 s, longer than the
CLI's 60 s per-read/write socket deadline (IO_DEADLINE). No size cap.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Superseded by its carry #28695, on the current base. Review and landing happen there. Closing this copy.

This branch was previously deployed

3 inactive deployments
artifacts — ab48db17 Deployed Oct 30, 2026 by teamleaderleo via add the Windows daemon to the tree #78994
sentry-dsyms — ab48db17 Deployed Oct 30, 2026 by teamleaderleo via upload cmux-tui dSYMs to Sentry #78994
ci-routing-agent — ab48db17 Deployed Oct 29, 2026 by teamleaderleo via cmux-tui tree preflight #78994
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