perf(cmux-next): a large file copy sends the Files pane ~200 progress updates, not one per block
Copying a large file in the Files pane sent the pane one progress update per block that copyfile copied. Each update went through an unbounded AsyncThrowingStream to FileBrowserModel on the main actor, and setting transferProgress re-rendered the pane. A 10 GB copy in 64 KB blocks makes about 150,000 of those.
FileTransferJob now passes a file's block reports through a TransferProgressGate, which lets one through for every 1/200 of the transfer's bytes. The first report always goes through. The update after each finished, skipped or moved item is sent as before, so item counts and the final state don't change. The progress bar now moves in steps of 0.5% of the whole transfer.
Evidence
Tests/CmuxNextFilesTests/TransferProgressGateTests.swift:
- A 10 GB transfer fed in 64 KB blocks (152,588 reports) lets 150โ201 through.
- The first report always passes.
- A zero-byte transfer still reports.
There's no red-first commit: the gate is new, and the existing copy tests can't observe the block reports, because copyfile clones on APFS and reports no data blocks for a temp-folder copy.
Observed / Not run
prepush-gate.py: no new violations.- Not run: no Swift toolchain on this Linux host, so nothing compiled here. PRs into feat-cmux-next skip
swift test, so these tests have not executed yet. No profile of a real copy.
The first commit, ed4f6a39c1f7, was made from a stale index and carried reverts of 37 unrelated base files. 1cf57d4bdab5 puts every one of them back to the base it branched from, so the PR's diff is FileTransferJob.swift and its test only. The branch wasn't force-pushed.
Review: BLOCK at ed4f6a39c1f7 for those stray reverts (independent general-purpose review subagent). It found the gate itself correct: the Swift 6 closure capture is sound, the gate carries across items without suppressing a later file's reports, and the final per-item progress always goes out. Review: SHIP at 1cf57d4bdab5 (same reviewer): the net diff against the base is exactly the two files, and the gate change is byte-identical to what it reviewed.
Proof
Not UI: the progress bar is the same view, updated less often during one large file.
Changelog
Fixed: Copying a large file in the Files pane no longer floods the pane with progress redraws.
๐ค Generated with Claude Code