Repository navigation
ci: add a schema-3 ci.toml bounding the Actions cache - #52
Merged
Merged
Conversation
wild held 4.58 GiB across 26 live cache entries (46% of the 10 GiB repository limit) with no ci.toml, so nothing bounded how many entries any family could accumulate. Declares the four families setup-soldr actually writes, with per-shape ceilings where entries within a family differ in size: cook cook-base-v2-* 3 entries 1653 MB evict=lru compile setup-soldr-buildcache-v2-* 3 entries 790 MB evict=lru registry setup-soldr-cargoregistry-v1-* 3 entries 92 MB soldr-mini soldr-mini-v2-* 3 entries 29 MB compile's entries span 114 MB (linux-x64) to 424 MB (macos-arm64); a single `max` would over-count 3.7x, so both large families declare `shapes` and their footprint is the honest sum. Every ceiling is at or above the observed live maximum -- `ci-lint cache janitor` LRU-evicts down to exactly family_footprint(), so under-stating truncates live caches. [v0-rust-* (14 entries, 2122 MB) is deliberately NOT declared: no via in ci_lint.cache.families.ALLOWED_VIA_VALUES resolves to that prefix. It is Swatinem/rust-cache's own default, and CACHE-025 bans that action outright. Removing the three steps is tracked in #19.] `[cache.promote] mode = "off"`: setup-soldr#566 is merged but unreleased, so there is no shipped ancestor mechanism to opt into. Also adds [workspace.metadata.soldr].targets to Cargo.toml, which CT-006 requires ci.toml's [platforms] to agree with. Verified: zero schema findings; CACHE-004/029/030 clean; the live janitor dry-run proposes zero deletions from all four declared families.
wild's `tidy_tests::check_toml_format` runs taplo over the repository's TOML, so an unformatted ci.toml fails `check_toml_format` and with it the six `Test Linux (...)` jobs, `minimal-versions`, `reuse-check` and `Nix/wild` -- nine red jobs from one formatting difference. taplo collapses the aligned `=` to single spaces, which is the whole change; no key or value is altered.
`fsfe/reuse-action` (the `reuse-check` job) verifies every file carries REUSE licensing metadata. The new `ci.toml` had none and was not listed in REUSE.toml's annotations, so the compliance check failed -- a licensing failure, not a CI one. Inherits the repository's existing annotation: MIT OR Apache-2.0, Copyright 2024-2026 Wild Linker Contributors.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
ci.toml(schema 3) so wild's GitHub Actions cache has declared family boundaries and a budget, plus the[workspace.metadata.soldr].targetstable CT-006 cross-checks it against.Nothing is deleted by this PR. No cache is touched, and no workflow is edited.
Why
Measured 2026-10-05 (paginated
actions/caches, after a reclaim): 26 entries, 4.58 GiB = 46% of GitHub's 10 GiB repository limit — the last fleet repository above 40% with noci.tomlat all. With no[cache.family]table, nothing bounded how many entries a family could accumulate.Families: measured, then declared
viacooksetup-soldr:cookshapes700/660/420 MB,evict = "lru"compilesetup-soldr:build-cacheshapes140/460/290 MB,evict = "lru"registrysetup-soldr:cargo-registrymax = "35MB",per = "os"soldr-minisetup-soldr:soldr-minimax = "12MB",per = "os"Why
shapeson the two large familiesci-lint cache janitorLRU-evicts anevict = "lru"family down tofamily_footprint(), which is the sum ofshapeswhen declared, elsemax × cardinality(per). CACHE-004's static proof uses the same number. wild's entries differ sharply within a family:compile: 113.9 MB (linux-x64) / 423.7 MB (macos-arm64) / 252.6 MB (windows-x64) — a 3.7x spreadcook: 666.4 / 616.3 / 370.6 MB — 1.8xOne
maxper family would model424 × 3 = 1271 MBfor a family that actually occupies 790 MB. Per-shape ceilings give the honest sum. Every ceiling is at or above the observed live maximum for that shape; over-stating only costs headroom, while under-stating truncates live caches.registryandsoldr-miniare uniform across hosts (31.0/30.9/30.4 and 10.3/10.1/8.6 MB), so a single ceiling each is truthful.Both shaped families also declare
per = "os". That is not padding: setup-soldr's prefixes embed${runnerOs}-${runnerArch}, so these families really are one entry per runner OS (3), andci_lint.cache.audit's live CACHE-004 model check readsper(it does not readshapes). Without it the live check computescardinality(per=None) × 2 = 2against 3 live entries and fires two spurious findings —cookas a hard violation,compileas needs-review. Withper = "os"both clear, and the footprint arithmetic is unchanged becausefamily_footprint()prefersshapes.Budget arithmetic
steady 2811 MB vs budget 9.5 GB. The lockfile-change peak is counted rather than waived: no writer flow declares
pre-prune = true, because wild runs noci-lint cache preprunestep today and claiming otherwise would be a false statement about the YAML. The honest arithmetic fits comfortably either way.Live audit (
ci-lint cache audit --repo .)Zero CACHE-004 findings. The only remaining findings are the undeclareable family below, plus CACHE-008 (six
v0-rust-*entries sitting on the merge refs of already-closed PRs #28/#31 — the janitor reclaims those safely on its next sweep, again not by this PR) and the GEN-009 rollup that cites them.Janitor dry-run — the check that matters
ci-lint cache janitor --repo . --dry-runagainst the live repository:Zero deletions from all four declared families —
before(n) == after(n)andbefore(B) == after(B)for every one. The 14 the dry-run would delete are exactly the undeclaredv0-rust-*entries, which is the correct signal: they are the ones nothing declares.This check is why the numbers above are a table rather than a summary. A previous adopter's first draft put a family's ceiling below live and static CACHE-004 passed it anyway; only the live dry-run caught it.
v0-rust-*— undeclareable, and the reason14 entries, 2122.0 MB, 45% of the repository's cache. Deliberately not declared.
ci_lint.cache.families.ALLOWED_VIA_VALUEScontainsci-lintplus the setup-soldr/setup-uv shapes, and none of them resolves to av0-rust-prefix. Verified by reading the shape table: the prefixes arecook-base-v2-,setup-soldr-buildcache-v2-,setup-soldr-cargoregistry-v1-,soldr-mini-v2-,setup-soldr-targetcache-,setup-uv-2-and the rest.v0-rust-is Swatinem/rust-cache's own default, fromcore.getInput("prefix-key") || "v0-rust"in itssrc/config.ts:74.And CACHE-025 bans
Swatinem/rust-cacheoutright — unwaivable, per the maintainer decision of 2026-10-02 (docs/policy-rust.md, zackees/ci.yml#209): no[[exceptions]]entry, no# ci-lint: allowcomment, no benchmark-baseline carve-out.ci-lint precheckcurrently reports three CACHE-025 violations in.github/workflows/ci.yml(lines 62, 83, 274).So there is no honest
viato declare, and inventing one would make a number fit at the cost of a false statement in the config. The correct disposition is to delete the threeSwatinem/rust-cache@v2steps, which removes the writer and makes the 2122 MB legitimately reclaimable. That is already tracked in #19 ("stop caching Rust toolchains in wild CI") and is deliberately not done here — it is a workflow change with real cold-start consequences, out of scope for a cache-policy PR.Until then these entries stay reported as CACHE-001, and
ci-lint cache janitortreats them as deletable. That is the intended behaviour and the reason to close #19.Other things this file does not claim
[cache.promote] mode = "off". setup-soldr#566 (ancestor-cache.ts,auto-key) is merged but unreleased;auto-keydefaults to"false"and no fleet repository has a single livesetup-soldr-ancestor-build-v1-*entry. Declaringmode = "ancestor"would trip CACHE-030needs_reviewon every run and stand as an invitation to opt into a pilot this repository cannot run.[local.gate]. wild has no local gate — nolocal-gate.tomlat the repo root, and nolocal-gatereference inAGENTS.md(both checked 2026-10-05). The table is deliberately absent, not empty:ci_lint.local_gate._load_gate_configonly prefers ci.toml's[local.gate]when the table exists, so omitting it leaves the "no gate configured" reading intact.write-on = ["main"],pr = { mode = "none", ..., budget = "0MB" }. PRs restore and never save.[publish.pypi]. wild ships a Rust binary and a Nix package, not a wheel.[rust]table. Declaring one obliges the file to also answer forpublic/private/shipand the full test-target inventory — a workspace-wide statement outside a cache-policy change. wild publishes every workspace crate to crates.io (RELEASING.md: "Runcargo publishfor each package"), so it has no public/private split to declare truthfully. The one thing RUST-005 asks for is waived with a dated[[exceptions]]entry: wild has exactly one integration-test target (wild/tests/integration_tests.rs,harness = false) — already at the floor, nothing to consolidate.[platforms]and the Cargo.toml additionTen platforms, every one a job that really exists in
.github/workflows/ci.yml:linux-x64,linux-arm64,linux-riscv64,linux-loong64,linux-ppc64le,linux-x64-musl,linux-arm64-musl,linux-wasm32,macos-arm64,windows-x64. The glibc/musl pairs come from the CI container images'rustup target addlines (docker/ci/*.Dockerfile), the cross triples from thelinux-cross-buildmatrix, andwasm32-wasip1from thewasm-testjob.CT-006 requires
[platforms]'s target set and[workspace.metadata.soldr].targetsto be identical, so this adds that 22-line table toCargo.toml. It is the single source of truth for the shipping matrix (it is whatsoldr prepare --target allreads) and is inert metadata otherwise.Two smaller notes on the declarations themselves:
[platforms].*.runs-onuses the fleet-pinned labels (macos-15,windows-2025), not themacos-latest/windows-latestthe workflows currently use. RUN-001 only resolvesruns-on: ${{ matrix.<var>.runs_on }}, and ci.toml declares the target state. Pinning the workflows to match is a follow-up.[allow].setup-soldr.only-in = ".github/workflows"names the location that actually exists — wild has no.github/actions/soldrwrapper and callszackees/setup-soldr@v0directly from eleven places. Declaring the preferred-but-absent path would fire CACHE-009/RUST-001 eleven times on a gap this PR does not close. Folding the calls into a wrapper composite action is the follow-up.Validation
The remaining
precheckfindings (SEC-004 SHA pinning, TOOL-001/RUST-001 barecargo, GEN-005, CACHE-013, WF-*, TAG-003, GATE-012) are pre-existing properties of wild's existing workflows and Cargo.toml, not introduced here. LAYOUT-001 and RUST-005 were introduced by this file's own declarations and are resolved: LAYOUT-001's selector list cannot distinguish host from target selection, so two target-selection files (libwild/src/args/elf.rs'sdefault_emulation(),linker-diff/src/utils.rs's objdump tests) are listed in[allow].platform-codewith the reasoning inline.🤖 Generated with Claude Code