Skip to content

fix(ci): drop the unhonoured pre-prune cache-policy waiver (CACHE-034) - #1329

Draft
zackees wants to merge 1 commit into
mainfrom
ci-cache-034-preprune-waiver
Draft

zackees wants to merge 1 commit into
mainfrom
ci-cache-034-preprune-waiver

Conversation

@zackees

@zackees zackees commented Oct 5, 2026

Copy link
Copy Markdown
Owner

Problem

ci.toml declared pre-prune = true on both writer flows ([flow.main] and [flow.nightly]), but no workflow in this repository ever runs ci-lint cache preprune. The declaration was an unhonoured waiver: ci_lint's CACHE-004 arithmetic honours it by dropping the lockfile-change peak from the worst-case footprint, so running-process's modelled cache footprint was understated by exactly that peak term, for free.

This is the finding from ci.yml PR #352 / rule CACHE-034.

Why option (A) — adding the pre-prune step — was not chosen

The instructions preferred (A) "if a writer workflow is a normal place to add the step AND it would actually run before saves." It is not, here:

  • The push:main writer flows are not one workflow. A single push fans out across five independently-triggered workflows, each saving its own setup-soldr cache:
    • ci.yml (via ci-preflight.yml / ci-preflight-rust.yml / coverage.yml)
    • dependency-check.yml, proto-breaking.yml
    • security-audit.yml (save-cache on main, line 72)
    • security-fuzz.yml (save-cache on main, line 108)
  • Two of the declared families are lockfile-keyed (compile, dylint-out) — those are exactly the ones whose writes create the peak.
  • GitHub Actions has no cross-workflow barrier. A prune job added to any one of these runs cannot be ordered ahead of the other four.
  • cache-budget.yml is the only job that can see the whole account, and it already runs after the writers — it needs: the platform lanes. That is a post-hoc trim, not a pre-prune.

This is a capability gap, not a workaround I chose to skip: until ci-lint/GitHub Actions has a way to order a prune ahead of independently-triggered writers, pre-prune = true cannot be truthfully declared by a repository in this shape. Filing that as a note here rather than working around it.

Change

Removed pre-prune = true from [flow.main] and [flow.nightly], with a comment recording why and why it cannot simply be re-added. [cache].budget is unchanged at 9GB. No numbers were invented.

CACHE-004 arithmetic — before and after

Both flows resolve via resolve_flow to cache = "write"; verified pre_prune was True for main and nightly before the change (so the waiver did apply to every writer flow and the peak was being waived).

line before (pre-prune = true) after (waiver removed)
steady total 11,036,262,400 B 11,036,262,400 B
+ lockfile-change peak 9,542,041,600 B 9,542,041,600 B
+ [cache.pr].budget 0 B 0 B
formula applied worst = steady + [cache.pr].budget (every writer flow pre-prunes: lockfile peak waived) worst = steady + lockfile-change peak + [cache.pr].budget (not every writer flow pre-prunes)
= worst case 11,036,262,400 B 20,578,304,000 B
budget ([cache].budget) 9,663,676,416 B 9,663,676,416 B

The CACHE-004 violation, honestly

CACHE-004 was already a VIOLATION before this change. The steady total alone (11,036,262,400 B) exceeds the 9GB budget (9,663,676,416 B). The waiver was not what kept this check green — it was already red. So this PR does not turn a passing check red; it corrects an understated number on an already-failing check.

After the change CACHE-004 reports:

cache budget exceeded: worst case 20578304000 B > budget 9663676416 B
(worst = steady + lockfile-change peak + [cache.pr].budget
 (not every writer flow pre-prunes))

I have deliberately not lowered family max sizes to force this to pass. The real question this surfaces is upstream of CACHE-004: running-process's declared family shape (compile at 1400MB x 6 platforms = 8.8 GB steady) does not fit a 9 GB budget no matter what the peak does. That is a cardinality/max decision for the repository owner, not something to paper over in a waiver-removal PR.

Verification

uvx --from "git+https://github.com/zackees/ci.yml@92106df315bd28de24ef1808c893c91a5859122d" \
  ci-lint precheck --repo . --local
  • CACHE-004: VIOLATION before and after (see above).
  • CACHE-034: not reported by this ci.yml revision — the rule is still being landed under ci.yml PR ci: parallelize release fuzz evidence runs #352. This PR is the remediation it asks for.

