Skip to content

fix(ci): cache Go modules once, not once per compile flavor - #446

Merged
EricAndrechek merged 19 commits into
mainfrom
ci-cache-split
Aug 11, 2026
Merged

fix(ci): cache Go modules once, not once per compile flavor#446
EricAndrechek merged 19 commits into
mainfrom
ci-cache-split

Conversation

@EricAndrechek

@EricAndrechek EricAndrechek commented Aug 10, 2026

Copy link
Copy Markdown
Member

Why

The repo hit 10.53 GB against GitHub's hard 10 GB Actions cache cap after #438's 24-module bump. Past the cap GitHub LRU-evicts, so warm entries disappear mid-run and builds get slower and less predictable — silently.

setup-env cached the Go module cache and build cache together under a per-flavor key:

path: |
  ~/go/pkg/mod        # pure function of go.sum — identical for every flavor
  ~/.cache/go-build   # genuinely flavor-specific
key: gobuild-v2-<os>-go<suffix>-<go.sum hash>

~/go/pkg/mod measures 1.6 GB on disk for the current go.sum and is byte-identical across all five suffixes, so it was stored five times over — five entries of ~0.9–1.2 GB each, ~5.2 GB per generation. Two live generations is the normal steady state (a bump mints a new set while the previous is still warm), so ~10 GB was the expected footprint. #438 tipped it over:

1210MB  gobuild-v2-Linux-go-lint-136f5059…
1068MB  gobuild-v2-Linux-go-unit-136f5059…
1067MB  gobuild-v2-Linux-go-integration-136f5059…
1058MB  gobuild-v2-Linux-go-unit-1a18a4a1…      <- previous generation
1033MB  gobuild-v2-Linux-go-e2e-cov-136f5059…
 929MB  gobuild-v2-Linux-go-cov-1a18a4a1…       <- previous generation
 928MB  gobuild-v2-Linux-go-cov-136f5059…

The action's header already noted the duplication — "Cross-suffix restore-keys still share the (identical) module cache on a cold start" — without drawing the sizing conclusion.

What

Split the one cache into two:

key path scope
modules gomod-v1-<os>-<go.mod+go.sum hash> ~/go/pkg/mod unsuffixed — one entry, every Go job
build objects gobuild-v3-<os>-go<suffix>-<go.mod+go.sum hash> ~/.cache/go-build per compile flavor, as before

Measured on this branch's own runs: 5.18 GB → 1.05 GB per generation (a 4.9× reduction) — gomod-v1 at 0.48 GB plus five gobuild-v3 entries totalling 0.57 GB (25–152 MB each). Two generations now fit with room to spare.

All sizes are stored-archive bytes ÷ 2³⁰, the unit the README's own usage check prints.

(The 0.48 GB module entry is a cold first save with no restore-key fallback; it drifts up as superseded module versions accumulate through the restore→save chain, so budget nearer ~1 GB for it in steady state.)

Two details worth review attention:

  • v3 on the build key is required. Saves fire only on an exact-key miss, so without the bump the old v2 entry — which still contains the module cache — would exact-hit forever and the new, smaller content would never be saved. Same reasoning as the v2 bump documented at the top of the action.
  • gobuild-v3 drops the bare-prefix restore-key. gobuild-v2-<os>-go- existed to borrow another flavor's copy of the shared module cache on a cold start. That job now belongs to gomod-v1, and another flavor's build objects aren't reusable here, so the fallback would only restore bytes that get thrown away.

gomod-v1 keeps a prefix restore-key: a bump moves a handful of modules, so a stale generation is still worth restoring and go mod download fetches only the delta.

Both keys hash go.mod as well as go.sum (CodeRabbit review). GOTOOLCHAIN=auto lands the toolchain in ~/go/pkg/mod/golang.org/toolchain and go.sum records no entry for it — this repo's go.sum has zero golang.org/toolchain lines. A go-directive bump would therefore leave a go.sum-only key byte-identical (verified: bcc16701da2c001f before and after go 1.26.51.27.0), exact-hit a toolchain-less archive, and — saves firing only on an exact-key miss — never save the freshly fetched toolchain, re-downloading it every run until some unrelated dependency bump moved go.sum. The same bump also invalidates every cached build object, since the compiler build ID feeds every action hash.

The sixth copy (from review)

