Skip to content

ci: assert the Turbo remote cache is on after Build Core, the Test Core closure and the three Type Check builds - #25419

Merged
os-zhuang merged 3 commits into
mainfrom
claude/project-thread-hr4due
Oct 23, 2026
Merged

os-zhuang merged 3 commits into
mainfrom
claude/project-thread-hr4due

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Elon · project thread

Fixes #25374
Clause-②: no
Metadata-protocol: none

Claim: comment 6364174741 on the card (session session_01QPa866zGYAuVVnv8kKLnKg, branch claude/project-thread-hr4due). Tier H: .github/workflows/ci.yml and .github/workflows/lint.yml are on the governed register, so this PR stays draft until a GOVERNED_APPROVERS approval.

维护者速读(草稿)

改了什么:CI 里五处走 Vercel Turbo 远程缓存的构建(Build Core、Test Core 每个分片的依赖闭包构建、lint 的三条 Type Check 车道)后面各加一步「远程缓存是否开着」的断言。它读 turbo 自己打印的那一句 Remote caching enabled / disabled / unavailable (…),并把本次构建的远程命中、本地命中、未命中个数写进该 job 的 Step Summary。新脚本一个:scripts/ci/assert-turbo-remote-cache.mjs;另把门禁 check-ci-filter-parity 的识别放宽到「pnpm build 后只跟这两个报告类参数」,其余写法照旧拒绝。

为什么改:远程缓存的 token 只在签名密钥非空时才传,任何一个密钥或变量缺失、轮换,缓存就静默关掉,构建照样绿,只在日志里留一句没人读的话。每个 PR 十条并行构建可能长期在冷跑而无人察觉。

风险与代价(含回滚):合并队列与 main 推送(会写远程缓存的运行)在缓存关闭时会变红,直到有人补好密钥;PR 与定时运行只出黄色警告(fork PR 拿不到密钥)。Vercel 连不上或服务端报错只警告,不红队列。新增步骤耗时为毫秒级;两个新增的 turbo 参数不改变任何任务哈希(83/83 相同)。回滚:还原本 PR 即可,无数据或产物迁移。

席位意见:

你要做的:批准本 PR(受管面)。

What changed

  • scripts/ci/assert-turbo-remote-cache.mjs (new, --self-test with a battery floor and the handshake). It reads the build step's turbo structured log for the prelude line, and the run summary (--summarize) for each build task's cache.source. The summary does not record whether the remote cache was on, which is why both are read. Verdict table (header is the authority):
    • enabled: green.
    • disabled (any reason), or unavailable for an account state (auth failed, disabled for the team, usage limit, spending paused, the mid-run 403): red on a writing run, a warning otherwise. A writing run is merge_group, or push / workflow_dispatch on refs/heads/main: the remote:rw branch of the TURBO_CACHE expression.
    • unavailable for a transient reason (Could not connect, Unexpected server error): a warning on every run, so a Vercel outage does not block the merge queue.
    • no prelude line, no log, or no summary: exit 3 PREREQUISITE NOT MET on every run.
    • Remote hits are reported, never judged.
  • The five carriers pass --summarize --log-file=.turbo/remote-cache/SITE.json to their existing turbo run build. The assertion step runs straight after each:
    • Build Core: The Turbo remote cache was on for the build. Build Core also runs the script's --self-test once, beside check-dts-emitted self-test.
    • Test Core closure: The Turbo remote cache was on for this shard's closure build, with --if-ran (an empty shard runs no turbo) and --move-summary-to "$RUNNER_TEMP/turbo-remote-cache", so .turbo/runs/ is still the test step's alone for the drift check and the timings capture. The closure comment that said "No --summarize" now says why it is there.
    • lint.yml Type Check · workspace, · debt ledger and · consumer gates: The Turbo remote cache was on for the workspace build, id: turbo-remote-cache-was-on + continue-on-error: true, so it is a lane gate and lane-verdict.mjs carries its red while the lane's other gates still run.
  • Build Core's "Turbo remote cache (ci: wire the Vercel turbo remote cache (team object-stack) into ci.yml — trusted events write, PRs read, signed — so cloud's pinned framework build can replay what this repo's main already built #21186)" comment gains an ASSERTED paragraph. The other carriers point back to it.
  • scripts/check-ci-filter-parity.mjs (one file beyond the dispatched surface; see Deviations). Its Build Core subject required a step whose run: is exactly pnpm build, so Build Core's new pnpm build --summarize --log-file=… was refused. The recognizer (isBuildCommand) now accepts pnpm build followed ONLY by the closed list --summarize and --log-file=PATH. These flags change what turbo reports, never the task set. Anything else still refuses. 9 new battery-(9) cases, floor 33 → 42:
    • pass: both flags, and --summarize alone;
    • refuse: --filter=… beside them, --affected, an unknown flag (--force), an empty --log-file=, a -- passthrough, the same flags on pnpm test, and a second command after the build.
    • The fixture now quotes run: so a multi-line value stays one YAML scalar.
    • Ablations: making the flag check always true reds 6 of the 7 refusal cases (the pnpm test one is held by the prefix check). Dropping the prefix check reds the pnpm test case.
  • The new script gets its Build Core guard row in ci.yml's core: filter (check-ci-filter-parity derives it: Build Core runs the script's self-test and assertion).

