Skip to content

ci: extend the turbo remote cache to the Type Check, Test Core, dogfood and Temporal build steps - #22086

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-22077-turbo-remote-cache-jobs
Oct 7, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-22077-turbo-remote-cache-jobs

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #22077
Clause-②: no

The turbo remote cache that #21186 wired into Build Core is now read by every turbo run build step of the three Lint Type Check build lanes, the Test Core shards, the dogfood shards and Temporal Conformance. Each carrier gets Build Core's four env lines verbatim: the same write rule (writes only on merge_group and on push / workflow_dispatch against main, everything else reads), the same signing, and no new secret. Two files: .github/workflows/ci.yml and .github/workflows/lint.yml.

Route that landed: the remote cache, not the artifact fallback

Nothing in the remote route failed, so the dist/ upload-artifact alternative was not needed:

  • Hashes. Each carrier's plan is a subset of Build Core's turbo run build --filter=!@objectstack/docs plan, with identical task hashes and identical globalCacheInputs. Measured with --dry=json on 3d9188502e, turbo 2.11.5, CI=true:

    carrier build nodes (with a command) same hash as Build Core
    Type Check Build workspace packages (3 lanes) 70 (67) 70/70
    Build the ledgered packages' dependencies / Build the nested packages ... 77 (71) 77/77
    dogfood Build the dogfood package's dependency closure 66 (63) 66/66
    Temporal: driver-sql / non-SQL backends / metadata-protocol / runtime 8 / 18 / 14 / 31 all
    Test Core Build this shard's dependency closure, shards 1-6 60 / 62 / 63 / 62 / 32 / 62 all

    Every plan is 100% #build tasks. Filters and --concurrency are not part of a task hash.

  • Signing and permissions. These are the same secrets and the same expressions as Build Core. A same-repo PR receives them; a fork PR receives none, so TURBO_TOKEN evaluates to '' and turbo reports Remote caching disabled (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 measured this). TURBO_CACHE never evaluates to ''.

  • The cache already serves. On the main push run at this PR's base (CI 37627942232), Build Core's build step took 6 s, because the queue entry for the same tree wrote it. In the same run, the jobs that did not read the remote rebuilt: dogfood took 200 / 201 / 336 s, and in Lint 37627942309 the Type Check lanes took 297 / 330 / 335 s.

Test Core: a new guarded build step

Test Core's existing build step, Build the sliced package's dependency closure, runs zero iterations, because no package has been sliced since #21487. The closure was built inside Run this shard's tests. That run cannot read the remote, because test / test:repo stay off it.

Merge-queue run 37623284168, Test Core (3/6), shows the cost: one turbo run of the tests and their closure printed Cached: 1 cached, 72 total / Time: 11m43.373s.

Each shard now runs a new step, Build this shard's dependency closure, before the slice step. It is one guarded turbo run build, with --filter=PKG^... for every package on the shard (PKG's dependencies without PKG), and it carries the env block. The test step then replays that closure from the local cache.

Measured on all six shards of the local partition: this plan equals the test plan's build tasks, with identical hashes, 0 extra and 0 missing. One exception is cli#build on shard 1/6: cli#test has dependsOn: ["build"], so the test step still builds that one, as before.

Other properties of the new step:

  • An empty FILTERS exits before turbo runs, because a bare turbo run build would build the whole workspace.
  • It has no --summarize, so .turbo/runs/ stays the test step's alone, for the drift check and the timings capture.
  • check:stall-guard-budget judges it at window 10m, cap 20m, budget 45m, slack 25m.

The two pins

Both pins are written into Build Core's Turbo remote cache (#21186) comment as a PINS paragraph, and every carrier points back to it. They are not a new gate.

#19086: a step that writes artifacts from a cache-served dist must not be among those served.

  • The env goes on build-only steps. Checked mechanically on the final tree: all 12 steps carrying TURBO_TOKEN hold Build Core's four lines byte-identical and run only turbo run build / pnpm build, and no job sets TURBO_* at job level. The dry-run plans above contain no test, test:repo, typecheck or gen:* task.
  • gen:schema and gen:skill-refs are cacheable turbo tasks, but no workflow runs them through turbo (turbo run gen: 0 hits).
  • Grepping the wired jobs for gen:, --fix and --write gives 0 hits, so no step there writes tracked artifacts.
  • The typecheck step in Type Check · workspace stays off the remote. Every build task its ^build closure schedules is already in the wired build step's plan (66 of 66, 0 extra), so it replays them locally.

#21193: the build hash covers every root input the builds read. I re-ran #21193's probe on 3d9188502e: append one comment line to a file, re-derive the 72-task Build Core plan, restore from HEAD, and prove the restore by blob hash.

file build hashes moved
tsup-drop-sources-content.mjs, check-dts-emitted.mjs, invoked-as.mjs 72/72 each
check-dts-references, ts-parse, check-regen-pending, regen-artifacts, git-env, import-prerequisite, cli-build-prerequisite, check-dev-prereqs, build-input-hash, workspace-enumerator, js-comment-mask 71/72 each
sync-scaffold-emission-policy.mjs, sync-template-versions.mjs, packages/cli/src/commands/init.ts 6/72 each
control: root tsup.config.ts 72/72
controls: scripts/check-turbo-task-graph.mjs, ci.yml, lint.yml 0/72 each