Consolidating five copies left a sixth outside setup-env entirely: actions/setup-go caches ~/go/pkg/mod + ~/.cache/go-build by default, so publish-dev.yml carries a live 0.97 GB entry (keyed on the root go.mod — setup-go hashed go.sum through v6.2.0 and go.mod from v6.3.0, actions/setup-go#705) — larger than the gomod-v1 entry this PR consolidates to, and a direct violation of the sizing rule the PR introduces. It is re-saved on each cache miss (every dependency bump), so the cost is ~1.95 GB across the two generations the repo holds in steady state. release.yml carried the same default.

Both now pass cache: false, matching the call goreleaser-validate.yml already made.

But publish-dev.yml re-caches the half that pays for itself. Reviewing this surfaced a measured regression: across its last 20 runs, GoReleaser takes 36–246 s with setup-go's cache warm and 401–446 s cold — zero overlap between the two groups. Dropping it outright would cost roughly 2.5–7 minutes (mean delta ≈4.8 min) on every push to main, and the value is entirely in the ~/.cache/go-build half (8-target cross-compile), not the module tree.

So that job now caches ~/.cache/go-build alone under gobuild-v3-<os>-go-release- (~0.5 GB instead of ~0.97 GB). The duplicate module tree — the actual #443 complaint — is gone; the cross-compile stays warm.

And it keeps the module tree warm too. The 36–246 s timings were measured with setup-go's bundled entry, which held ~/go/pkg/mod as well — so caching only the build half would have left the module tree cold on every push (~90 modules, ~112 MB re-downloaded) and landed the job above its own documented range. publish-dev therefore also restores gomod-v1 via actions/cache/restore: read-only, reading ci.yml's entry from main's scope. It writes nothing, so it costs 0 GB of budget and — importantly — cannot write a partial module tree to the key every ci.yml Go job shares. The -release suffix keeps those objects separate from CI's native-only flavors, which can't use them.

release.yml keeps the plain opt-out — and re-enabling it there would be strictly negative, not merely unhelpful: cache writes are scoped to the ref that made them, so a save from refs/tags/v1.0.0 can never be read by refs/tags/v1.0.1, by main, or by a PR — only by a re-run of that same tag. It would be a ~1 GB entry per release that nothing but a retry can ever read. If release wall-clock ever matters, the lever is actions/cache/restore (restore-only) on publish-dev's key.

Docs

.github/workflows/README.md gets the updated inventory rows plus a sizing policy section — the 10 GB cap, the two-generations rule, the gh api one-liners to check the current footprint, and the rule that content which is a pure function of a lockfile gets keyed once, unsuffixed. That's the part that stops this recurring.

Two additions from review:

  • A narrowing-rotation exception to the key-versioning policy. The existing policy says to keep old prefixes as transitional restore-keys; gobuild-v3 deliberately doesn't, because a v2 archive still contains ~/go/pkg/mod and restoring it would re-materialize exactly what the rotation removes. The doc now prescribes what the code does.
  • The CodeQL caches are listed. codeql-dependencies-* / codeql-overlay-base-database-* (~0.4 GB) are minted by GHAS default setup, outside this repo's workflows. They were invisible in the inventory, so a maintainer doing the two-generations check was seeing ~85% of the real budget.

Verification

  • make ci green on this tree (full pipeline incl. integration + e2e)
  • make verify clean — markdownlint over the README + CHANGELOG, and actionlint over .github/workflows/**.
    Note: make lint-gha globs workflows only, so .github/actions/setup-env/action.yml gets no actionlint and no shellcheck — pointed at it directly, actionlint rejects a composite action as a malformed workflow. The new guard step's inline run: is therefore hand-verified, not tool-verified: the if: predicate is byte-identical to the two actions/cache steps' own conditions, and all 8 call sites were audited (5 suffixed, 3 go: "false").
  • Both pre-push reviewers run, no skips
  • No change to what any job does; only which cache keys hold which paths

Expect the first run on main after merge to be a cold miss on both new keys (one-time repopulation), then warm. Don't read that run's timing as a regression.

Post-merge

Purge the orphaned entries — the five dead gobuild-v2-* (5.18 GB) and the setup-go-* entry (0.97 GB) that cache: false orphans. Nothing restores or refreshes either family after this lands. The repo is at 9.27 GB / 10 GB across 24 entries with them still resident. This branch's own runs add a ~1.05 GB generation on the PR ref (pre-merge peak ~9.3 GB), and merging adds another ~1.05 GB generation plus the ~0.5 GB release cache on main — so if the PR-scope entries haven't been reclaimed yet the transient peak is ~10.3 GB, over the cap this PR exists to defend. Purge immediately at merge, not later — this is load-bearing, not housekeeping. The orphans would clear on the 7-day idle sweep, but not necessarily before the next dependency bump.

gh api repos/Wave-RF/WaveHouse/actions/caches --paginate \
  -q '.actions_caches[]|select(.key|startswith("gobuild-v2-") or startswith("setup-go-"))|.id' \
  | xargs -I{} gh api -X DELETE repos/Wave-RF/WaveHouse/actions/caches/{}

Do this after merge, not before — main still uses the v2 keys until then, so an early purge just forces a cold repopulate of caches we're about to abandon.

Notes

  • GitHub's LRU eviction reclaimed the previous generation on its own mid-investigation (10.53 GB → 7.19 GB), so this isn't currently breaking builds — it recurs on the next dependency bump. Usage has since climbed to 9.27 GB as this branch's runs added entries, which is why the post-merge purge above matters.
  • Pre-existing docs drift surfaced by the docs-reviewer gate (unrelated to this branch) is tracked in docs: development.md drifted from Makefile; make verify needs pnpm #444 rather than folded in here.

Closes #443

🤖 Generated with Claude Code

EricAndrechek and others added 4 commits August 10, 2026 15:53
~/go/pkg/mod is a pure function of go.sum — byte-identical for every
compile flavor — but it was cached together with ~/.cache/go-build under
a key partitioned by go-cache-suffix. That stored the same 1.6 GB five
times (-lint, -unit, -integration, -e2e-cov, -cov), ~5 GB per go.sum
generation. Two live generations is the steady state (a bump mints a new
set while the previous is still warm), so the repo sat at ~10 GB against
GitHub's hard 10 GB cap; #438's 24-module bump tipped it to 10.53 GB and
GitHub began LRU-evicting warm entries mid-run.

Split into gomod-v1 (~/go/pkg/mod, unsuffixed, shared by every Go job)
and gobuild-v3 (~/.cache/go-build only, still per flavor). ~5 GB -> ~2 GB
per generation, so two generations fit with headroom.

The v3 bump is required: saves fire only on an exact-key miss, so without
it the old v2 entry — still carrying the module cache — would exact-hit
forever and the smaller content would never be saved. gobuild-v3 also
drops the bare-prefix restore-key, which existed only to borrow another
flavor's copy of the module cache; that job is now gomod-v1's, and
another flavor's build objects aren't reusable.

Documents the sizing constraint in the workflows README so the next cache
addition budgets for two generations against the 10 GB cap.

Closes #443

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
Review follow-up. The split consolidated five copies of ~/go/pkg/mod but
left a sixth outside setup-env: actions/setup-go caches by default, and
publish-dev.yml runs on every push to main, so its go.sum-keyed entry was
~1 GB live — more than the gomod-v1 entry this PR consolidates to, and a
direct violation of the sizing rule the PR adds. release.yml carries the
same default. Both now pass cache: false, matching the call
goreleaser-validate.yml already made.

Also documents what the inventory was hiding: the CodeQL caches GHAS
default setup mints outside this repo's workflows (~0.4 GB), so a
maintainer doing the two-generations check from the table sees the whole
budget rather than 85% of it.

Adds the narrowing-rotation exception to the key-versioning policy. The
policy said to keep old prefixes as transitional restore-keys; gobuild-v3
deliberately does not, because a v2 archive still carries ~/go/pkg/mod
and restoring it would re-materialize exactly what the rotation removes.
The doc now prescribes what the code does.

CHANGELOG entry for the whole change per AGENTS.md Documentation Sync.
Pre-existing docs drift the gate surfaced is tracked in #444, not folded
in here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
Review follow-up. The sizing policy mixed on-disk size with stored-archive
size, so the arithmetic it tells the next maintainer to perform didn't
close: ~1.6 GB (a du of ~/go/pkg/mod) times five entries is 8 GB, not the
~5 GB quoted. What counts against the 10 GB cap is the compressed entry.

Live API data: the five gobuild-v2 entries measure 0.97-1.27 GB each
(5.57 GB total) and the setup-go entry holding the same module tree is
1.045 GB. So the tree is ~1.6 GB on disk and ~1 GB stored, and a
generation is five entries of ~1.1 GB — ~5.5 GB.

Budget statements now quote stored sizes, with the on-disk figure kept
only where it explains what the directory actually contains. Same wording
in the action header, the README table and policy, and the CHANGELOG.

Also rewords "a seventh copy" of the setup-go cache, which contradicted
the "sixth copy" in the CHANGELOG and the previous commit subject; the
ordinal depended on whether you counted pre- or post-split, so it now
just says it duplicates what gomod-v1 holds once.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
No content change. 1f18ead inserted the stored-archive figures without
re-wrapping, leaving a 39-char orphan line mid-paragraph in the setup-env
comment block and a 20-char one in the README sizing policy, both inside
paragraphs that otherwise wrap at ~72 cols.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
Copilot AI lite review requested due to automatic review settings August 10, 2026 20:56
@github-actions github-actions Bot added github_actions Pull requests that update GitHub Actions code area/docs Documentation, site/, README area/infra CI, build, deploy, Docker, release labels Aug 10, 2026
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Chores

    • Improved CI caching by separating shared Go modules from per-build compilation data.
    • Isolated build caches by compilation configuration for more reliable reuse.
    • Disabled redundant Go caching in publishing and release workflows.
    • Ensured coverage reporting downloads required Go modules before generating reports.
  • Documentation

    • Updated cache guidance, storage limits, inspection instructions, and rotation details.
    • Documented revised CI caching behavior and cache-key management in the changelog.

Walkthrough

The CI cache architecture separates shared Go module data from per-flavor build objects. Publish workflows disable setup-go caching. Documentation, the changelog, and the coverage target describe the updated cache and module-download behavior.

Changes

Go cache architecture

Layer / File(s) Summary
Separate Go cache storage
.github/actions/setup-env/action.yml
The setup action caches ~/go/pkg/mod under shared gomod-v1 keys. It caches only ~/.cache/go-build under suffix-specific gobuild-v3 keys. Go jobs now require an explicit cache suffix.
Workflow cache integration
.github/workflows/publish-dev.yml, .github/workflows/release.yml
Release workflows disable bundled setup-go caching. The development publish workflow adds a release-scoped build cache and restores the shared module cache without saving it.
Cache documentation and coverage setup
.github/workflows/README.md, CHANGELOG.md, Makefile
Documentation records cache ownership, rotation rules, budget guidance, inspection commands, and suffix requirements. The changelog records the cache changes. The cov target now downloads Go modules first.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: taitelee, jfwoods

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes satisfy issue #443 by separating module and build caches, removing duplicate setup-go caching, and documenting cache limits and cleanup.
Out of Scope Changes check ✅ Passed The Makefile, changelog, workflow documentation, and coverage setup support the cache objectives and do not introduce unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title clearly and concisely summarizes the main change: consolidating Go module caching across compile flavors.
Description check ✅ Passed The description directly explains the cache split, workflow changes, rationale, verification, documentation, and cleanup requirements.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci-cache-split
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch ci-cache-split

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reduces GitHub Actions cache pressure by separating the Go module cache (shared across all compile “flavors”) from the Go build object cache (still flavor-specific), preventing redundant storage that was pushing the repo past GitHub’s hard 10 GB cache cap and triggering LRU evictions.

Changes:

  • Split setup-env caching into two keys: an unsuffixed ~/go/pkg/mod cache (gomod-v1) and a per-flavor ~/.cache/go-build cache (gobuild-v3), with key-version bumps to ensure new content is actually saved.
  • Disable actions/setup-go’s default caching in release-oriented workflows (publish-dev.yml, release.yml) to avoid minting an additional redundant ~1 GB cache entry.
  • Update workflow documentation to reflect the new cache inventory and add an explicit sizing/keying policy to prevent recurrence.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
.github/actions/setup-env/action.yml Splits Go module vs build-object caches into separate keys and updates restore-key strategy accordingly.
.github/workflows/publish-dev.yml Disables actions/setup-go cache to avoid an extra go.sum-keyed duplicate cache entry on every push to main.
.github/workflows/release.yml Disables actions/setup-go cache for tag-triggered releases to avoid redundant cache budget usage.
.github/workflows/README.md Updates cache inventory and documents key-versioning + sizing policies, including the “narrowing rotation” exception.
CHANGELOG.md Records the cache-splitting fix and its motivation/impact under “Fixed”.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

📚 Docs preview is livehttps://538bec56-wavehouse-docs.wave-rf.workers.dev

  • Commit7aa2326: docs(ci): the 3-6.5 min claim doesn't follow from its own numbers
  • Author@EricAndrechek, Claude Opus 5 (1M context)
  • Committed — 2026-08-11 08:22 (UTC-04:00)
  • Deployed — 2026-08-11 09:12 EDT

@github-code-quality

github-code-quality Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: Go

Go

The overall coverage in commit 7aa2326 in the ci-cache-split branch remains at 90%, unchanged from commit b66bbe5 in the main branch.

Show a code coverage summary of the most impacted files.
File main b66bbe5 ci-cache-split 7aa2326 +/-
internal/stream/metrics.go 100% 95% -5%

Updated August 11, 2026 13:12 UTC

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 10fb7386-4b4c-411f-b570-e11f83210410

📥 Commits

Reviewing files that changed from the base of the PR and between b66bbe5 and b475d94.

📒 Files selected for processing (5)
  • .github/actions/setup-env/action.yml
  • .github/workflows/README.md
  • .github/workflows/publish-dev.yml
  • .github/workflows/release.yml
  • CHANGELOG.md
📜 Review details
⏰ Context from checks skipped due to timeout. (12)
  • GitHub Check: E2E tests
  • GitHub Check: Coverage
  • GitHub Check: Docs build
  • GitHub Check: Unit tests
  • GitHub Check: Integration tests
  • GitHub Check: copilot-pull-request-reviewer
  • GitHub Check: Lint
  • GitHub Check: Validate snapshot build
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-06-10T15:01:09.027Z
Learnt from: EricAndrechek
Repo: Wave-RF/WaveHouse PR: 312
File: docs/src/content/docs/development.md:0-0
Timestamp: 2026-06-10T15:01:09.027Z
Learning: In this repo’s Markdown review (all .md files), do not flag capitalization/style issues for literal paths starting with ".github/" (or any substring that is a path beginning with ".github/"). Treat ".github" as the correct lowercase dotfile directory name, even when it appears inside prose or code spans; automated checks such as LanguageTool’s "(GITHUB)" rule commonly produce false positives for this literal filesystem path.

Applied to files:

  • CHANGELOG.md
🪛 LanguageTool
.github/workflows/README.md

[style] ~196-196: Since ownership is already implied, this phrasing may be redundant.
Context: ...ml (cache: falseon each). It stores its own go.sum-keyed copy of
/go/pkg/mod+...

(PRP_OWN)

🔇 Additional comments (4)
.github/workflows/README.md (2)

194-205: LGTM!


207-237: LGTM!

.github/workflows/release.yml (1)

27-31: LGTM!

.github/actions/setup-env/action.yml (1)

120-126: 🚀 Performance & Scalability

No suffix change is needed. All Go-enabled callers use distinct suffixes: -lint, -unit, -integration, -e2e-cov, and -cov.

			> Likely an incorrect or invalid review comment.

Comment thread .github/actions/setup-env/action.yml Outdated
Comment thread .github/workflows/publish-dev.yml Outdated
@github-project-automation github-project-automation Bot moved this from Backlog to In review in WaveHouse Task Board Aug 10, 2026
EricAndrechek and others added 11 commits August 10, 2026 17:09
CodeRabbit review. GOTOOLCHAIN=auto lands the toolchain in
~/go/pkg/mod/golang.org/toolchain (we run no setup-go in ci.yml), and
go.sum records no entry for it — this repo's go.sum has zero
golang.org/toolchain lines. So raising go.mod's `go` directive changes
which toolchain belongs in the cache while leaving go.sum byte-identical.

Verified: with go 1.26.5 -> 1.27.0, sha256 of go.sum alone is unchanged
(bcc16701da2c001f both before and after) while go.mod+go.sum rotates.
Under the old key that is a permanent regression, not a one-off — the
stale key exact-hits, and because saves fire only on an exact-key MISS
the freshly fetched toolchain is never saved, so every subsequent run
re-downloads it.

Both Go keys now hash ('**/go.mod', '**/go.sum'). Costs no extra rotation
in practice: dependency bumps already touch both files, so the only newly
rotating case is precisely the toolchain one this fixes.

Also corrects the setup-go rationale in publish-dev.yml and the CHANGELOG:
actions/cache saves on a cache MISS, so that entry is re-saved on each
dependency bump, not "minted afresh on every push to main". The budget
argument is unchanged — one live ~1 GB entry per generation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
Review follow-up on the go.mod key change.

The gobuild-v3 block never stated its own reason for hashing go.mod — the
header just said "same key inputs", pointing at a rationale (the toolchain
rides in ~/go/pkg/mod) that doesn't apply to ~/.cache/go-build. The real
reason is stronger and is what stops someone simplifying this key back to
go.sum: the compiler's build ID feeds every action hash, so a toolchain
bump invalidates every object in the build cache. Keyed on go.sum alone
that bump exact-hits, nothing restored is reusable, and the new objects
are never saved — every run recompiles cold and drags in ~1 GB of dead
objects until an unrelated go.sum change rotates the key.

Also updates the sizing policy's trigger list: after this change a
go.mod-only bump mints a new generation too, and that paragraph is the one
a maintainer reads before doing budget arithmetic.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
The exception prescribes purging the stale entries but only shipped
inspect commands, so a maintainer following it post-rotation had to
improvise the delete. Adds the snippet, the after-not-before ordering
(main still restores the old keys until the rotation lands, so an early
purge just forces a cold repopulate), and the reminder to include every
family the rotation orphans — turning on cache: false strands that job's
setup-go-* entry as well as the renamed one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
Review follow-up. The split has now minted real entries, so the estimates
are replaced with readings from the live cache API:

  gomod-v1                 493 MB
  gobuild-v3 unit/integration/lint/e2e-cov/cov
                           152 / 148 / 140 / 120 / 25 MB
  generation total        1.05 GB   (was 5.56 GB)

Two numbers were wrong. "~1 GB stored" for ~/go/pkg/mod was inferred from
the combined v2 entries rather than read; a cold save is 0.49 GB, drifting
up as superseded versions accumulate through the restore -> save chain, so
both halves of that are now stated. And "~1 GB of dead objects" in the
build-key comment overstated ~/.cache/go-build by 6-40x — that figure
belonged to the pre-split combined entry, and in the failure mode being
described the key exact-hits forever so the entry can't grow into it. The
win is larger than documented (1.05 GB, not ~2 GB), so the old figures
erred conservative, but they broke the PR's own arithmetic.

Also records the residual gap hashing go.mod does NOT close: GOTOOLCHAIN
=auto uses the local toolchain whenever it satisfies the directive, so a
runner image bumping its bundled Go swaps the compiler with neither
go.mod nor go.sum moving — same stale-exact-hit pathology, past both keys.
Left as a documented cause to check rather than plumbed into the key,
since resolving the toolchain before the cache restore would forfeit the
property that the restore captures the toolchain download.

And fixes the go-cache-suffix description, which still said "Empty = the
shared default key" — pre-split wording. Post-split an empty suffix yields
a restore-key that prefix-matches every flavor, the exact cross-flavor
restore this split removes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
Review follow-up, and a repeat of the defect the previous commit set out
to fix. The measured figures were each read from the live API but
converted three different ways: 0.49/0.59 were MiB/1000, 1.05 was
bytes/2^30, 5.56 was bytes/10^9. So the decomposition disagreed with its
own total (0.49 + 0.59 = 1.08, not 1.05) and the improvement read as 5.3x
when it is 4.9x.

Everything is now stored-archive bytes / 2^30 — the unit the README's own
usage check prints, so a reader running the documented command sees the
number the docs quote:

  gomod-v1          516,549,867 B  = 0.48 GB
  gobuild-v3 x5     613,276,117 B  = 0.57 GB
  generation      1,129,825,984 B  = 1.05 GB
  gobuild-v2 x5   5,564,533,024 B  = 5.18 GB  (0.9-1.2 each)

0.48 + 0.57 = 1.05, and 5.18 / 1.05 = 4.9x.

Also corrects what the setup-go entry actually holds. Four places called
it a ~1 GB copy of the module tree; setup-go caches GOMODCACHE *and*
GOCACHE, and .goreleaser.yaml cross-compiles 8 targets, so roughly half of
it is release build objects nothing else caches. Only the other half
duplicates gomod-v1. The budget conclusion is unchanged — dropping it
frees the whole ~1 GB — but a change whose thesis is precise byte
accounting should not misattribute the bytes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
Review follow-up. The biggest of these is a contradiction I introduced.

"Adding a job" step 3 still read "use setup-env with a fresh
go-cache-suffix IF it compiles Go with new flags", while the input
description now says always pass one. A new Go job whose flags match an
existing flavor reads the checklist as "no new flags, no suffix needed",
omits it, and gets key gobuild-v3-<os>-go-<hash> with restore-key
gobuild-v3-<os>-go- — which prefix-matches every flavor's entry and mints
a sixth build cache. That is precisely the cross-flavor restore this PR
removes and the sixth entry its sizing policy forbids, reachable by
following the checklist 60 lines below the policy. AGENTS.md sends people
to this README before editing ci.yml, so the rule has to live here too,
not only in the input description.

Also splits the "deliberately not cached" rationale, which applied the two
release jobs' reasoning to goreleaser-validate.yml as well. That job runs
build --single-target with no dockers_v2, and its own comment gives the
real reason: the snapshot is fast enough that the post-step save costs
more than a cold go mod download. A reader auditing whether cache: false
still earns its place there was being handed the wrong justification.

Re-flows the module-cache comment, which the units edit left ragged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
Review follow-up, and a correction to this PR's own change. Blanket
cache: false on publish-dev.yml measurably regressed it. Across its last
20 runs, GoReleaser splits cleanly on whether setup-go's cache hit:

  warm (post-step 0-1s):   36 37 39 47 50 54 188 224 241 242 245 246 s
  cold (post-step 12-15s): 401 414 417 420 431 432 446 s

No overlap. Run 29029026651 is the control — docs-only change, go.sum
unchanged, entry evicted: 431s against 188-246s for its warm neighbours.
So the opt-out cost 3-6.5 minutes on every push to main, and the value
sits in ~/.cache/go-build (8 targets: 4 goos x 2 goarch), not the module
tree. The rationale this PR shipped — "dominated by cross-compiling and
multi-arch docker, not by go mod download" — argued for keeping it.

setup-go's bundled cache is still wrong here because it stores the module
tree alongside, re-duplicating what gomod-v1 holds once. So: keep
cache: false, and cache ~/.cache/go-build alone under
gobuild-v3-<os>-go-release- (~0.5 GB vs the bundled ~1 GB). The
duplication #443 is about is gone; the cross-compile stays warm.

The -release suffix is load-bearing: those objects are cross-compiled for
8 GOOS/GOARCH pairs and share nothing with ci.yml's native-only flavors,
so neither side restores bytes it cannot use. It also satisfies the
always-pass-a-suffix rule this branch added.

release.yml keeps the plain opt-out — tag-triggered, so a warm entry is
rarely there to hit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
Review follow-up. 4a48e03 added the repo's only bare actions/cache outside
setup-env, contradicting invariant 6 ("Caches are owned end-to-end by
setup-env ... No save steps") and the checklist item that enforces it,
without updating either. Invariant 6 is now scoped to ci.yml and names
publish-dev.yml's release build cache as the deliberate exception —
hand-rolled because that workflow doesn't use setup-env at all. The
inventory row says so too, since its "Saved by" cell was the only one
naming a workflow rather than a ci.yml job, sending a reader to setup-env
to find nothing.

Three accuracy fixes alongside:

- "~1 GB live" reintroduced the unit ambiguity 5bc361c removed. That
  figure is stored-archive; read as on-disk it contradicts the table 13
  lines above, where the module half alone is 1.6 GB on disk. Now "stored".

- release.yml's stated reason was wrong. Cache reads fall back to the
  default branch's scope, so a tag run CAN hit publish-dev's key — which
  this PR keeps hot on every push to main. The real reason is that a
  tagged release is rare and not latency-sensitive. Also notes it could
  restore that key at zero budget cost, since an exact hit never saves.

- "mints a sixth build entry" became wrong the moment this PR added the
  release cache as the sixth. Now ordinal-free so it stays right.

And attributes the timing measurements honestly: they were taken on
setup-go's bundled entry, which carried the same ~/.cache/go-build tree.
The gobuild-v3-<os>-go-release- key is new here, so someone auditing those
runs for hits on it would find none.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
Review follow-up, and an error introduced while fixing the previous one.
ab9cfe7 replaced release.yml's wrong reason ("a warm cache is almost never
there to hit" — false, tag runs read the default branch's scope) with a
second wrong reason: that a tag run "could hit it". It can't. "It" is
setup-go's bundled archive, and this PR makes that key cease to exist —
publish-dev.yml now opts out, goreleaser-validate.yml already did, and
ci.yml runs no setup-go at all. The README even instructs purging the
stranded entry. So flipping cache: true there would be a cold miss AND a
fresh ~1 GB save, the opposite of what the comment implied. The
parenthetical also contradicted itself: an "equivalent" key is a different
key, and setup-go only looks up its own.

Both the comment and the README paragraph now say what is actually true:
nothing mints that key any more; what IS warm is publish-dev's
gobuild-v3-<os>-go-release- entry, restorable from the default branch's
scope; a tagged release is rare and not latency-sensitive, so it isn't
worth a hand-rolled restore step — but that is the lever if it ever is.

Also stops "Same call as publish-dev.yml" flattening a distinction the
README is careful about: same cache: false, different follow-up, since
publish-dev re-caches the useful half. And names the key in the README
rather than saying "that key", whose antecedent resolved the wrong way in
the release.yml comment — the ambiguity was not hypothetical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
Two corrections from review, both checkable and both wrong in exactly the
dimension this PR argues about.

setup-go's bundled cache is NOT go.sum-keyed at the pinned v7 — it keys on
the root go.mod. actions/setup-go#705 (Jan 2026) changed
dependencyFilePattern from 'go.sum' to 'go.mod', and the live entry proves
it: its key ends 9e56ecf5..., and sha256(sha256(go.mod)) = 9e56ecf5...
exactly, while sha256(sha256(go.sum)) = 136f5059... — the hash in every
gobuild-v2 key. Four places said go.sum-keyed. Worse, the CHANGELOG
contrasted "both Go keys now hash go.mod alongside go.sum" against that
"go.sum-keyed" entry, which reads as upstream having the toolchain
staleness bug this PR fixes, when upstream fixed precisely that and errs
the other way.

And the release.yml argument stopped a step short. Cache writes are scoped
to the ref that made them, so a save from refs/tags/v1.0.0 can never be
read by refs/tags/v1.0.1 — or by anything else, ever. Re-enabling the
bundled cache there isn't just a cold miss plus a save; it is a ~1 GB
write-only entry burned on every tagged release, permanently unreadable.
That is the strongest argument for the opt-out and it was missing.

Same fact sharpens the escape hatch: "an exact hit never saves" holds only
for an exact hit — a restore-keys prefix match would save, tag-scoped and
unreadable. The README now prescribes actions/cache/restore (restore-only)
for that lever, which has no save step at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
Third pass at the same sentence, and the version boundary was wrong.
Verified against the upstream tree rather than inferred this time:

  v6.2.0  dependencyFilePattern: 'go.sum'
  v6.3.0  dependencyFilePattern: 'go.mod'   <- the switch
  v7.0.0  dependencyFilePattern: 'go.mod'

actions/setup-go#705 merged 2026-01-26 and shipped in v6.3.0. Saying
"go.sum through v6" is worse than vague: the floating v6 tag resolves to
v6.5.0 today, which keys on go.mod, so it tells a reader that pinning @v6
gets go.sum keying. All four sites now say v6.2.0 / v6.3.0.

Also drops an absolute that isn't true. "A save from refs/tags/v1.0.0 can
never be read by anything else, permanently unreadable" overstates the
scoping rule it cites: a re-run of that same tag's workflow runs at the
same ref and does restore it — and a re-run is the realistic case here,
since release.yml chains buildx, GHCR login, GoReleaser and attestation.
Now: unreadable by another tag, by main, or by a PR — only by a retry.
The conclusion is unchanged; the claim is now falsifiable-proof.

And fixes a link that rendered as literal text: [actions/setup-go#705] was
a shortcut reference with no definition in the file. markdownlint doesn't
catch it (MD052's shortcut_syntax defaults false), and every other
external reference in that README is inline.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
Copilot AI review requested due to automatic review settings August 11, 2026 11:19

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Suppressed comments (1)

.github/actions/setup-env/action.yml:56

  • go-cache-suffix is documented here as mandatory for Go jobs (to avoid the gobuild-v3-<os>-go- cross-flavor restore-key and an extra cache entry), but the input still defaults to an empty string. That leaves a footgun where a new Go job can accidentally reintroduce cross-flavor restore behavior and cache bloat simply by omitting the input. Consider making the default non-empty (e.g. -default) so an omitted suffix is safe by construction.
  go-cache-suffix:
    description: "Per-job Go build-cache partition, e.g. '-unit' (different jobs compile with different flags). Always pass one for a Go job: an empty suffix yields a restore-key that prefix-matches every other flavor's entry, which is the cross-flavor restore the gomod-v1/gobuild-v3 split exists to avoid. The shared part of the cache is gomod-v1, which needs no suffix."
    default: ""

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a19a1faf-43ac-48c6-be75-458ef4906aae

📥 Commits

Reviewing files that changed from the base of the PR and between b475d94 and ba37815.

📒 Files selected for processing (5)
  • .github/actions/setup-env/action.yml
  • .github/workflows/README.md
  • .github/workflows/publish-dev.yml
  • .github/workflows/release.yml
  • CHANGELOG.md
📜 Review details
⏰ Context from checks skipped due to timeout. (11)
  • GitHub Check: Coverage
  • GitHub Check: E2E tests
  • GitHub Check: Docs build
  • GitHub Check: Integration tests
  • GitHub Check: copilot-pull-request-reviewer
  • GitHub Check: Lint
  • GitHub Check: Validate snapshot build
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-06-10T15:01:09.027Z
Learnt from: EricAndrechek
Repo: Wave-RF/WaveHouse PR: 312
File: docs/src/content/docs/development.md:0-0
Timestamp: 2026-06-10T15:01:09.027Z
Learning: In this repo’s Markdown review (all .md files), do not flag capitalization/style issues for literal paths starting with ".github/" (or any substring that is a path beginning with ".github/"). Treat ".github" as the correct lowercase dotfile directory name, even when it appears inside prose or code spans; automated checks such as LanguageTool’s "(GITHUB)" rule commonly produce false positives for this literal filesystem path.

Applied to files:

  • CHANGELOG.md
🪛 LanguageTool
.github/workflows/README.md

[uncategorized] ~123-~123: The official name of this software platform is spelled with a capital “H”.
Context: ...owned end-to-end by setup-env** ([.github/actions/setup-env](../actions/setup-env...

(GITHUB)


[style] ~191-~191: Since ownership is already implied, this phrasing may be redundant.
Context: ...erent flags. go.mod is in the key for its own reason — the compiler's build ID keys e...

(PRP_OWN)


[style] ~209-~209: Since ownership is already implied, this phrasing may be redundant.
Context: ...caches the half that pays for itself on its own key (gobuild-v3-<os>-go-release-, ~0....

(PRP_OWN)


[style] ~230-~230: Since ownership is already implied, this phrasing may be redundant.
Context: ... goreleaser-validate.yml opts out on its own grounds: its --single-target snapshot...

(PRP_OWN)


[style] ~341-~341: This word has been used in one of the immediately preceding sentences. Using a synonym could make your text more interesting to read, unless the repetition is intentional.
Context: ...nvariant 6); a workflow outside it that needs a cache hand-rolls one, as `publish-...

(EN_REPEATEDWORDS_NEED)

🪛 zizmor (1.29.0)
.github/workflows/publish-dev.yml

[error] 76-76: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): enables caching by default

(cache-poisoning)

🔇 Additional comments (4)
.github/actions/setup-env/action.yml (1)

17-28: LGTM!

Also applies to: 82-93, 110-150

.github/workflows/publish-dev.yml (1)

53-60: LGTM!

Also applies to: 62-81

.github/workflows/release.yml (1)

27-49: LGTM!

.github/workflows/README.md (1)

122-132: LGTM!

Also applies to: 192-197, 199-232, 234-246, 248-287, 335-342

Comment thread .github/actions/setup-env/action.yml Outdated
Comment thread .github/actions/setup-env/action.yml
Comment thread .github/workflows/README.md Outdated
EricAndrechek and others added 4 commits August 11, 2026 07:29
CodeRabbit's re-review, and the second finding is a real bug this PR
introduced.

`make cov` never declared the go-mod-download prerequisite its siblings
have (lint-go, vulncheck, test-unit, test-integration all do; test-e2e
gets it via $(COVER_BINARIES)). That was harmless under gobuild-v2, where
every job had its own suffixed entry — a partial module tree only
affected the job that saved it. It is not harmless now: gomod-v1 is a
single unsuffixed entry every Go job races to save on a key rotation, and
the coverage job runs only `go run ./scripts/cov report`, which fetches
just the modules that one program imports. If it won that race it would
store a PARTIAL ~/go/pkg/mod under the shared key, which then exact-hits
for every other job — and because saves fire only on a miss, nothing would
ever repair it until the next rotation.

Worth noting an earlier review asserted the opposite ("every Go-toolchain
make target declares the go-mod-download prereq, so the shared entry is
complete no matter which job wins"). Only four targets do, and cov is not
one of them. The coverage job is also the likeliest winner: it starts at
run creation with no `needs` on the suites.

Also enforces the suffix contract instead of only documenting it.
setup-env now fails a go: true job that passes no go-cache-suffix, since
an empty one yields restore-key gobuild-v3-<os>-go-, prefix-matching every
flavor's entry and publish-dev's -release one.

And tightens ownership wording: gomod-v1 and the gobuild-v3 flavors belong
to ci.yml jobs going through setup-env; publish-dev owns only -release,
and release.yml caches nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
…advice

Two reviews on dd0e7ee, and the load-bearing item is that the job would
have shipped slower than its own documentation claims.

The 36-246s "warm" figure justifying publish-dev's hand-rolled cache was
measured on setup-go's bundled entry, which carried ~/go/pkg/mod as well.
Caching only the build half leaves the module tree cold on every push —
~112 MB re-downloaded — so the job would land above the documented range
and read as an unexplained regression to whoever checked next. It now also
restores gomod-v1 from main's scope, which ci.yml keeps warm there.

Restore-only, deliberately. A full actions/cache adds a post-step save,
and this job must never write the entry every ci.yml Go job shares: it
runs no full `go mod download`, so a save from here is exactly the partial
tree the cov fix in the previous commit exists to prevent. Restore-only
writes nothing and costs 0 GB.

The guard's error message gave wrong advice to the person likeliest to hit
it. `go` defaults to true, so the realistic trigger is a NEW NON-GO job
that uses setup-env with no `with:` block — and the message told them to
pass a suffix. It now names `go: "false"` as the fix for that case, and
the input description states the contract ("REQUIRED when go is true")
rather than advising it, since an empty value is now exit 1.

Also: the ownership tightening in dd0e7ee missed two sentences written in
that same commit (the checklist's "every Go job races to save" and the
Makefile's "every other Go job") — both now ci.yml-scoped; CHANGELOG's
file list gains Makefile, which that commit modified; the guard comment's
"a sixth entry" is off by one now that -release exists; and checklist item
3, having grown to four rules in one paragraph, is now three sub-bullets
so the go-mod-download requirement is findable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
The branch drifted against itself. ab9cfe7 amended invariant 6
specifically to name the ONE cache living outside setup-env — "It is the
only actions/cache@ in the repo outside the composite — keep it that way"
— and 3c14a9f added a second four commits later. The literal string
actions/cache@ is still unique only because the new one is
actions/cache/restore@, which is a pun rather than a contract: a
maintainer grepping actions/cache finds two steps and no way to tell
whether the second violates the rule they were just given.

Invariant 6 is the normative list, so it now names both — the bare
actions/cache owning the release build cache, and the
actions/cache/restore that reads gomod-v1 and owns nothing — and states
the principle behind the asymmetry: a workflow that needs the shared
module tree reads it restore-only; writing it belongs to the ci.yml jobs
that run a full go mod download. Verified there are exactly two
`uses: actions/cache*` outside the composite and six inside.

Also re-flows the two comment blocks the previous commit's rewording left
one line wide (Makefile 82 cols in a 63-74 paragraph, action.yml 85 in a
71-82 one).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
The warm/cold clusters are 36-246s and 401-446s, so the envelope between
them is 401-246 = 155s to 446-36 = 410s: roughly 2.5-7 minutes, mean delta
~4.8. "3-6.5" is a narrower claim than the data supports, and the sentence
invites the subtraction by saying "so". Corrected in all four places it
appears (README table row and prose, CHANGELOG, publish-dev.yml comment).

Also unpicks a dangling "without which" in the README and CHANGELOG. The
CHANGELOG version put twenty-odd words and a plausible-but-wrong
antecedent between the pronoun and its referent, so it first parses as
"without the key every ci.yml Go job shares" — the opposite of the point.
Both now end the clause and start a sentence.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QFfYUaPp3Pv3gLjniiHCpm
Copilot AI review requested due to automatic review settings August 11, 2026 12:40

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

@EricAndrechek
EricAndrechek marked this pull request as ready for review August 11, 2026 13:09
@EricAndrechek
EricAndrechek requested review from a team and taitelee August 11, 2026 13:09
@EricAndrechek
EricAndrechek merged commit f9643a0 into main Aug 11, 2026
35 of 36 checks passed
@EricAndrechek
EricAndrechek deleted the ci-cache-split branch August 11, 2026 13:19
@github-project-automation github-project-automation Bot moved this from In review to Done in WaveHouse Task Board Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docs Documentation, site/, README area/infra CI, build, deploy, Docker, release github_actions Pull requests that update GitHub Actions code

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

fix(ci): Actions cache exceeds 10GB cap — module cache stored 5x

2 participants