Unresolved

  • The 1,732 pre-existing violations from precheck in this repository are untouched by this PR and out of scope.
  • running-process has a local-gate.toml; no Local-Gate: trailer is attached to this commit. If the gate requires one, this PR will need a re-run of python3 -m ci_lint local-gate run on the branch. Not fabricated.

🤖 Generated with Claude Code

Both writer flows ([flow.main] and [flow.nightly]) declared
`pre-prune = true`, but no workflow in this repository ever runs
`ci-lint cache preprune`. ci_lint's CACHE-004 arithmetic honours the
declaration by dropping the lockfile-change peak from the worst-case
footprint, so the modelled footprint was understated by 9,542,041,600 B
for free.

Option (A), adding a `ci-lint cache preprune --lockfile-changed` step to
a writer flow, is not expressible here: the push:main writer flows fan
out across five independently-triggered workflows (ci.yml,
dependency-check.yml, proto-breaking.yml, security-audit.yml,
security-fuzz.yml), and GitHub Actions has no cross-workflow barrier to
order a prune ahead of all of them. cache-budget.yml is the only job
that can see the whole account, and it already runs *after* the writers
(it `needs:` the platform lanes), which is a post-hoc trim.

So the waiver is removed and the peak is counted honestly.

CACHE-004 was ALREADY a violation before this change (steady total
11,036,262,400 B alone exceeds the 9,663,676,416 B budget), so this does
not newly break a green check -- it corrects an understated number. The
worst case is now 20,578,304,000 B.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@zackees

zackees commented Oct 5, 2026

Copy link
Copy Markdown
Owner Author

CACHE-034 is now merged — zackees/ci.yml#352 (docs #353). It fires on this repository's main today:

flow(s) 'main', 'nightly' declare pre-prune = true, which waives the lockfile-change peak from CACHE-004's worst case, but no workflow, composite action, or ci/ script invokes ci-lint cache preprune

So the remediation in this PR is now a rule ci-lint enforces, not just a review finding. Verified against merged main (dee1c2c6) with ci-lint precheck --repo . --local.

Two things I confirmed independently

CACHE-004 was already a VIOLATION before this change — 11,036,262,400 B against a 9,663,676,416 B budget, with the waiver applied. The waiver was not keeping the check green; the check was already red. This PR corrects an understated number on a failing check rather than breaking a passing one, which is the right order to do things in.

The choice of (B) over (A) is correct here. [flow.main] fans out across independently-triggered workflows (ci.yml, dependency-check.yml, proto-breaking.yml, security-audit.yml, security-fuzz.yml), each saving its own setup-soldr cache. GitHub Actions has no cross-workflow barrier, so no single job can order a prune ahead of all of them, and cache-budget.yml runs after the writers — a post-hoc trim, not a pre-prune. Declaring pre-prune = true anyway was the fiction.

The real blocker underneath

compile at 1400 MB × 6 platforms = 8.8 GB steady does not fit a 9 GB budget regardless of the peak. Even fully honestly declared, running-process's cache shape is over budget. That is a cardinality/max owner decision, not something to paper over — the same wall zackees/clud#1800 hit.

Held as a draft deliberately: it needs an owner decision on the family sizes before it can go green, and no Local-Gate: trailer has been fabricated.

@zackees

zackees commented Oct 5, 2026

Copy link
Copy Markdown
Owner Author

One correction to my earlier recommendation: I said option (A) — adding the pre-prune step — was preferred. For running-process that option is not currently expressible, which your own analysis established and I should not have talked past.

[flow.main] fans out across five independently-triggered workflows, each saving its own setup-soldr cache, and GitHub Actions has no cross-workflow barrier. No single job can order a prune ahead of all of them — so no arrangement of steps in one workflow fixes it.

Filed the shared prerequisite as zackees/ci.yml#354, covering soldr, bosn and running-process, which all hit the same wall for structural reasons rather than by omission.

This does not change the recommendation to land it. running-process's honest worst case (19.19 GiB) is over budget, but so is its steady state (11.04 GB) — the waiver was not what made CACHE-004 fail. This PR makes the real number visible; the cardinality decision that follows is the actual work.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant