SummaryWith What we saw in CIPublic repo (basecamp/hey-sdk; the trial is #182, the write-up and revert #187), A pull request that left
Reproduction on a Linux workstation (mbx
|
| Populate commands (in order) | bundle | after import: clippy --all-targets --all-features |
after import: test --all-features --no-run |
|---|---|---|---|
clippy only |
484 actions, 1 task manifest with 484 predictions | 273 hits, 3 misses, 184 not looked up, 5.1 s | 2 hits, 605 not looked up (never populated; expected) |
clippy, then test --no-run |
892 actions, 1 task manifest with 424 predictions | 55 hits, 1 miss, 404 not looked up | 273 hits, 2 misses, 184 not looked up, 6.1 s |
The second row is the CI shape in miniature: the bundle carries every action from both commands (892) but only the second command's predictions (424), so the first command after import cannot look anything up except the actions the two commands share (build scripts, proc-macro crates). The 184 "not looked up" in the hit rows are aws-lc-sys C compilations (cc-unportable-output in MBX_BYPASS_LOG), unrelated to this.
In CI the last command that touches the workspace lockfile is a small one (build --examples, or the no-default-features test build), so the manifest that ships carries 6–60 predictions and the next job's clippy pass, with 654 compilations, finds none. A local store on the same workstation hits (478 hits on a second clone) because it learned every command's predictions itself.
Where it comes from
crates/mbx-cache-store/src/lib.rs, export_receipts: receipts are sorted by completion time and inserted into a map keyed by receipt.identity, so a later receipt replaces an earlier one:
// One task manifest can carry only one action per invocation. The
// newest run of the same task is the useful prediction set to import;
// every older action remains in `actions` and therefore in the bundle.
tasks.insert(receipt.identity.clone(), TaskActionManifest { …, predictions: receipt.predictions });The identity is the digest of Cargo.lock (build_identity → workspace_marker), so every mbx command in a job shares one identity, and a receipt holds "the exact cache predictions completed by one top-level build command". Two commands with different flags predict different invocations, so the newest receipt is not a superset of the older ones; the comment's assumption holds for repeated runs of one command, not for a job that runs several.
On the import side, merge_imported_manifest already unions by invocation when a manifest for the identity exists (imported predictions first, existing ones fill in). Doing the same at export — fold every receipt for an identity into one manifest, newest prediction per invocation — would give the next job a lookup for each command the previous job ran. An alternative that needs no format change would be for the action to run one mbx cache export per command, but the bundle is one GitHub cache entry, so the union at export seems like the right place.
Note on the store sweep
With the sweep left at its default, gc.max_size is 5% of the runner's disk, well under the 10.5 GiB the import had just written, and the first mbx command of the job evicted about half of the imported objects before compiling. MBX_GC_AUTO=0 for the job fixed that. It may be worth the action either disabling the automatic sweep for the job or raising the budget to at least the bundle it just imported.
Happy to test a branch; the repository, commit and commands are all public, and the workstation reproduction takes about a minute.
Replies: 3 comments
|
Confirmed—your diagnosis matches the export path. I've opened #424 to union each task's predictions across all command receipts, choosing the newest completed receipt only when the same invocation appears more than once. The archive still retains every referenced action, including superseded results. The regression exports and imports overlapping command receipts into an empty store. It fails on the old code and passes with the fix; all 50 cache-store tests passed on Linux, and the full local CI gate passed on macOS. The GC budget issue is separate and isn't changed by this PR. |
|
I've opened a separate Action fix for the GC-budget problem: jdx/mr-boxington-action#37. For GitHub-hosted runners using The regression makes the timing concrete: import a bundle, build with a 1-byte budget and collection due, then export the completed command's closure. With GC enabled the first build hits, but the post-build sweep evicts the objects and re-export fails with This complements #424's prediction-union fix; it doesn't require a new mbx feature. Until the Action change is released, the job-level |
|
Results from CI with the fix, on the same Push to Pull request with against 193–204 s with We're pinning |
Confirmed—your diagnosis matches the export path. I've opened #424 to union each task's predictions across all command receipts, choosing the newest completed receipt only when the same invocation appears more than once. The archive still retains every referenced action, including superseded results.
The regression exports and imports overlapping command receipts into an empty store. It fails on the old code and passes with the fix; all 50 cache-store tests passed on Linux, and the full local CI gate passed on macOS.
The GC budget issue is separate and isn't changed by this PR.
MBX_GC_AUTO=0remains the workaround for your disposable runner experiment; this fix prevents missing prediction…