Hive Hive
Sign in

feat(kura): raise the Xcode CAS artifact cap from 25 MiB to 256 MiB

GitHub issue · Closed

Metadata
Source
tuist/tuist #11650
Updated
Jul 5, 2026
Domains
Kura
Details

What changed

MAX_XCODE_BYTES goes from 25 MiB to 256 MiB, with a comment documenting the constraint chain.

Why / root cause

Xcode’s compilation cache stores every task’s outputs as CAS objects, and app-shaped projects have a heavy artifact tail (objects with fat debug info, asset-catalog outputs, bundles) that exceeds 25 MiB. Those uploads get a 413 from Kura, which the daemon experiences as a dropped connection mid-upload. The affected tasks can never publish, so they form a permanent-miss set: every rebuild recompiles them AND re-attempts the doomed upload.

Benchmarking the Mastodon fixture on a staging runner quantified it:

  • 2,559 failed saveCASArtifact uploads per warm build (plus 217 failed keyvalue puts, some blocking until timeout)
  • cache hit rate plateauing at 81-89% of 815 cacheable tasks, never reaching 100%
  • warm cached build 139.7 s vs 56.0 s with caching disabled (2.5x net-negative)

The inversion is not runner-specific: the June 23 production benchmark grid shows the same on third-party M4 runners against prod Kura (Mastodon xcode-cache 59.1 s vs 50.0 s no-cache), which runs the same constant. CLI-shaped projects (small artifacts, e.g. the tuist repo itself) never trip the cap, which is why this stayed hidden.

Why 256 MiB is safe

  • Memory: unaffected. Uploads stream to a temp file (read_request_to_temp), never into RAM.
  • Tmp disk: already governed. The tmp dir has its own budget (default 8 GiB) with 503 backpressure; concurrent large uploads are bounded by design.
  • Total cache budget: unchanged. KURA_CAS_CAPACITY_BYTES / the disk-percent policy still caps overall usage; a larger per-object cap does not grow the cache. The only effect is ring granularity: large objects consume segment space faster, marginally shortening retention for large-artifact accounts.
  • Segment architecture: respected. Segments rotate at 512 MiB; 256 MiB stays well under, so rotation never sees an oversized object.
  • Precedent: Gradle artifacts already use this exact path with a 100 MiB cap; Xcode gets more because its output tail is heavier.

Impact

For app-shaped projects this is the difference between the Xcode cache being net-negative and functional: with the tail publishable, hit rates can reach ~100% and the per-build failed-upload storm disappears. Follow-up (separate PR): a CLI-side size gate with a negative cache so artifacts over whatever cap remains are skipped once instead of re-attempted every build.

Validation

  • cargo check clean; full cargo test run before merge (no test references the constant).
  • The end-to-end validation is the Mastodon bench re-run once this reaches staging: hit rate should climb to ~100% and the cached build should drop below the 56 s no-cache baseline or near it.

🤖 Generated with Claude Code

Flights

Investigate, reproduce, or fix this item in an isolated repository. Each Flight preserves its outcome and agent session.

New Flights are paused Configure model inference, GitHub, and a sandbox provider to start another Flight. Existing results remain available below.
No Flights yet

Start a Flight and preserve its objective, outcome, and session here.

Comments

No GitHub comments yet.