Repository navigation
Description
The platform-checks slice declares cache_mode: "none", so every run of it compiles from scratch, on main as well as on pull requests. The sdk slice sits on the same runner_role: platform-build and declares pr-isolated. I cannot find anything in ci/ci.md that explains the difference, so this is a question before it is a proposal.
What it costs today
Platform checks (windows-unit) on the ten most recent pushes to main, 2026-09-22:
| durations | 18, 19, 19, 20, 21, 23, 23, 23, 24, 24 min |
| mean | 21.4 min |
| sccache on one of those jobs | 1005 compile requests, 2 cache hits, 807 compilations, hit rate 0.25% |
Platform checks (macos-unit) is the same slice and also cold, 12m43s on a recent run.
Pushes to main that trigger Main · Windows: 9 on 09-19, 14 on 09-20, 18 on 09-21, 10 on 09-22 by 11:01Z. At roughly fourteen pushes on a full day that is about five hours of Windows runner per day for this one row, plus about three for the macOS one, all of it recompiling a dependency graph that did not change.
Why it looks like one word
scripts/plan-ci.py:564 reads:
def _planned_cache_mode(definition: dict[str, Any], profile: str) -> str:
mode = definition["cache_mode"]
if mode != "pr-isolated":
return mode
if profile == "main":
return "trusted-readwrite"
if profile == "manual-full":
return "trusted-readonly"
return modeSo a slice declared pr-isolated is already PR-isolated on pull requests and becomes trusted-readwrite on main, which is what sdk gets on the same runners. A slice declared none stays none everywhere, including on main where the trust boundary is not the same as on a PR.
Changing platform-checks to pr-isolated would therefore be one word in ci/slices.yml, with no new authority on pull requests.
What I am not claiming
I have not measured what a warm cache actually buys here, and I will not guess: a 0.25% hit rate says there is nothing to read from, not how much a populated store would save. The compile is 807 crates, most of which do not change between pushes, so the ceiling looks high, but that is an expectation and not a number.
I also do not know whether none is deliberate. It may encode a trust decision about these runners that sdk does not need, or it may simply be what the slice was born with. If it is deliberate, this issue is answered by saying so, and it would be worth a line in ci/ci.md so the next person does not ask again.
Offer
If the answer is "try it", I can prepare the catalog commit in the shape 947222559 took, watch the first few main runs, and report the before and after durations with the sccache statistics. If the row gets the nine crates measured on #1985, a cold build will only get longer, so the question is worth settling before rather than after.
Measured from the public run logs; nothing here needs a Windows machine to reproduce.
Activity
Virgile-pct commentedon Sep 28, 2026
Update with a narrower diagnosis and a concrete proposal.
Current cost.
Platform checks (windows-unit)on the last 10 successfulMain · Windowsruns: 22.9 to 28.4 min, mean 26.1 min (21.4 min when I opened this; the row has grown since).It is not only
cache_mode. Comparing the two Windows slice workflows onmain(b380e140c):ci-windows-host-slice.ymlsetsSCCACHE_GHA_ENABLED: "true"andRUSTC_WRAPPER: sccache, then runs./.github/actions/configure-sccache-ghaaftermozilla-actions/sccache-action, fed by theallow_native_github_cache/allow_depot_remote_cacheoutputs of its runner policy.ci-platform-checks-slice.ymlinstallssccache-actiontoo, and the repository's.cargo/config.tomlmakes cargo use it, but no step gives it a backend. Itsrunner_policyalready computes the same twoallow_*outputs and the job already runsaudit-depot-pr-isolationwith them; they are only used for the macOS llama cache. So sccache runs with a job-local disk cache on a fresh runner every time, which is the 0.25% hit rate above.Proposal, if
noneis not a deliberate trust decision for these runners:ci-platform-checks-slice.yml, for the Windows unit job:configure-sccache-ghaaftersccache-actionwith the twoallow_*inputs, plus the sameSCCACHE_GHA_ENABLED/RUSTC_WRAPPERenv the host slice uses. PR runs keep the isolation the host slice already has, since the same policy action decides what a PR may read or write.ci/slices.yml,platform-checksdeclarespr-isolatedlikesdk, so the plan states what the job does (trusted-readwriteonmain, isolated on PRs, per_planned_cache_mode).Part 2 is a protected-catalog change, so it would be a catalog-only maintainer merge like #2068, and part 1 is a lane workflow change that PR lanes load from
main, so neither can prove itself before landing. I have not measured the warm-cache gain and will not guess it. Happy to open both if you confirm the direction.Virgile-pct commentedon Oct 20, 2026
Update: the Windows half of this is fixed. #2374 (Oct 12) wired
configure-sccache-ghaintoci-platform-checks-slice.ymlfor Windows. On main's latestPlatform checks (windows-unit)(job 118444921110): 2120 compile requests, 1431 hits, 80.8% hit rate, against 0.25% when I opened this. The job still takes 24 to 41 min on main (last 12 runs), but that time is nowRun Windows unit testsitself (27 min), not a cold build.macOS is unchanged. The two sccache steps are gated on
platform == 'windows', sosetup-macos-lldstarts sccache with a local disk cache on a fresh runner, and nothing restores Rust build state between runs (only the static Metal ABI is cached).Run macOS unit teststakes 22 min on main (job 118449867228). The macOS host slice handles this withSwatinem/rust-cachebehindallow_native_github_cache; the unit row could do the same, or drop the Windows gate on the sccache steps. I can't run macOS CI here to measure what either buys, so I'd rather leave that choice to you than guess.ndizazzo commentedon Oct 26, 2026
Evidence — reproduced on current base (configuration-level)
Verified against
fix/megabugs@973ba7faf0(identical onmain). No fix applied yet.1. The cited owner has moved.
scripts/plan-ci.pyno longer exists. The planner is Rust:tools/xtask/src/ci_plan/plan.rs:33ownsplanned_cache_mode, andtools/xtask/src/ci_plan.rs:104stores it per slice. Semantics are unchanged from the Python version the report quotes.2. The divergence is present in the checked-in catalog.
ci/slices.ymldeclares both slices on the same runner role with different cache authority:runner_rolecache_modeplatform-checksplatform-buildnonesdkplatform-buildpr-isolatedplatform-checksis the onlyplatform-build-role slice with no cache.native-abi/native-ffialso declarenone, but they run on the separate self-hostednative-abirole, so they are not the comparison.3. The planner preserves it in every profile.
planned_cache_modemapspr-isolated→trusted-readwrite(main),trusted-readonly(manual-full),pr-isolated(allpr-*), and returnsnoneunchanged fornone. The committed expected fixtures show the asymmetry on the current base:.github/fixtures/ci_plan/control-main.plan.json—"platform-checks":"none"alongside"sdk":"trusted-readwrite".github/fixtures/ci_plan/manual-full-force-all.plan.json—"platform-checks":"none"alongside"sdk":"trusted-readonly"native-ffi,reverse-dependency-log-store,windows-log-store) —"platform-checks":"pr-isolated"So on
mainthe Windows/macOS hosted compile slice runs with no cache while the SDK slice on the identical runner role gets a read-write cache.4. PR isolation does not depend on the catalog value.
.github/workflows/ci-runner-contract-slice.yml:48fails anypr-*plan containing atrusted-readwritemode, andci/ci.md§11.1 requires PR jobs to restore only and forbids PR writes to the main namespace.pr-isolatedis therefore the correct declaration for this slice;noneis not protecting the PR boundary, it is only removing restore onmain. Thesdkslice is the existing proof that aplatform-buildslice can declarepr-isolatedand stay PR-restore-only.5. Scope check against the Cargo-archive rule.
ci/ci.md§11.1 forbids restoring per-shard Cargo target archives and per-object GHA publication for the Linux Clippy, Rust tests, host, and runtime families.platform-checksis the Windows/macOS hosted family, so aligning it does not touch that rule.Not re-verified here: the 0.25% sccache hit rate and ~21 min figures are the reporter's measurements. I confirmed the configuration and planner behavior that produces a cold compile, not the historical hit-rate number, and I did not rerun the expensive hosted workflows.
Planned fix and its merge constraint. Smallest correct change is catalog-only:
platform-checkscache_mode: "none"→"pr-isolated", with the affectedci_planfixtures regenerated. Note the sequencing constraint fromci/ci.md§11.1 ("Catalog evolution is a sequenced maintainer merge"): the protected planner compares the PR'sci/slices.ymlbyte-identically against the default-branch copy, so a branch that edits the catalog cannot pass its own Plan gate until that catalog change lands on the protected default branch. The PR will therefore show a red Plan gate by design until the catalog commit is landed; the compare must not be relaxed to work around it.ndizazzo commentedon Oct 26, 2026
Correction to the paths and one value in the comment above
Verified by reading the fixture files directly.
Wrong path. The planner goldens are at
tools/xtask/tests/fixtures/ci_plan/expected/, not.github/fixtures/ci_plan/. Correct references:tools/xtask/tests/fixtures/ci_plan/expected/control-main.plan.jsontools/xtask/tests/fixtures/ci_plan/expected/manual-full-force-all.plan.jsontools/xtask/tests/fixtures/ci_plan/expected/windows-log-store.plan.json,.../native-ffi.plan.json,.../reverse-dependency-log-store.plan.jsonWrong value. I wrote that the PR-profile fixtures show
"platform-checks":"pr-isolated". They do not. Read from the committed goldens:profileplatform-checkssdkcontrol-mainmainnonetrusted-readwritemanual-full-force-allmanual-fullnonetrusted-readonlywindows-log-storepr-readynonenative-ffipr-readynonereverse-dependency-log-storepr-readynoneThis makes the gap wider than I stated, not narrower:
platform-checksresolves tononein every profile, so the slice gets no cache on PRs either, whilesdkon the sameplatform-buildrole getstrusted-readwriteonmain,trusted-readonlyon manual-full, and restore-only isolation on PRs. Points 1, 2, 4, and 5 above are unchanged.One implementation consequence found while preparing the fix. The planner contract cases do not read the live
ci/slices.yml;tools/xtask/tests/migration_ci_plan/support.rsmaterializes each case's manifests fromtools/xtask/tests/fixtures/ci_plan/manifests/<case>/slices.json. So the catalog change has to be mirrored into those fixture manifests and the affected goldens regenerated, otherwise the contract test would keep asserting the oldnonevalue from a stale fixture copy.ndizazzo commentedon Oct 26, 2026
Conclusion: NOT-REPRODUCIBLE on current
main— no fix appliedThe reported behavior does not occur, and the stated mechanism is not connected to the runtime path. No code change and no PR.
1. Current
mainrun shows a warm, read-write cache on this exact slicemain_windows.ymlrun40248201661(branchmain, 2026-10-26T00:00:01Z, success), job121337069666Platform checks (windows-unit):Selector job
121337069602:allow_native_github_cache: true,allow_depot_remote_cache: false.So the Windows platform compile job on
mainalready runs with a read-write GitHub Actions compiler cache at an 80.88% hit rate, not 0.25%.2.
cache_modeis planner metadata; nothing in the runtime path reads itplan.cache_modeshas exactly one consumer in the entire CI surface:.github/workflows/ci-runner-contract-slice.yml:48—jq -e 'all(.cache_modes[]; . != "trusted-readwrite")', a pull-request-profile assertion.No workflow or action reads it. The actual cache decision for this lane comes from
.github/actions/configure-sccache-gha/action.yml, which keys off the event name (pull_request*→ read-only, disk-only; otherwisedisk,ghawithread_write) plusallow_native_github_cache/allow_depot_remote_cachefrom.github/actions/select-ci-runners, wired in.github/workflows/ci-platform-checks-slice.yml:142-144. Changingplatform-checksfromnonetopr-isolatedinci/slices.ymlwould change only the input to that one assertion — zero runtime effect.3. What is actually true
ci/slices.ymlline 248 declaresplatform-checkswithcache_mode: "none"while line 251 declaressdkwithcache_mode: "pr-isolated", both onrunner_role: "platform-build". It is inert metadata, not a cause..github/workflows/ci-platform-checks-slice.ymlboth the sccache install (line 140) and the cache configuration (line 142) are gatedif: ${{ matrix.check.platform == 'windows' }}, so macOS jobs never had sccache regardless of the catalog value.configure-sccache-gha, not the slice catalog. That is a different investigation from the one this issue describes.4. Corrections to my earlier comments on this issue
Restated here so the final record is self-contained.
tools/xtask/tests/fixtures/ci_plan/expected/, not.github/fixtures/ci_plan/.platform-checksresolves tononein thepr-readygoldens too, notpr-isolated.5. Disposition
No source, test, workflow, or catalog change. A regression test asserting
platform-checksplans astrusted-readwriteonmainwas drafted and discarded: it would have pinned planner metadata that no runtime consumer reads, presenting an unused field as a behavioral contract. Catalog and cache policy are unchanged.ndizazzo commentedon Oct 26, 2026
Accuracy amendment to the comment above
I posted that before reading the two maintainer updates on this issue. They are consistent with my measurements, and one of my sentences overreached.
What my evidence does establish. Independently of the earlier measurement,
main_windows.ymlrun40248201661(2026-10-26) logsread_writeGitHub Actions cache andCache hits rate 80.88 %onPlatform checks (windows-unit). That reproduces the maintainer's 80.8% on job118444921110and confirms the Windows cold-build / 0.25%-hit-rate condition no longer occurs onmain. It also confirms the mechanism claim is wrong on current source:plan.cache_modesis consumed only by the pull-request-profile assertion inci-runner-contract-slice.yml, so thecache_mode: "none"catalog entry cannot have caused the original cold build either — the real cause was the missingconfigure-sccache-ghawiring, which #2374 added atci-platform-checks-slice.yml:140-144.What my evidence does not establish. I wrote "the reported behavior does not occur." That is too broad. The duration concern is not disproven by a hit-rate number: the maintainer's measured timings stand —
windows-unit22.9–28.4 min over 10 runs, 24–41 min over the last 12, andRun macOS unit tests~22 min onmain. What changed is where that time goes: test execution, not a cold build.Correction on macOS. I called the Windows-only sccache gate "a deliberate design choice." I had no evidence for intent. The gate is real (
matrix.check.platform == 'windows'at lines 140 and 142), but per the maintainer update the macOS cache question is an open, unmeasured decision —setup-macos-lldstarts sccache on a job-local disk with nothing restored between runs, and the two candidate fixes (aSwatinem/rust-cachestep behindallow_native_github_cache, or dropping the Windows gate) have not been measured. This issue still has that live half.On the catalog entry.
platform-checksstill declarescache_mode: "none"whilesdkdeclarespr-isolatedon the sameplatform-buildrole. Aligning it is a truthful-plan/documentation change that needs a catalog-only maintainer merge, and it will not change any runtime behavior or recover the macOS time.Disposition unchanged: no source, test, workflow, or catalog change from me. Ledger status is recorded as NOT-REPRODUCIBLE for the
cache_modemechanism and the Windows cold-build claim, with the macOS half left open.docs: scope the #2003 finding to the cache_mode premise
Virgile-pct commentedon Nov 1, 2026
Closing, this is fixed on main. Today's Main · Windows run (41291374619) has Platform checks (windows-unit) on a read_write cache at 90.48% hits, and the last runs take 7 to 8 min against 21 min when I opened this. Thanks Nick for tracking it down.