ci(cmux-next): DEV Release compile reuses a content-keyed compilation cache, not kept build products

Merged
TE
9d ago
+215-4

Leo: "the incrementally, you know, tracking the latest commit or whatever, building it off the right way, building the right things, like reusing as much as you can"

What changes

Only the DEV Release compile (cmux NEXT DEV Release compile, the unsigned app the DEV channel signs and publishes). Nightly and stable stay whole-module, with no cache change.

On a glaeda mini the compile now:

  • starts from a tree that keeps only CompilationCache.noindex (Xcode's content-addressed compilation cache) and SourcePackages. No kept build products, so nothing stale links into the shipped app (the kept-DerivedData autolink failure, #21761). The DerivedData path is real-path'd because it is part of the cache keys.
  • builds with COMPILATION_CACHE_ENABLE_CACHING=YES and the 3 GiB limit nightly uses, then prunes dead generations (prune-xcode-compilation-cache.py) and drops the cache past 6 GiB.
  • uses SWIFT_COMPILATION_MODE=incremental (still -O). Whole-module is one job per module, which no cache can replay; incremental lets the cache replay every file the merge didn't change.
  • uses DEBUG_INFORMATION_FORMAT=dwarf, because the DEV channel ships no dSYM (only the .app is zipped).

Self-healing: a build that fails on the cache itself (CAS open or corrupt errors in the log) drops the cache and builds once more without it. A code failure is not retried. Blacksmith fallback VMs keep the cache off (a fresh VM would only pay to fill it).

Switch back with one repo variable each: CMUX_NEXT_DEV_COMPILATION_CACHE=0, CMUX_NEXT_DEV_SWIFT_COMPILATION_MODE=wholemodule.

check-release-compile.sh (a compile check whose products are never shipped) also gets DEBUG_INFORMATION_FORMAT=dwarf: GenerateDSYMFile is serial work after the last link.

Trust

No remote store and no new writer. The cache bytes come only from the same runner that builds and uploads the app. fleet-cas as a remote is left out on purpose: letting cmux15's writer feed bytes into the signed DEV binary is a trust-policy question, and the coordinator is raising it.

Numbers (harness measure_next_build.py --steps, glaeda std minis, same job)

Before (base): xcodebuild 518 s / 545 s / 560 s (SwiftCompile (129 tasks), 0 cache hits), compile step 8.9-9.4 min, job 10.2-12.5 min.

After: the DEV step only runs at refs/heads/feat-cmux-next, so it is measured on the first real merges after landing; numbers go in a comment here. Each runner's first cache build is cold (incremental -O, cache filling); later builds on that runner replay.

  • Success: a one-Swift-file merge on a warm runner: xcodebuild <= 300 s, with cache hits in summary.md (build_metrics.py already counts them per target).
  • Failure: a stale object in the app (impossible by construction: no kept products, and cache keys are content); a cache fault failing the build instead of falling back; a cold incremental build much slower than WMO (switch the var back).

Risk

Medium-low. Incremental -O gives up cross-file optimisation inside a module for the DEV app only, so it may run slightly slower than nightly; behaviour is the same Swift semantics. Rollback is a repo variable.

Agent session: cosmic-gray

šŸ¤– Generated with Claude Code


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