Two first-run discoveries. actions/checkout (and every JS action) execs
`node` inside the job container — the android-ci image didn't ship it, so
the job died at checkout with exit 127 (flatpak.yml documents the same
lesson for fedora:43); a trailing layer keeps the fat SDK/NDK layers
cache-valid. And windows-msix has been red since bf981027 required
punktfunk.exe in the package without adding punktfunk-cli to the build —
the same gap 90c84ef4 already closed for deb, now closed here (rpm and
arch already build it; the CLI has no features, so the arm64 leg's
--no-default-features changes nothing).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Android was the last job still downloading its world every run: ~3 GB of
SDK/NDK/CMake from Google, a from-source cargo-ndk build, and one monolithic
cache key where a gradle edit invalidated the cargo registry and the Rust
target/ with it. punktfunk-android-ci (content-keyed, LAN registry) bakes
JDK 21 + SDK + NDK + cargo-ndk + sccache; the workflow shrinks to checkout →
two caches → gradle. The cargo-home cache joins the fleet-wide namespace
(same lockfile, same layout — it was the same bytes under a private key),
gradle gets its own key shared with android-screenshots (which stored the
identical content under a second name), and target/ leaves the cache —
sccache covers the three ABI builds now.
Apple: sccache (self-healing ~/.local/bin install + already provisioned on
the mini) covers every cargo invocation build-xcframework.sh makes across
the swift job, the screenshots job and release.yml — three jobs that each
recompiled the same core. screenshots.sh learns PF_SHOT_DERIVED_DATA so CI
pins one stable DerivedData root instead of cold-building into two throwaway
mktemp trees per run (release.yml's disease, same cure), and the Simulators
get shut down after capture (the 846-leaked-sims lesson).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>