These are #21193's own numbers. The last row also shows that this PR's own diff moves no build hash. A static check agrees: the import closure of every root script that a build command or a tsup config names lies inside the declared $TURBO_ROOT$ inputs. The spec generators' closure (450 files) reaches 10 root scripts, all declared.

Measurement (before / after)

Before. Build-step seconds, from the jobs API:

step main push at base 3d9188502e (CI 37627942232 / Lint 37627942309) merge-queue entry for the same tree (CI 37623284168 / Lint 37623284080)
Build Core Build packages (excluding docs) (reads the remote already) 6 s 193 s
Type Check · workspace Build workspace packages 297 s 323 s
Type Check · debt ledger: build, then ledgered build 335 s, then 31 s 340 s, then 32 s
Type Check · consumer gates: build, then nested build 330 s, then 30 s 342 s, then 31 s
dogfood 1/3, 2/3, 3/3 closure build 200, 336, 201 s 322, 340, 287 s
Temporal: driver-sql, non-SQL, metadata-protocol, runtime 1, 35, 0, 79 s 95, 47, 1, 91 s
Test Core Run this shard's tests (closure plus tests), shards 1-6 1181, 835, 616, 752, 663, 767 s not split out; see the 3/6 reading above

After (seat-appended from the dev's report 6040381091 on #22077; this PR's pull_request run, CI 37635720375 / Lint 37635720510, head cbb948b926). Step seconds from the jobs API:

step before (main push, base 3d9188502e) after (this PR)
Type Check · workspace Build workspace packages 297 s 1 s
Type Check · debt ledger: build, then ledgered build 335 s, then 31 s 1 s, then 1 s
Type Check · consumer gates: build, then nested build 330 s, then 30 s 1 s, then 1 s
dogfood 1/3, 2/3, 3/3 closure build 200, 336, 201 s 1, 2, 1 s
Temporal: driver-sql, non-SQL, metadata-protocol, runtime 1, 35, 0, 79 s 3, 3, 1, 3 s
Build Core (wiring unchanged) 6 s 7 s
Test Core new Build this shard's dependency closure, shards 1-6 — 1, 0, 0, 0, 0, 0 s

Most of that main-to-PR delta is the local actions/cache seed, which this run restored from the base push. The attributable reading is the same-base control, Lint 37632788013 (PR #22084: no remote, same seed), against Lint 37635720510:

  • debt Build the ledgered packages' dependencies: control Remote caching disabled / Cached: 66 cached, 71 total / Time: 29.447s; this PR Remote caching enabled / Cached: 71 cached, 71 total / Time: 527ms >>> FULL TURBO;
  • consumers nested build: control Cached: 66 cached, 71 total / Time: 29.819s; this PR Cached: 71 cached, 71 total / Time: 558ms >>> FULL TURBO.

The 5 tasks the control executed lie outside the plan the typecheck seed is saved from, so the remote served them here. Turbo's lines for the dogfood, workspace, driver-sql and non-SQL steps are NOT MEASURED: they fall outside the last 5000 log lines the read path returns. The merge-queue reading is pending: the seat takes it from this PR's own queue entry at landing and records it.

How to read the after numbers: a PR's restored actions/cache seed comes from the latest main push. A cache hit does not say whether the local seed or the remote served it. So the clean signal is the next main push after landing: today Build Core takes 6 s there while the Type Check lanes take about 300 s.

Kept as ruled

  • ⛔ No job removed, no required context changed, no new gate. check:required-contexts is green.
  • ⛔ The local actions/cache restore and save steps are untouched. They stay until the remote hit rate is measured.
  • ⛔ No new secret, and nothing written from a PR context.
  • turbo.json and scripts/** are not touched.

Local gates

The gates come from node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on this diff: 52 commands. Each exit code was written to disk before it was read. The full table, with exit codes and the --ran reconciliation, is in the os-dev-report on #22077. The workflow readers were green before this PR opened: check-ci-filter-parity, check-self-test-workflow-commands, check-step-collectors, check-self-test-wired, check-aggregator-roster, check:stall-guard-budget, check:workflow-step-name-quoting, check:required-contexts, check:pnpm-filter-targets and check:pm-expected-skips.

Acceptance notes

  • Dogfood Verify CLI and Console Pin Gate also run turbo builds. The card does not name them, so they are not wired here.
  • The Type Check · source gates lane runs no turbo build, so it has nothing to wire.
  • This PR changes only .github/workflows/**, which publishes nothing. skip-changeset applies.

Generated by Claude Code

… and Temporal build steps

Extends Build Core's remote-cache env block, verbatim (same write rule:
merge_group and push/workflow_dispatch on main write, everything else reads;
same signing; no new secret), to every `turbo run build` step of lint.yml's
three Type Check build lanes and of ci.yml's dogfood shards and Temporal
Conformance. Test Core built its closure inside the test step's own turbo run,
which must stay off the remote, so each shard now builds its `^build` closure
in a new guarded step that carries the block, and the test step replays it.

Build Core's comment gains the PINS every carrier points back to: build tasks
only, hash-identical to Build Core's plan, and root inputs declared.

Claude-Session: https://claude.ai/code/session_01VF48aw8RPG6wzDnMgp6rtw
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 7, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 7, 2026 14:49
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 7, 2026
Merged via the queue into main with commit b04a529 Oct 7, 2026
46 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-22077-turbo-remote-cache-jobs branch October 7, 2026 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

2 participants