Skip to content

Commit f382f7f

Browse files
committed
ci: bound the performance-budget.yml Turbo cache save (#7048)
Same split; `timeout-minutes: 5`, `continue-on-error: true`, save placed last — after the budget verdict and after the comment that reports it, which is where the generated post phase already ran. Bound derived from this site: this job's own save of `.turbo/cache` measured 1s on 2026-09-02 (`Post Turbo Cache`, job 100096569559) against a 4m07s job, so 5 minutes is 300x it. That is the same RATIO PR #7047 sized its bound at, arrived at from this job's own number rather than copied from that one. `Bundle Analysis` is a required context (objectui#6245) and this job declares no `timeout-minutes`, so its ceiling is the 360-minute default — the bound is the only thing that stops a stalled save holding a required check open for hours. Adding a ceiling would change what the gate rejects and is deliberately not done. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BGMDbrVa8JjZcCQ7DWYH1b
1 parent be1e7d7 commit f382f7f

1 file changed

Lines changed: 67 additions & 2 deletions

File tree

‎.github/workflows/performance-budget.yml‎

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,37 @@ jobs:
134134
node-version: '22.x'
135135
cache: 'pnpm'
136136

137-
- name: Turbo Cache
138-
uses: actions/cache@v6
137+
# ── Cache bookkeeping cannot void a recorded verdict (objectui#7048) ──
138+
# THE ORDERING, carried here from the type-check split in `ci.yml`
139+
# (objectui#6577, PR #7047) because it is what a future reader needs in
140+
# order to judge whether these steps may be touched: the verdict is
141+
# recorded by the checking steps; everything after them is bookkeeping,
142+
# and bookkeeping must never discard an answer the gate already produced.
143+
#
144+
# Why the SPLIT rather than a timeout on one step: combined
145+
# `actions/cache` declares `main: dist/restore/index.js` plus
146+
# `post: dist/save/index.js`, so its save is a step the RUNNER generates
147+
# at job end (`Post Turbo Cache`). No workflow syntax attaches
148+
# `timeout-minutes` or `continue-on-error` to a generated post step.
149+
# Measured once, on `ci.yml`'s type-check cache: a 1-second save took
150+
# 789s, ran that job into its ceiling, and the resulting `cancelled` —
151+
# which the merge queue cannot tell from `failure` — ejected an all-green
152+
# pull request (objectui#6577). `actions/cache`'s own `save-always`
153+
# deprecation text points at this same split.
154+
#
155+
# ⚠️ This job declares NO `timeout-minutes`, so its ceiling is GitHub's
156+
# default of 360 minutes, and `Bundle Analysis` is a required context
157+
# (objectui#6245). A stalled save would therefore hold a required check
158+
# open for up to six hours before reporting `cancelled`. ⛔ Adding a
159+
# ceiling is NOT the fix and is not attempted here — it would change what
160+
# this gate rejects. The bound below is on the bookkeeping step alone.
161+
#
162+
# The restore half is deliberately left UNBOUNDED: a restore stall fails
163+
# BEFORE any verdict exists — a gate that did not run, which is honest —
164+
# rather than a recorded verdict discarded.
165+
- name: Restore Turbo Cache
166+
id: turbo-cache
167+
uses: actions/cache/restore@v6
139168
with:
140169
path: .turbo/cache
141170
key: turbo-${{ runner.os }}-${{ github.sha }}
@@ -470,3 +499,39 @@ jobs:
470499
core.warning(`Could not comment on PR: ${error.message}`);
471500
await core.summary.addRaw(body).write();
472501
}
502+
503+
# The bookkeeping half of the split documented at the restore step above,
504+
# placed HERE — last in the job, after the budget verdict AND after the
505+
# comment that reports it — because that is exactly where the post phase
506+
# it replaces already ran. Nothing about which commits this gate accepts
507+
# or rejects moves with it.
508+
#
509+
# `timeout-minutes: 5` is DERIVED FOR THIS SITE, and landing on the same
510+
# number PR #7047 chose is a result rather than a copy — objectui#7048
511+
# fences inheriting that 5, so here is this site's own arithmetic. This
512+
# job's own save of this cache measured 1s on 2026-09-02 (`Post Turbo
513+
# Cache`, job 100096569559); the whole job was 4m07s. 5 minutes is 300x
514+
# the measured save — the same ratio #7047 sized its bound at, arrived at
515+
# from this job's own number.
516+
#
517+
# `continue-on-error: true` is the other half, and without it the bound
518+
# would only trade a `cancelled` gate for a red one. A cache that failed
519+
# to upload costs the next run some time; it says nothing whatsoever
520+
# about the bundle sizes under test, so it must not speak for them.
521+
#
522+
# Behaviour preserved, spelled out so the equivalence is checkable:
523+
# - `cache-hit != 'true'` reproduces the combined action's own "exact
524+
# hit on the primary key ⇒ do not save" skip. A `restore-keys` prefix
525+
# match leaves `cache-hit` false and the save still runs, exactly as
526+
# the combined action behaved.
527+
# - the condition names no status function, so the implicit `success()`
528+
# still applies — matching the combined action's `post-if: success()`.
529+
# - same `path` and same `key` as the restore step above.
530+
- name: Save Turbo Cache
531+
if: steps.turbo-cache.outputs.cache-hit != 'true'
532+
uses: actions/cache/save@v6
533+
timeout-minutes: 5
534+
continue-on-error: true
535+
with:
536+
path: .turbo/cache
537+
key: turbo-${{ runner.os }}-${{ github.sha }}

0 commit comments

Comments
 (0)