What
Memoizes the resolved auth token inside ServerAuthenticationController, bounded by the token’s own expiry, so repeated authenticationToken() calls don’t re-resolve the credential on every call. Uses the controller’s existing shared CachedValueStore (the .current instance already used to coordinate refreshes), so the cache is process-wide and single-flight.
Why (root cause)
The CAS compilation-cache daemon resolves auth on every artifact request (its middleware calls authenticationToken() per request). On macOS the credential store is the keychain, so every call did a keychain read via securityd, which serializes under concurrency.
This surfaced while investigating why the Xcode CAS was net-negative on hosted macOS runners:
- CAS analytics recorded ~340ms/op
transfer_duration for ~78KB artifacts.
- A packet capture on the host<->VM bridge showed the wire is ~1ms (handshake ~0.1ms, server processing ~0.2ms, transfer p90 ~0.3ms). So it is not the network.
- Sampling the daemon mid-build put the hot path in
ServerCredentialsStore.read (LocalAuthentication/KeychainCircle), not the network stack.
The gap in the controller: the valid-token path returned straight after a tokenStatus() keychain read, and cachedValueStore.getValue was applied only on the refresh branches. So a valid, non-expired token (the steady state during a build) was re-read from the keychain on every call.
What changed
authenticationToken(refreshIfNeeded: true) now wraps the resolution in cachedValueStore.getValue, keyed distinctly from the refresh lock, with an expiry shortly before the token’s own so the refresh/rotation path still runs in time (project tokens get a short TTL; an absent result is not memoized so a fresh login is picked up next call). Because it reuses the shared CachedValueStore, the memoization is process-wide and benefits every auth caller, not just the daemon. getValue’s single-flight means a concurrent burst performs one underlying read.
(An earlier revision of this PR used a decorator wired only into the CAS daemon; per review it was moved into the controller, which is the natural home and reuses the shared store.)
Impact
Removes the per-op keychain read from every hot auth path, chiefly the CAS daemon where it cost the most under load.
Validation
- Compiles: narrow
swift build --target TuistServer / TuistCAS both build.
- Adds
memoizes_a_valid_token_across_calls asserting that 10 resolutions read the credential store once.
- The memoization primitive (
CachedValueStore.getValue, single-flight + expiry) is existing, tested code. An earlier standalone run of the same pattern did one underlying read for 300 concurrent resolutions (0.0034s vs 0.902s when the read serializes like securityd).
Note: these are Tuist-generated test targets (run via tuist generate + xcodebuild / CI), not swift test targets, so CI is the authoritative test run.
Follow-up: once this reaches a canary, re-run the staging xcode-cache benchmark and confirm the recorded per-op transfer_duration collapses from ~340ms.
🤖 Generated with Claude Code