ci(cmux-next media): rebuild a warm tour's prebuilt modules after a binary pin change
A pull request's second tour can fail on a Mac that last built its tag before a GhosttyNextKit pin change. cmux#21686's tour (job 117892119256) failed that way: the Mac had last built ci-media-pr-21686-head at 15:16Z on Oct 18 with GhosttyNextKit e6a27a1fb, and the new head pins ced99dcde. Xcode copied the new ghostty.h into Build/Products/Debug/include but reused the explicit module it had precompiled from the old one, so every Swift module importing GhosttyNextKit stopped with:
error: file '…/Build/Products/Debug/include/ghostty.h' has been modified since the module file
'…/Build/Intermediates.noindex/SwiftExplicitPrecompiledModules/GhosttyNextKit-….pcm' was built
The stale module is the SwiftPM binary target's (GhosttyNextKit), in SwiftExplicitPrecompiledModules. It isn't the GhosttyKit.xcframework that the "Download pre-built GhosttyKit" step re-extracts: both revisions in that job used the same ghostty SHA, and the cmux scheme doesn't link it.
The build step now runs scripts/ci/media_module_cache_stamp.py around each reload.sh:
clear, before the build, hashes every sha256 literal in the trackedPackage.swiftfiles (binary-target checksums change with their URLs) plus every trackedPackage.resolved. If the hash differs from the tag's stamp, or there's no stamp yet, it removesSwiftExplicitPrecompiledModules,ExplicitPrecompiledModulesandModuleCache.noindex. Everything else in DerivedData stays warm.record, after a build that succeeded, writes the stamp.
Each existing warm dir has no stamp yet, so its first tour after this lands rebuilds its modules once.
Validation
tests/test_ci_media_module_cache_stamp.py(registered in ci-guards andtests/test-execution.toml) runs the real build step twice against a stand-inreload.shthat fails like Xcode did when a module from another pin is still there. Before the fix (d7aab706f6) it fails with the same "has been modified since the module file" error; with the fix (2594d7504d) all 12 checks pass.actionlintreports nothing oncmux-next-media.yml.test_ci_prune_media_derived_data.pyandtest_cmux_next_media_tour_gate.pystill pass.- CI repro on a real tour: a draft proof PR builds the head tag, reverts the GhosttyNextKit pin to a19c884fa on that warm tag, and rebuilds it twice: once without the stamp (control) and once with it. Results are linked below once that run finishes.
Changelog
none
🤖 Generated with Claude Code
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes cmux-next media tours failing on Macs whose warm tag DerivedData holds Swift explicit modules precompiled from an older GhosttyNextKit pin; a new pin makes every Swift module importing GhosttyNextKit fail with ghostty.h has been modified since the module file ... was built (job 117892119256).
The build step now runs scripts/ci/media_module_cache_stamp.py around each reload.sh. clear hashes the binary-target checksums in tracked Package.swift files plus every tracked Package.resolved and removes SwiftExplicitPrecompiledModules, ExplicitPrecompiledModules, and ModuleCache.noindex when the hash differs from the tag's last recorded stamp; record writes the stamp after a successful build. Everything else in DerivedData stays warm, and existing warm dirs rebuild their modules once since they have no stamp yet.