Repository navigation
Commit eae9a58
ci: restore the Next.js cache on every run, save it on push and schedule only (#26984)
Part of #25452 (step 1, change (c), of the maintainer's reopen
directive). Steps 2 and 3 stay on the card, so this PR does not close
it.
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:`ci.yml` 的 Build Docs 任务里,Next.js 缓存从一个合并式 `actions/cache`
拆成两步:每次运行都恢复,只在 `push` 和 `schedule` 运行上、精确键未命中时保存。
- 为什么改:PR 和合并队列每次运行都会存一份 0.2–0.9 GB 的 Next.js 缓存,只有它自己的 ref 能恢复,却占用同一个
10 GB 缓存池,把 `main` 的条目挤掉(池子读数 10.30 GB,其中 nextjs 占 4.98 GB)。pnpm store
在这个基点上已经是 PR/队列只恢复不保存,本 PR 不再改动。
- 风险与回滚:最坏情况是保存条件写错导致 `main` 也不再保存,docs 构建变冷但不会变红(保存步骤
`continue-on-error`);回滚就是 revert 这一个提交。
- 先看:`.github/workflows/ci.yml` 的 "Restore Next.js cache" 与 "Save
Next.js cache" 两个步骤(只这一个文件)。
- 两分钟验证:打开本 PR 的 Build Docs 任务日志,应看到 "Restore Next.js cache" 正常恢复(Cache
restored from key 一行),而 "Save Next.js cache" 显示为跳过;合并后 `main` 的 push
运行里该保存步骤应实际执行。
- 需要你做的:以 GOVERNED_APPROVERS 账号批准本 PR(Tier H,`.github/workflows/**`)。
## What changes
The maintainer's directive, verbatim, from the reopen comment on the
card:
> 可以:重开 #25452,挂回 pm:queue(domain:devx),按卡上的 (c)+(a) 先做:PR 和合并队列上
Next.js、pnpm 缓存只恢复不保存,再去掉远程缓存已覆盖的 build-core/typecheck/pack-smoke
种子;做完再测一次池子。
This PR does the first clause only: on `pull_request` and `merge_group`,
the Next.js cache and the pnpm store restore and do not save, and `push`
to `main` keeps saving. Dropping the build-core / typecheck / pack-smoke
seeds (change (a)) is out of this PR: the #26070 ruling keeps
pull-request runs without a remote-cache token, so those seeds are what
PR builds restore, and the seat is taking (a) back to the maintainer.
The seed steps are untouched. The pool limit is not raised.
One file, `.github/workflows/ci.yml`, job `build-docs` (+39 / -5):
- **Restore Next.js cache** (was "Setup Next.js cache"):
`actions/cache@v6` becomes `actions/cache/restore@v6` with `id:
nextjs-cache`. Path, key and restore-keys are byte-identical, so the
entries `main` already holds stay valid.
- **Save Next.js cache** (new, last step of the job):
`actions/cache/save@v6`, `timeout-minutes: 5`, `continue-on-error:
true`, key `steps.nextjs-cache.outputs.cache-primary-key`.
- The comment above "Assert the docs app actually built" now names the
restore step instead of the removed combined step. Its rule is kept: the
cached path is still `apps/docs/.next/cache` only, so `.next/BUILD_ID`
cannot come from the cache.
The house pattern is `.github/actions/setup-workspace` (the pnpm store)
and `ui-deps`'s "Save pnpm cache" in the same file: a restore step on
every event, and a main-phase save gated on `push || schedule` and a
miss of the exact key. This PR copies that pattern. The other spelling
the dispatch offered, `actions/cache` with `lookup-only`, is not a
restore-only mode: `lookup-only` "Check[s] if a cache entry exists ...
without downloading the cache" (actions/cache v6 `restore/action.yml`),
so it would have turned off the restore on PRs. That silent loss of the
restore is the failure this PR has to avoid.
### Per step: the expression, why it restores on PR, why it saves on
push
| step | `if:` | `pull_request` | `merge_group` | `push` (main) |
`schedule` | `workflow_dispatch` |
|:--|:--|:--|:--|:--|:--|:--|
| Restore Next.js cache | none | restores | restores | restores |
restores | restores |
| Save Next.js cache | `(github.event_name == 'push' \|\|
github.event_name == 'schedule') && steps.nextjs-cache.outputs.cache-hit
!= 'true'` | skipped | skipped | saves on a miss | saves on a miss |
skipped |
- **The restore runs on every event because it has no `if:` at all.**
Nothing on the restore path depends on an event name, so a misspelled
condition cannot turn the restore off.
- **The save is skipped on PR and queue runs.** `github.event_name` is
the literal `pull_request` or `merge_group` there, so the left operand
is false and the save does not run. On `push` and `schedule` the left
operand is true. The right operand is false only on an exact-key hit,
where the combined action's post step also skipped the save.
- **What the combined action did on every event, kept for the events
that still save:**
- The save sits behind `success()`: `actions/cache@v6` declares
`post-if: "success()"`, and a step with no status function in its `if:`
gets `success()` implicitly.
- The save uses the same key. The combined post step saved under the
primary key it resolved at restore time, and `cache-primary-key` is that
key. A key re-hashed after the build would hash `apps/docs/`, the tree
the build writes into.
- **Build Docs runs on `schedule` and `workflow_dispatch`.** Its filter
output `docs` is `'true'` on both, because the paths-filter step is
skipped there and `|| 'true'` applies.
- After this change, `schedule` keeps saving: those runs are on `main`,
so their entries can be restored everywhere.
- `workflow_dispatch` no longer saves. That is the same rule
`setup-workspace` applies to the pnpm store. A dispatch on a non-main
ref would otherwise write an entry only that ref can restore.
### The pnpm store half: already restore-only on this base, so no step
changes
I re-derived `git grep -n 'actions/cache' origin/main -- .github/` at
the dispatch's `aa00362f` and again on this head. The `pnpm-store-v3`
sites the dispatch named are all **already** `actions/cache/restore@v6`,
not plain `actions/cache`. The only save among them is gated like the
house pattern:
| site (this head) | job | step | `if:` |
|:--|:--|:--|:--|
| `ci.yml:3248` | `ui-deps` | Restore pnpm cache | none (all events) |
| `ci.yml:3336` | `ui-deps` | Save pnpm cache | `(push \|\| schedule) &&
steps.pnpm-cache.outputs.cache-hit != 'true'` |
| `ci.yml:3385` / `3643` / `3882` / `4204` | `type-check-ui` / `test-ui`
/ `lint-ui` / `build-e2e-ui` | Restore pnpm cache | none, restore only
("Build UI Deps saves the store") |
| `governed-surface-guard.yml:241` | `governed-surface-guard` | Restore
pnpm cache | `steps.toolchain.outputs.needed != 'false'`; the workflow
triggers on `pull_request` and `merge_group` only, and it has no save
step |
| `.github/actions/setup-workspace/action.yml:104` / `:123` | every
caller (12 in `lint.yml`, 7 in `ci.yml`, others) | Restore / Save pnpm
store | save: `install != 'false' && save-store != 'false' && (push \|\|
schedule) && cache-hit != 'true'` |
`lint.yml` has no `pnpm-store-v3` key of its own: every job there goes
through `setup-workspace`. No `setup-node` step caches pnpm (`cache:
pnpm` matches nothing). So the pnpm half of the directive already holds,
and the only step left was the Next.js cache.
## Tests
This is a workflow-only diff with no package, script or test touched.
The local evidence is the derived gate set, a YAML parse, and the
control-character scan. The reading of record is the PR's own CI run.
- YAML parse of `ci.yml` with the `yaml` package, listing `build-docs`
steps: `Checkout repository | Setup workspace | Restore Next.js cache |
Build Docs (the command production runs) | Assert the docs app actually
built | Save Next.js cache`, and both new steps parse with the
expressions above.
- `grep -naP` for control bytes over `ci.yml`: no hits.
- No ablation: the diff changes no tested behaviour (workflow config,
which the os-dev contract exempts from ablation).
## Acceptance notes
- **The CI log lines that prove "restores, does not save" on this PR:
NOT MEASURED at the time of writing**, because the PR's run had not
reported yet. Expected: in the Build Docs job, "Restore Next.js cache"
prints a `Cache restored from key:` line (or a miss on a cold key), and
"Save Next.js cache" is skipped. The first `main` push run after landing
should run the save step on a miss.
- **The pool re-reading (directive step 3) is not in this PR.** The seat
container gets a 403 on `actions/cache/*`.
- **Combined `actions/cache` steps that post-save on `pull_request` but
are outside this directive.** They cache `.turbo/cache`, not Next.js or
pnpm: `os-create-smoke.yml:95` (triggers `pull_request`, `schedule`,
`workflow_dispatch`) and `pack-smoke-optin.yml:125` (`pull_request`,
label opt-in), both with a per-sha key. `publish-smoke.yml:205` and
`release.yml:1810` do not run on PR events. If the step-3 reading still
shows `refs/pull/*` turbo entries from these two, that reading is the
place to raise them.
- `setup-pnpm`'s Corepack store save (`action.yml:228`) runs on any
event, on a miss of a key that is content-addressed by the pnpm pin. A
PR saves it only on the first run after a `packageManager` bump. That is
one entry per pin, and it stays as it is.
## Verification
Union of the derived gate set at head `4597816157`, from `node
scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`: 53 commands, each exit code captured before
any pipe.
**Reconciliation, verbatim from `dispatch-gates --ran`:** `✓
dispatch-gates --ran: 53 derived famil(ies) accounted for — 50 run, 3
NOT-MEASURED (0 DERIVED from a recorded exit 3, 3 claimed).`
<details><summary>Gate results at 4597816</summary>
- **Exit 0 (50 commands).** The 18 direct `node` commands:
closing-keyword-parity and its self-test, comment-mask-corpus,
dts-emitted self-test, self-test-wired and its self-test,
self-test-workflow-commands and its self-test, step-collectors and its
self-test, whole-set-label-write and its self-test, and the self-tests
of assert-turbo-remote-cache, plan-test-core-shards, prune-turbo-cache,
scheduled-full-run and ci-failure, plus docs-audit check-drift-comment.
The `pnpm check:*` commands: agent-test-spelling, aggregator-roster,
ci-filter-parity, cross-package-test-inputs, declared-population-live,
driver-memory-census, gitlink-declared, lean-entry-closure,
node-version, nul-bytes, pm-close-cards, pm-dispatch-gates (fast tier:
`1935 cases pass`), pm-expected-skips, pm-fleet-write-dispatch,
pm-fleet-write-execute, pm-fleet-write-validate, pm-governed-merges,
pm-issue-transfer, pm-post-stamped, pm-record-recognisers,
pnpm-acquisition, pnpm-filter-targets, refd-timer-probe,
required-contexts, shard-attestation, sourcemap-no-sources-content,
stall-guard-budget, stall-guard-headroom, type-check-coverage,
watch-hint-literal, workflow-status-functions and
workflow-step-name-quoting.
- **NOT MEASURED: `pnpm check:type-check-debt`.** Its closure build
never got the shared verify lock: `os-verify-lock: VERDICT queue-timeout
(exit 99) · never acquired · waited 540s`, with the lock held by another
agent's run. This is a whole-workspace ledger ratchet, and a
workflow-only diff cannot move it. CI's Lint & Repo Gates runs it.
- **NOT MEASURED: `pnpm check:dts-closure` and `pnpm
check:dual-build-cjs-loads`.** Both read `dist/`. This worktree's
`dist/` is half-built: an earlier local run of type-check-debt was
killed by my 400 s wrapper timeout during its closure build, and
`@objectstack/organizations` never emitted `index.d.ts`. This diff
touches no package. CI's Build Core builds from a fresh checkout.
- **Not derived, not run:** actionlint. It is not in the derived set and
not installed here.
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QSeKYmTYfaPbLQD4BJfomW)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 0b78a20 commit eae9a58
1 file changed
Lines changed: 39 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3006 | 3006 | | |
3007 | 3007 | | |
3008 | 3008 | | |
3009 | | - | |
3010 | | - | |
| 3009 | + | |
| 3010 | + | |
| 3011 | + | |
| 3012 | + | |
| 3013 | + | |
| 3014 | + | |
| 3015 | + | |
| 3016 | + | |
| 3017 | + | |
| 3018 | + | |
| 3019 | + | |
3011 | 3020 | | |
3012 | 3021 | | |
3013 | 3022 | | |
| |||
3073 | 3082 | | |
3074 | 3083 | | |
3075 | 3084 | | |
3076 | | - | |
3077 | | - | |
3078 | | - | |
| 3085 | + | |
| 3086 | + | |
| 3087 | + | |
3079 | 3088 | | |
3080 | 3089 | | |
3081 | 3090 | | |
| |||
3086 | 3095 | | |
3087 | 3096 | | |
3088 | 3097 | | |
| 3098 | + | |
| 3099 | + | |
| 3100 | + | |
| 3101 | + | |
| 3102 | + | |
| 3103 | + | |
| 3104 | + | |
| 3105 | + | |
| 3106 | + | |
| 3107 | + | |
| 3108 | + | |
| 3109 | + | |
| 3110 | + | |
| 3111 | + | |
| 3112 | + | |
| 3113 | + | |
| 3114 | + | |
| 3115 | + | |
| 3116 | + | |
| 3117 | + | |
| 3118 | + | |
| 3119 | + | |
| 3120 | + | |
| 3121 | + | |
| 3122 | + | |
3089 | 3123 | | |
3090 | 3124 | | |
3091 | 3125 | | |
| |||
0 commit comments