Skip to content

ci: store each app-host product file once in the product archive - #14601

Merged
teamleaderleo merged 2 commits into
mainfrom
ws5-compile-speed
Sep 25, 2026
Merged

teamleaderleo merged 2 commits into
mainfrom
ws5-compile-speed

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

Why

The owned Macs upload at about 7.5 MB/s each (a per-host uplink cap: measured 6 to 7 MB/s to Cloudflare from 7s, 15 and mini-6 at once, single or 8 parallel streams). The 830 MB app-host product therefore takes 120 s p50 (199 s p90) of every owned compile admission, and about as long again for each owned consumer that downloads it (hq#661 workstream 5).

A third of those bytes are duplicates. Build/Products reaches every framework binary through Versions/Current symlinks. Product extractors accept no symlinks, so packaging used tar -h, which stored each framework binary three times: 1.9 GB on disk became 2.7 GB of tar.

Change

Stage the tree as hard links with the symlinks followed (pax -rwlL, the same tree tar -h wrote) beside the DerivedData so the links stay on one volume, then tar the stage. tar stores each file once and every other path as a hard link. Applied to the three places that pack this product: compile admission, the seed workflow and E2E.

  • tar -x (restore-app-host-test-product.sh, the rerun workflow), aa (layered products) and reuse_app_host_products.py unpack (which already accepts hard links) all extract the same files as before. Checked locally with a framework-shaped tree through all three.
  • Nothing is removed. The rerun workflow still gets the .o and .swiftmodule files it links against.

Measured

On a kept cmux10s product, same moment, mini under load:

archive pack time
tar -chf + gzip -1 (before) 829,759,308 B 41 s
pax hard-link stage + tar -cf + gzip -1 572,435,138 B 28 s (pax 4 s)

Expected on an owned admission: about 35 s less upload and 13 s less packing, and about 35 s less download per owned consumer. I will post the before/after from real runs on hq#661.

🤖 Generated with Claude Code


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


Summary by cubic

Stores each app-host product file once in the product archive, cutting the archive from 830 MB to 572 MB and pack time from 41 s to 28 s. Build/Products reaches each framework binary through Versions/Current symlinks, so tar -h stored every binary three times; on owned Macs that 830 MB upload costs about 120 s per compile admission.

  • Stages the tree as hard links with pax -rwlL beside DerivedData, then tars the stage; compile admission, the seed workflow, and E2E all use it. The stage is also removed on any exit via trap.
  • tar -x, aa, and reuse_app_host_products.py extract the same files as before, and the rerun workflow still gets the .o and .swiftmodule files it links against.

Written for commit 7a2870f. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Chores
    • Improved packaging of macOS build artifacts by reducing duplicated framework files in archived builds. The packaged app contents remain unchanged.

@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: f4a859cf-923e-48fe-b678-a2b881fbc095

📥 Commits

Reviewing files that changed from the base of the PR and between 561d317 and 7a2870f.

📒 Files selected for processing (3)
  • .github/workflows/ci-macos.yml
  • .github/workflows/seed-derived-data.yml
  • .github/workflows/test-e2e.yml

Included review availability: Your plan provides up to 10 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The macOS, seed-derived-data, and end-to-end workflows now stage build products with symlinks followed and files hard-linked before archiving the staged tree. The macOS workflow retains gzip -1 compression and removes its staging directory on exit.

Changes

Product Archive Packaging

Layer / File(s) Summary
Stage and archive build products
.github/workflows/ci-macos.yml, .github/workflows/seed-derived-data.yml, .github/workflows/test-e2e.yml
The three workflows stage build products with symlinks followed and files hard-linked, then archive the staged tree. The macOS workflow removes its staging directory on exit and retains gzip -1 compression.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~12 minutes

Change: Refactor

Merge Risk: ⚪ Minimal · up to 7a287

The changed archives remain compatible with the supplied product-reuse path. No identified issue blocks merging after normal checks.

Architecture Summary

Architecture risk: 🔵 Low · up to 7a287

The changed surface does not map to a changed system, dependency edge, entrypoint, or external dependency.

Changed systems: None identified.

Architecture concerns
No architecture-level concerns identified.

Review details

Before / after behavior

  • observed — Modified behavior in .github/workflows/ci-macos.yml: Product packaging now stages Build/Products with symlinks followed and files hard-linked, then archives the staged tree without dereferencing links. This replaces direct tar -h archiving, which stored framework binaries repeatedly. The staging directory is created beside DerivedData and removed on exit; compression remains gzip -1.
  • observed — Modified behavior in .github/workflows/seed-derived-data.yml: Product packaging now stages Build/Products with symlinks followed and files hard-linked, then archives that tree. This replaces direct tar -h archiving, which stored repeated framework binaries separately.
  • observed — Modified behavior in .github/workflows/test-e2e.yml: Product packaging now creates a temporary stage beside DerivedData, uses pax to follow symlinks while preserving repeated files as hard links, and archives the staged tree with COPYFILE_DISABLE=1. This replaces direct tar -h archiving of Build/Products.
🚥 Pre-merge checks | ✅ 25
✅ Passed checks (25 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: storing each app-host product file once in the archive.
Description check ✅ Passed The description clearly explains the problem, implementation, affected workflows, compatibility considerations, and measured results. Testing evidence is included, although it is not presented under a…
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Cloud Persistent Session And Early Input ✅ Passed PASS: The pull request changes only three GitHub Actions workflows that package app-host product archives. The diff adds pax staging, tar archiving, and cleanup traps. It does not change Cloud ter…
Cmux Swift Actor Isolation ✅ Passed The pull request changes only three GitHub Actions YAML workflows. The authoritative diff contains no Swift source, Swift declarations, actors, MainActor annotations, Sendable types, or UI-bound store…
Cmux Swift Blocking Runtime ✅ Passed PASS: The pull request changes only three GitHub Actions workflow files. The diff adds shell packaging commands (mktemp, pax, tar, gzip, and an exit trap); it does not change Swift production …
Cmux Browser Automation Off-Main ✅ Passed PASS: The pull request changes only three GitHub workflow packaging steps. The diff replaces direct tar -chf calls with pax hard-link staging and tar -cf; it does not add or modify any `browser.…
Cmux Expensive Synchronous Load ✅ Passed PASS: The pull request changes only three GitHub Actions workflow YAML files. The diff adds shell-based product staging and archiving commands; it adds or moves no production Swift code and no agent-h…
Cmux Cache Substitution Correctness ✅ Passed PASS. The authoritative PR diff changes only three GitHub Actions YAML workflow files. It updates archive staging and cleanup commands; it does not change production Swift, TypeScript, or JavaScript c…
Cmux No Hacky Sleeps ✅ Passed PASS: The PR changes only three GitHub Actions workflow YAML files. The rule explicitly excludes workflow/action YAML from this check. The changed commands stage files with pax, archive with tar, …
Cmux Algorithmic Complexity ✅ Passed PASS. The PR changes only three workflow packaging steps. In each file, pax -rwlL stages Build/Products and tar | gzip archives it (ci-macos.yml:954-957, seed-derived-data.yml:408-411, `test…
Cmux Swift Concurrency ✅ Passed PASS. The pull request changes only three GitHub Actions YAML files. The diff adds shell-based pax, tar, gzip, and cleanup commands. It adds no cmux-owned Swift code and introduces no Swift conc…
Cmux Swift @Concurrent ✅ Passed PASS: The pull request changes only three GitHub Actions YAML files. The authoritative diff contains no Swift files, Swift declarations, or Swift call sites. Therefore it cannot introduce any `@concur…
Cmux Swift Package Boundaries ✅ Passed PASS: The pull request changes only three GitHub Actions workflow files. The authoritative diff contains no Swift files or Swift package/app-target code, so the Swift package boundary rule is not appl…
Cmux Swiftpm Lockfiles ✅ Passed The PR changes only three workflow packaging steps. The diff replaces tar -chf with hard-link staging and cleanup. It does not change Package.swift, Package.resolved, .gitignore, Xcode project…
Cmux Swift Logging ✅ Passed The pull request changes only three GitHub Actions workflow files. The diff adds shell packaging commands and comments; it adds no Swift code or logging statements. Therefore, none of the Swift loggin…
Cmux User-Facing Error Privacy ✅ Passed PASS. The authoritative diff changes only three GitHub Actions workflow packaging steps. It adds staging, pax, tar, cleanup, and developer-only comments; it does not add user-facing errors, alerts…
Cmux Full Internationalization ✅ Passed PASS: The review-scoped diff changes only .github/workflows/ci-macos.yml, .github/workflows/seed-derived-data.yml, and .github/workflows/test-e2e.yml. The changes replace CI archive commands wit…
Cmux Swiftui State Layout ✅ Passed PASS: The pull request changes only three GitHub Actions workflow files: .github/workflows/ci-macos.yml, .github/workflows/seed-derived-data.yml, and .github/workflows/test-e2e.yml. The diff con…
Cmux Architecture Rethink ✅ Passed PASS: The pull request changes only three GitHub Actions YAML workflows. It adds shell-based pax, tar, staging, and cleanup logic. It changes no Swift source and introduces none of the architectur…
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR changes only three GitHub Actions workflow files. The authoritative diff contains no Swift or window-related code, so the auxiliary-window close-shortcut rule is not applicable.
Cmux Source Artifacts ✅ Passed PASS. The pull request changes only three existing GitHub Actions workflow configuration files. The added staging directory and archive commands create temporary CI runtime data; they do not add artif…
Cmux No Test Or Debug Seam In Production Source ✅ Passed PASS. The authoritative pull-request diff changes only three GitHub Actions workflow YAML files. It changes no Swift file under a production Sources/ path and introduces no test/debug seam covered b…
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

teamleaderleo and others added 2 commits September 25, 2026 08:29
Build/Products reaches every framework binary through Versions/Current
symlinks. Product extractors accept no symlinks, so packaging used
`tar -h`, which stored each framework binary three times: 1.9 GB on disk
became 2.7 GB of tar and 830 MB gzipped. On an owned Mac the upload runs
at about 7.5 MB/s (a per-host uplink cap), so the duplicates cost about
35 s of every compile admission and as much again on every owned consumer
download.

Stage the tree as hard links with the symlinks followed (pax -rwlL, the
same tree `tar -h` wrote) beside the DerivedData, and tar the stage. tar
stores each file once and the other paths as hard links, which tar -x,
aa and reuse_app_host_products.py all extract to the same files. Measured
on a kept cmux10s product: 830 MB -> 572 MB, 41 s -> 28 s to pack.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo merged commit 36b8063 into main Sep 25, 2026
61 checks passed
@teamleaderleo
teamleaderleo deleted the ws5-compile-speed branch September 25, 2026 12:52
@github-actions

Copy link
Copy Markdown
Contributor

Merge receipt for 7a2870f5c5: every check was green at merge (15 verified; 14 skipped by policy). Full suite runs on main after merge.

rustybret pushed a commit to rustybret/bmux that referenced this pull request Sep 25, 2026
c055747 ci: parse runner expressions in the fork guard, and gate LINUX_RUNNER on fork PRs (manaflow-ai#14192)
fc112a8 docs(testing): describe how run-e2e.sh actually picks the runner (manaflow-ai#14620)
0f6edfa ci(owned): keep seeds until the disk is actually short, not at a fixed 6 (manaflow-ai#14621)
1b78097 CI: one owned-pool rescue sweeper instead of a rescue run per CI run (manaflow-ai#14602)
c7e79f6 Hold Files tree reloads while its context menu is open (manaflow-ai#14451)
dbb24cb ci: read the owned-pool rescue's Actions API through the route App (manaflow-ai#14499)
36b8063 ci: store each app-host product file once in the product archive (manaflow-ai#14601)
0dba677 CI: run CmuxWorkspaces package tests (manaflow-ai#14592)
2244e98 Fix color detection in native tmux mirrors (manaflow-ai#14175)
3d2478e build: keep every built file in a project group so Xcode reuses its build description (manaflow-ai#14486)
a1a5ae9 ci(cmux-tui): cache cargo builds in the Rust jobs (manaflow-ai#14613)
560e640 ci(owned): keep 8 seeds per mini and pick seeds by cost, not a 2-commit cap (manaflow-ai#14607)
561d317 cmux-debug-cli: find a publish-hq build in the HQ tag app cache (manaflow-ai#14579)
c0aaac7 fix(events): survive receive-timeout reconfiguration churn during replay (manaflow-ai#13888)
3bd994a fix: keep split zoom when the zoomed pane outlives a tab close (manaflow-ai#12853)
ca984c7 Session snapshots can send binding actions to ghostty on a surface that is no longer live (manaflow-ai#12623)
a47d65b settings: expose local tmux session persistence (manaflow-ai#13210)
e3acb25 ci: give an owned Mac's full app rebuild 35 minutes to compile (manaflow-ai#14594)

# Conflicts:
#	.github/workflows/ci-artifact-transport.yml
#	.github/workflows/ci-cache-receipts.yml
#	.github/workflows/ci-guards.yml
#	.github/workflows/ci-macos.yml
#	.github/workflows/ci-owned-pool-rescue.yml
#	.github/workflows/ci-web.yml
#	.github/workflows/ci.yml
#	.github/workflows/cloud-machine-tests.yml
#	.github/workflows/cloud-vm-guest-install.yml
#	.github/workflows/cloud-vm-image-contract.yml
#	.github/workflows/cloud-vm-image-reachability.yml
#	.github/workflows/cloudflare-relay.yml
#	.github/workflows/cmux-skill-contract.yml
#	.github/workflows/cmux-tui-sdks.yml
#	.github/workflows/cmux-tui-spec.yml
#	.github/workflows/cmux-tui.yml
#	.github/workflows/indexnow-tests.yml
#	.github/workflows/iroh-v2.yml
#	.github/workflows/localization-catalog.yml
#	.github/workflows/r2-upload-tests.yml
#	.github/workflows/remote-daemon.yml
#	.github/workflows/repair-nightly-appcast-content-types.yml
#	.github/workflows/required-checks-drift.yml
#	.github/workflows/resolve-dispatch-ref.yml
#	.github/workflows/seed-derived-data.yml
#	.github/workflows/terminal-hang-diagnostics.yml
#	.github/workflows/test-e2e.yml
#	.github/workflows/test-ios.yml
#	.github/workflows/testbox-broker-guard.yml
#	.github/workflows/web-validation.yml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant