chore(ci): lint.yml 的 typecheck 补 build-core 的 turbo 缓存回退 (#5401) - #5542
Merged
Conversation
…5401) Only main writes the Turbo cache, so a merge_group entry always restores by PREFIX. This job's chain covered only its own job namespace, which has a window where that prefix matches nothing at all: the previous main generation is already gone while the current one is still being written. Measured 2026-08-05 (run 30985524210, job 92239260750): at 07:34:18Z all three keys reported "Cache not found" and "Build workspace packages" went from 4s to 4m54s, while the very same queue entry's ci.yml jobs hit `-main-f417863f` in that same minute. build-core's entry survives the window - its main-push save completed 07:32:50Z, 88s earlier - and `pnpm build` (turbo run build --filter=!@objectstack/docs) is a superset of this job's build step. Adds the two build-core fallbacks the Temporal Conformance / Dogfood Verify / Console Pin jobs in ci.yml already carry, spelled byte-identically. The writer is untouched: "Save Turbo cache (main only)" keeps its condition and key, so the single-writer discipline is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BWS4heBoAitLmzCLhcYdbK
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
os-zhuang
marked this pull request as ready for review
August 5, 2026 17:16
This was referenced Aug 5, 2026
os-zhuang
pushed a commit
that referenced
this pull request
Aug 5, 2026
本 PR(#5650)自己按新硬步骤执行时,实测结果与原措辞相反:标签 22:03:54 落地, `opened` run(workflow run 31051251795,创建于 22:03:38)的 Check Changeset job 直到 22:04:35 才启动并做实时标签回读 —— 早于回读 41 秒落地的标签被读到,该 run 直接 **success**,并非预设的红。 于是这一句改为如实描述竞态:首 run 的颜色取决于 runner 启动耗时与 POST 落地 的先后,两个方向都有实例(#5542 红、#5650 绿)。指导语随之从「预期会红」改为 「尽快落标签,把首 run 的颜色当信息而不是自己的判决」。 预设方向被自己的实测证伪时如实记录,而不是让措辞压着实测走。
akarma-synetal
pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Aug 6, 2026
…tstack-ai#5650) * docs(os-dev): PR 收尾清单增补 `skip-changeset` 硬步骤,以回读 PR labels 为闭环 (objectstack-ai#5559) 测试-only / 工作流-only / `.claude/`-only 的 PR 不写 changeset,靠 `skip-changeset` 标签豁免 Check Changeset。此前收尾清单对这一步只字未提,dev 在 PR 正文「声明」了 标签却没有真正挂上,objectstack-ai#5533/objectstack-ai#5538 两例各烧一轮门禁红并由 PM 手工兜底 —— 「声明了 ≠ 执行了」正是 declared ≠ enforced 的 agent 版。 新增条目把它写成与「PR 正文以 Fixes 开头」同级的硬步骤,并按实测校正了三处认知: - 没有任何自动化会替你挂:`.github/labeler.yml` 九条规则里没有 `skip-changeset`, 2026-08-05 六例(objectstack-ai#5533/objectstack-ai#5538/objectstack-ai#5542/objectstack-ai#5624/objectstack-ai#5642/objectstack-ai#5645)的该标签全部来自 agent, `github-actions[bot]` 一次都没挂过 —— 它只负责 `size/*`、`documentation`、 `tests`、`ci/cd`。 - 只「加一个标签」,不要整集写入:整集写入会把 bot 刚挂的 `size/*` / `documentation` / `tests` 抹掉(objectstack-ai#5533/objectstack-ai#5538/objectstack-ai#5642/objectstack-ai#5645 的 agent `unlabeled` 事件即此),反向也成立 —— objectstack-ai#5533 的标签 15:46:44 落、15:46:45 就被 `github-actions[bot]` 的写入抹掉,只活了一秒。 - 闭环是回读而不是 POST:Check Changeset 在 PR 打开后数秒就实时读一次标签 (objectstack-ai#5580),`opened` run 通常早于标签落地 —— objectstack-ai#5542 的 dev 做对了全套,仍留下 一条红 `opened` run,之后每一次 run 才被标签豁免。所以要在 bot 平息后回读 标签、并把读到的列表写进报告。 * docs(os-dev): 首 run 颜色按实测改成双向竞态,不再预设为红 (objectstack-ai#5559) 本 PR(objectstack-ai#5650)自己按新硬步骤执行时,实测结果与原措辞相反:标签 22:03:54 落地, `opened` run(workflow run 31051251795,创建于 22:03:38)的 Check Changeset job 直到 22:04:35 才启动并做实时标签回读 —— 早于回读 41 秒落地的标签被读到,该 run 直接 **success**,并非预设的红。 于是这一句改为如实描述竞态:首 run 的颜色取决于 runner 启动耗时与 POST 落地 的先后,两个方向都有实例(objectstack-ai#5542 红、objectstack-ai#5650 绿)。指导语随之从「预期会红」改为 「尽快落标签,把首 run 的颜色当信息而不是自己的判决」。 预设方向被自己的实测证伪时如实记录,而不是让措辞压着实测走。 --------- Co-authored-by: os-zhuang <hr@objectstack.ai>
This was referenced Aug 6, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5401
工作流-only 改动,
.github/workflows/lint.yml的typecheckjob 的Restore Turbo cache步加两条restore-keys。净增 21 行、删 0 行,写入方一字未动。依据:先量再改
本 PR 的全部依据是落在 issue 上的一手测量:#5401 的评论 5194564203(只读调查,无状态干预)。它同时否证了 issue 正文的方向 1,所以本 PR 做的不是方向 1:
正文方向 1 是「给恢复步加 main 前缀 restore-keys」。它早就在文件里:链尾那条
${{ runner.os }}-turbo-${{ github.job }}-,即Linux-turbo-typecheck-,比任何「main 前缀」都更宽 —— main 写入的键就是Linux-turbo-typecheck-main-{sha},裸前缀本就前缀命中它。没有任何 restore-key 能加得更宽。事故 run
30985524210/ job92239260750,07:34:18Z 的日志把三条键全列了出来并全部 not found,含最宽那条:而基线 run
30985094934(07:27:59Z)用同一条链命中了Linux-turbo-typecheck-main-58975525c9bffcc2afa834465a3e4bec4e21cbcb—— 证明 merge_group 的 ref 本就读得到 main 作用域的缓存,不是权限/作用域问题,也不是缺前缀。所以真实缺口是:这条链只覆盖自己的 job 命名空间,而该命名空间存在一个「上一代已消失、当代还没写完」的空窗。
现有 key 的构成 / 加了什么 / 为什么它能命中
typecheckjob 的 key 与 main 的写入键:{os}-turbo-{job}-{ref_name}-{sha}Linux-turbo-typecheck-gh-readonly-queue/main/pr-5398-f417863f…-98369a86…ref_name=mainLinux-turbo-typecheck-main-{sha}加的两条(位于链尾,只读):
第二条前缀匹配 ci.yml
build-corejob 在 main push 上写入的Linux-turbo-build-core-main-{sha}。两条与 ci.yml 的 Temporal Conformance / Dogfood Verify / Console Pin 三个既有消费 job 的写法逐字节相同(ci.yml:466-467 / 746-747 / 1135-1136),已用脚本断言过集合完全一致,含缩进。用 #5401 那次实测反推「若当时有此回退会命中哪个 key」:同一次 main push 的 ci.yml run
30985383135里,Build Core的Save Turbo cache (main only)在 07:32:47Z → 07:32:50Z 就 success 了;typecheck的恢复步在 07:34:18Z 才执行,晚 88 秒。所以那一刻Linux-turbo-build-core-main-f417863f…已在池中可读,第 4 条 restore-key 会前缀命中它 —— 同一队列条目的 ci.yml 各 job 也正是在那一分钟里全部命中-main-f417863f…(Build Core / Test Core (1/3) / Dogfood Regression Gate (1/3)),互为佐证。而 build-core 跑的是
pnpm build=turbo run build --filter=!@objectstack/docs(整个 workspace 除 docs),是本 job 构建步turbo run build --filter='./packages/*' --filter='./examples/*^...'的超集 —— 与 ci.yml 那三个 job 注释里给出的理由同源。陈旧 / 异构缓存的正确性
回退到一个更旧或由别的 job 写入的缓存都不会产出错误结果:turbo 的缓存是按内容哈希寻址的,每个 task 的复用与否由该 task 的输入哈希决定,而不是由
.turbo/cache这个目录从哪儿来决定。哈希不匹配的 task 一律重跑,只是少了一次命中;哈希匹配的 task,其输出按定义就是这份输入应当产生的输出。所以「旧而温」严格优于「冷」,「读别的 job 的条目」也只是多一批可能命中的 entry,不引入任何新的正确性面。写入方保持原样以维持缓存单写者纪律:
Save Turbo cache (main only)的if: always() && github.event_name == 'push'与 key 均未改,merge_group 条目仍然只读不写。方向 2(对 cache-save 未完成做短等待)按裁定维持否决 —— 它给每个条目加固定延迟,与提速目标相反。验证(工作流改动无本地运行时,以下为代偿,未跑的项如实说明)
node scripts/check-workflow-status-functions.mjs用 CI 同一个yaml解析器parseDocument走了全部 22 个 workflow(含本文件):check-workflow-status-functions: OK (scanned 22 workflow file(s), 39 job(s), 19 job-level if: expression(s); 9 read needs.*.outputs.*, all naming a status function).,--self-test34 assertions 通过。另用 Pythonyaml.safe_load解析后回读了该步的 key 与 4 条 restore-keys、以及 save 步的if/key(确认未变)。仓库未依赖 actionlint,容器内也没有,故未跑。check-nul-bytes: OK (scanned 5500 tracked text file(s); …; no raw ASCII control bytes),--self-test48 assertions 通过;并对改动文件做了越过门禁盲区的自扫(C0 全集 + DEL),零命中。1 file changed, 21 insertions(+),删除 0 行;两条功能行 + 一段说明注释,写入方与其余 6 个 turbo 恢复步全部未动。pnpm test/pnpm typecheck,也没有可加的单测 —— 这条改动的正确性只能由落地后的 run 日志判定,判据见下。落地后的可观测判据(「部分温」,不承诺基线的 4 秒)
后续任何紧跟 main 合并入队的 merge_group 条目,其
TypeScript Type Checkjob 应表现为:Restore Turbo cache打印Cache hit for restore-key: Linux-turbo-build-core-main-{sha}(而不是 0 秒的Cache not found for input keys: …);Build workspace packages明显低于事故那次的 4m54s。明确不承诺回到基线那 4 秒:build-core 只写
build任务,不跑typecheck任务,所以本 job 的Type check workspace packages一步仍只能靠自己的命名空间 —— 命中 build-core 时那一步照旧是冷的。即「暖构建步、不暖 typecheck 步」,这是本改动的设计上限,不是缺陷。未做的部分(留在 issue 里)
上一代条目为何在 6 分钟内从池中消失,未能证实:
GET /repos/…/actions/caches被调查会话的出网代理拦截。按每代约 12 个 job 键 × 250-300 MB ≈ 3 GB、池上限 10 GB 粗估,新一代写入挤掉上一代是最自然的解释。若成立,则杠杆在池容量 / 条目体积 / 远端缓存(方向 C),按裁定只留 issue 记录不做;shardedtest/dogfood也带同样的「仅自身命名空间」链,但无实测拉力,本 PR 不扩。工作流-only,无用户可见变更 → 挂
skip-changeset,不带 changeset。Generated by Claude Code