Repository navigation
ci(lint): Type Check · workspace type-checks the affected packages on PR and queue runs; the whole workspace on push and schedule - #23043
Conversation
… PR and queue runs pull_request and merge_group select the packages their diff affects (plus dependents, plus the declared cross-package test radius) through ci.yml's own selector; schedule, push and workflow_dispatch keep the whole universe. A changed repo-root file, or a scripts/ file a package's own scripts run, means the whole universe: turbo ls --affected selects zero packages for a root package.json, pnpm-workspace.yaml, .npmrc or root-importer lockfile change. Claude-Session: https://claude.ai/code/session_01LqNgdPZB2Jnr5HpGbaqLeB Co-authored-by: Claude <noreply@anthropic.com>
…union is a stated superset Claude-Session: https://claude.ai/code/session_01LqNgdPZB2Jnr5HpGbaqLeB Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LqNgdPZB2Jnr5HpGbaqLeB Co-authored-by: Claude <noreply@anthropic.com>
… what the cache still decides Claude-Session: https://claude.ai/code/session_01LqNgdPZB2Jnr5HpGbaqLeB Co-authored-by: Claude <noreply@anthropic.com>
…w-file size ceiling The three previous pushes of lint.yml (513,738 bytes) each produced a failed workflow-file run with zero jobs, and the pull request got no Lint & Type Check run at all; main's copy is 505,924 bytes. The rationale lives in the pull request body. Claude-Session: https://claude.ai/code/session_01LqNgdPZB2Jnr5HpGbaqLeB Co-authored-by: Claude <noreply@anthropic.com>
维护者速读(终稿)· PR #23043 · 席位已对照 diff 逐行校正,2026-10-12T13:14Z改了什么: 为什么改:这一步中位约 8 分钟,是合并队列里最长的环节之一。卡上原以为是缓存键写错、PR 恢复不到 main 的缓存;dev 实测缓存能恢复(某 PR 139 个任务命中 138 个),真正原因是几乎所有包都依赖 spec:spec 一变,缓存里的结果全部作废,而队列里的条目总比 main 新,所以几乎每次都全量重跑。按改动范围挑包才是根治,缓存键那一步因此没改(改了也是空操作)。 风险与代价(含回滚):改仓库根目录文件(锁文件、根 package.json、tsconfig 等,Markdown 除外)或各包脚本共同调用的 席位意见:建议批准。队列的耗时主因被实测查清,方案不删不减任何检查(全量仍在 main 与每小时跑),合并队列上预计从约 8 分钟降到 1–3 分钟,落地后由席位读三次队列与三次 PR 实测回填。 你要做的:在 PR 上 Approve;席位随后翻正式并入队。 |
Fixes #23017
Clause-②: no
Type Check · workspace(thetypecheck-workspacelane behind the requiredTypeScript Type Checkcontext) now type-checks only the packages apull_request/merge_groupdiff affects;schedule,pushandworkflow_dispatchkeep the whole workspace (the full battery, #22998). The job name, theTypeScript Type Checkaggregate and its roster are unchanged. One file changes:.github/workflows/lint.yml, one step (Type check workspace packages) and the comment above it.The card's mechanism, measured first, and refuted
The card's hypothesis was that the turbo cache never restores on PR and queue runs because the restore keys are scoped to
github.ref_name. Onmainat edecd44 the restore step carries FOUR restore keys; the third is the bare prefix${{ runner.os }}-turbo-typecheck-, which matches the newest main-push save on every event. Measured on the jobs API and the job logs:claude/issue-22992-showcase-boot-splash): restore 10 s,Cached: 138 cached, 139 total,Type check workspace packages19 s. The cache restores.Cached: 64 cached, 139 total. All 64 hits arebuildtasks; 0 of 74typechecktasks replayed; step 512 s (turboTime: 8m31.023s).@objectstack/types#typecheckcomputed locally is88ca22ad9987a868at 3071d3e,5d35a004a079ced5at 2acff87, and30eade7d14ef0536from c7d6037 through edecd44, the last equal to the hash the merge group logged. 2acff87 and c7d6037 both touchpackages/spec. Nearly every package depends on spec, and atypecheckhash includes its dependencies'buildhashes.So the restore-keys fix the card proposes (a
-typecheck-main-line) would change nothing: the bare prefix already restores main's seed, and on PR runs main's saves are the only typecheck saves that exist. The seed misses because of hash churn. A merge group is built on entries that have not reached main yet, so its seed is behind by construction. Commit (1) of the suggested route was therefore not made. H4 (the build step misses for the same key reason) is refuted the same way: onpull_requestthe build step reads the remote cache (remote:r) and its misses are the PR's own affected packages, which nobody has written yet; onmerge_groupthe build step is aremote:rwwriter and its median is 114 s.What changed
The step's
run:, with the comment above it explaining each rule:pull_request/merge_group:scripts/ci/select-shard-packages.sh, ci.yml Test Core's own selector, called with the same event fields. Both jobs therefore read one rule for where a diff starts: merge-base withorigin/mainon a PR, the group'sbase_shain the queue, and the whole list with a::warning::when neither resolves. The selection includes dependents (turbo ls --affected). It also unions in packages whose tests read the changed files across a package boundary (check-cross-package-test-inputs.mjs --union-into), because their typecheck programs compile those same tests. For example, lint's and cli's tests importexamples/app-showcase, which no^buildedge reaches. The selection is intersected with the unchanged universe (./packages/*,./packages/*/*,./apps/*) and passed toturbo run typecheckas one--filter=NAMEflag per package.tsconfig.json,tsup.config.ts(theglobalDependencies) andturbo.jsonselect all 81 packages underturbo ls --affected. Rootpackage.json,pnpm-workspace.yaml,.npmrc, and a change to the ROOT importer'stypescriptversion inpnpm-lock.yamlselect ZERO. So any changed repo-root file (a path with no/) means the whole universe, except Markdown, because no tsc program reads a root*.md. A changedscripts/file that a package's ownpackage.jsonscripts run also means the whole universe. For example,scripts/check-test-typecheck.mtsis run by thetypecheckof 72 of the universe's 76 packages. That set is found withgit grepat run time, not kept as a list.turbo run typecheck, because that command with no--filterruns the whole workspace. Every doubt falls back to the whole universe: no changed-file list, a failed union, or a base that cannot be resolved.schedule,push,workflow_dispatchand any other event: the whole universe, as before. Thepush-only cache save is unchanged, so main's seed stays complete.turbo.jsonis unchanged. H2 found no input that moves on every commit: thetypecheckhash stays the same across commits that do not touch its dependency closure (measured above).Measurements
Before. The card (29 runs): step median 486 s, p90 627 s; job wall median 11.1 min, p90 14.2 min. Re-read over 300
lint.ymlruns (2026-10-11T20:38Z to 2026-10-12T11:35Z), counting only successfulType Check · workspacejobs:Selection replay. The final step script was run on the last 60 first-parent commits of
mainending at edecd44, each as a merge group on its parent.turbo lsand the union were real;turbo run typecheckwas stubbed. Results, out of a 76-package universe:The 6 whole-universe runs: 3 objectui pin bumps that also touch
packages/spec, 1 lockfile change, 1.gitattributeschange and 1 change toscripts/sync-scaffold-emission-policy.mjs.Local timing. On a 4-core / 15 GB box (the ubuntu-latest shape), with a fresh turbo cache dir and the dependency closure built beforehand, every selected typecheck task is a cold miss. A one-line diff in
packages/plugins/plugin-email/src/index.tsselects 11 packages:Compare that with the whole universe's 486 s median on the runner. With the seed restored, any of the 11 whose own hash is in the seed replays instead of running.
This PR's own run: run 38252457300 on
06f9521d—Type Check · workspacejob wall 56 s,Type check workspace packages2 s (log:No workspace package is affected by this diff -- nothing to type-check.);TypeScript Type CheckandLint & Repo Gatesgreen. Every turbo restore key missed on that run (Cache not found for input keys: Linux-turbo-typecheck-23043/merge-..., Linux-turbo-typecheck-, Linux-turbo-build-core-...), so the run also shows the step is independent of main's seed.Cache hit count: the dispatch asked for the turbo summary's hits on untouched packages. With this change, PR and queue runs do not schedule untouched packages at all, so there is no hit count to quote. The pre-change PR run 38239402273 above (138 of 139) shows that the restore already reaches main.
Gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderives 43 commands from this diff. All 43 ran on06f9521dand exited 0, reconciled with--ran(43 run, 0 NOT-MEASURED (a DERIVED zero ...)). They includecheck:required-contexts,check-aggregator-roster,check:type-check-coverage,check:type-check-debt,check:cross-package-test-inputs,scheduled-full-run --self-test,check:pm-dispatch-gates(fast tier, its off-CI default) andcheck:nul-bytes. No pin script flagged anything (H5): the step keeps its name and itsturbo run typecheckinvocation.The YAML was parsed with
yaml, and the extractedrun:passesbash -n. The script was also replayed against synthetic merge-group and PR diffs:package.jsonscripts/check-test-typecheck.mtsexamples/app-showcasepush/scheduleeventbase_shaAcceptance notes
The card and the claim call
.github/workflows/**Tier H, butGOVERNED_SURFACESinscripts/pm/check-governed-merges.mjshas no workflows row. This PR stays a draft as dispatched either way.typecheck's turbo inputs are package-local. A package scheduled through the union or the root rule still replays a cached green when its own hash is in the seed, on every event includingschedule. This PR does not change that, and the step comment says so. Declaring$TURBO_ROOT$inputs fortypecheck(astesthas them) would be the fix. It is not attempted here, because it changes hash semantics for every package.The union is a superset for tsc: it also names files that tests only read, so spec, core, types, objectql and runtime join most package diffs (+73 s cold in the local timing above). A tsc-only radius would need its own declaration and gate.
Root Markdown is exempt because AGENTS.md alone was 2 of the last 30 commits. Any other root file, including
.objectui-sha,.gitattributesandsdui.manifest.json, means the whole universe.lint.ymlis at GitHub's workflow-file size ceiling. This branch at 513,738 bytes (0bd33ce6,d4265926,b39592f3) produced a failed zero-job workflow-file run on each push (38245964547, 38249293618, 38250844690) and the PR got no Lint & Type Check run at all;06f9521dat 510,016 bytes is valid;mainis 505,924 bytes. The step comment was compacted for that reason, and this body carries the rationale. The ceiling itself is carded by the seat (a gate on the file's size and a split plan).维护者速读(草稿)
改了什么:
Type Check · workspace这条类型检查车道,在 PR 和合并队列上只检查本次改动影响到的包(含依赖它们的包);每小时定时、推到 main 和手动触发仍然全量检查。作业名、必需检查TypeScript Type Check及其成员都不变。只改了.github/workflows/lint.yml里的一个步骤。为什么改:这一步的中位耗时约 8 分钟,是合并队列里最长的环节之一。卡片原先以为是缓存键写错,导致 PR 恢复不到 main 的缓存。实测缓存其实能恢复(某个 PR 的 139 个任务命中了 138 个)。真正的原因是几乎所有包都依赖 spec:只要 spec 一变,缓存里的检查结果就全部作废;而队列里的条目总比 main 新,所以几乎每次都全量重跑。按改动范围挑包才能根治。
风险与代价(含回滚):改动仓库根目录的文件(锁文件、根 package.json、tsconfig 等,Markdown 除外),或改动各包类型检查共同调用的脚本时,一律全量检查,不交给 turbo 判断。实测 turbo 对根 package.json 的变化、以及锁文件里 TypeScript 版本的变化,都会判为"没有包受影响"。被其他包的测试跨包引用的包(例如示例应用被 lint/cli 的测试引用)也会被并入检查。代价是:普通的包改动会顺带检查 spec 等五个大包,冷启动时约多 70 秒。改动了 spec 的提交(约占三分之一)仍然接近全量。回滚只需还原这一个步骤,不涉及数据或产物迁移。
席位意见:
你要做的:审阅后决定是否批准这个草稿 PR。落地后,由 PM 读取连续三个合并队列和三个 PR 的实测耗时。
Body amended by the director seat from the dev's report 6124930963 (three stale spots named there: the gates sha, this PR's own run, the size-ceiling note), 2026-10-12T13:13Z.
Generated by Claude Code