setup-pm-cache.test.mjs compared `if:` expressions as literal strings and
indexed `build-${platform}-${arch}-{release,commit}` by id. So the per-arch
split, or rewording a gate, broke it while the cache contract still held.
- A small evaluator for the Actions expression subset. Gates are asserted by
how they behave:
- The exact-key wheel save runs only for callers with extras or a test
environment, and never together with the rolling restore.
- The prune runs after a failure but not on cancel.
- The upload needs a successful prune.
- Desktop build legs are the jobs that use the desktop-build-cache action,
keyed by matrix target and cache-mode. A new check requires a write leg and
a read leg for every native target. The write leg runs only for tag builds;
the read leg runs for commit and channel builds.
- Candidate saves are evaluated: they run after a successful prepare of a
trusted dispatch (a tag build, or a main push for the payload). They do not
run on a failed prepare, a cancel, commit or channel builds, pull requests,
other branches, or a foreign ref.
- Selection gates are found by SELECTED_BUILD_SUCCEEDED. Each needs validate
plus one write and one read leg of a single target, and refuses a failed
admission. The selection logic and the "only gates consume legs" invariant
are covered in tests/ci/test_desktop_bundle_smoke.py.