Measured

  • Flags do not move a hash. turbo run build --filter=!@objectstack/docs --dry=json, with and without --summarize --log-file=.turbo/remote-cache/x.json: 83 of 83 tasks, 0 differing hashes (turbo 2.11.5).
  • --log-file must be repo-relative. An absolute path outside the repo prints Structured log path '…' escapes the repository root, using default location and writes .turbo/logs/EPOCH.json instead. A repo-relative path creates its directory.
  • The structured log is not valid JSON as a whole. turbo 2.11.5 leaves some separating commas out, so it is read line by line.
  • The three states, from a real run (turbo 2.11.5, --filter=@objectstack/formula):
    • no token: Remote caching disabled (remote cache requested — set TURBO_TOKEN and TURBO_TEAM, or run "turbo login" and "turbo link"), using shared worktree cache;
    • token without team: Remote caching disabled (TURBO_TOKEN set without TURBO_TEAM);
    • token and team, no route to Vercel: Remote caching unavailable (Could not connect to "https://vercel.com/api"), at level warn.
    • enabled cannot be produced from a seat container, which has no route to Vercel. The prelude wording is read from the turbo binary's strings, and the full set of disabled / unavailable reasons comes from the same place.
  • Token withheld, writing run: the simulation. This is the acceptance's PR-side simulation. A real turbo run build --filter=@objectstack/formula --summarize --log-file=.turbo/remote-cache/sim.json was run with TURBO_TOKEN= (what the carriers' expression yields with the signing key empty). The script was then run on its log:
    • GITHUB_EVENT_NAME=merge_group: exit 1, with ::error title=Turbo remote cache disabled (…)::Remote caching disabled (remote cache requested — set TURBO_TOKEN and TURBO_TEAM, …) -- this run writes the remote cache, so it must be on. …;
    • GITHUB_EVENT_NAME=pull_request: exit 0, with the same sentence as a ::warning;
    • the summary was moved out of .turbo/runs/ (now empty);
    • --if-ran with no log: exit 0, "the build step ran no turbo".
  • Before (the card's item 3). Merge-queue run 39939612132 (830a63a): Build Core Build packages (excluding docs) 4m21s, Cached: 38 cached, 76 total. The six closure builds took 2m14s to 3m28s. The prelude line itself is outside the 5,000 lines a seat container can read from that log, so whether the remote cache was on before this change is read from this PR's first run: the new step summary on Build Core and on each closure shard. The seat records that reading on the card.

Not changed, on purpose

  • No new job, workflow or check context: every new step sits inside a job that is already required (check:required-contexts).
  • The test / test:repo / typecheck steps stay off the remote, as Build Core's PINS require. The assertion steps run no turbo.
  • Only the first build of each lint lane asserts: the lane's second build carries the same four TURBO_* lines, so it would print the same state.

Deviations

  • One file beyond the dispatched surface, approved by the seat on 2026-10-23. That file is scripts/check-ci-filter-parity.mjs; the seat's conditions were the closed allowlist, cases both ways, and the 83/83 measurement stated here. On its own it reads NOT governed; this PR is Tier H because of the two workflows.

Acceptance notes

  • Two more remote-cache carriers exist and are not asserted here, because the card names five places. They are Temporal Conformance (four build steps, ci.yml temporal-conformance) and the dogfood closure build (ci.yml dogfood). Each needs the same two flags and one step. Leaving them is a scope choice for the seat; the script needs no change for them.

Gates

At head ef582fff (this branch merged with origin/main f0fdd45b), after a full pnpm build:

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derives 71 commands for the 4 paths. All 71 ran and all 71 exited 0. --ran over the record: 71 derived, 71 run, 0 NOT-MEASURED.
  • Of those, node scripts/check-ci-filter-parity.mjs and its --self-test (140 assertions) were red in the first round, before the gate change, and are green now.
  • node scripts/ci/assert-turbo-remote-cache.mjs --self-test: 32 cases across 6 batteries, OK.
  • eslint --no-inline-config over both scripts: exit 0.
  • node scripts/pm/check-governed-merges.mjs --branch HEAD: governed (Tier H) through .github/workflows/ci.yml and lint.yml; the two scripts are not on the register; 526 changed lines (+514 / −12).

Generated by Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_01QPa866zGYAuVVnv8kKLnKg

…rier

Build Core, Test Core's closure build and lint.yml's three Type Check
lanes now pass --summarize and a repo-relative --log-file to their
remote-cache turbo build, and the step after reads turbo's
"Remote caching enabled|disabled|unavailable" prelude line plus the
summary's per-task cache source. A run that writes the remote cache
(merge_group, push/workflow_dispatch on main) reds when it is off; a
read-only run warns. Hit / miss / remote-hit counts go to the job's
step summary.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPa866zGYAuVVnv8kKLnKg
…ng flags

Build Core's build now runs `pnpm build --summarize --log-file=PATH` for
the remote-cache assertion. The gate's build-step recognizer accepts
exactly that closed list after `pnpm build` and still refuses anything
else (a --filter, --affected, an unknown flag, a passthrough, the flags on
another command, a second command). The new script gets its Build Core
guard row in the core filter.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QPa866zGYAuVVnv8kKLnKg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd size/l skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants