fix(spec): 给 packages/spec 的 vitest 设 testTimeout 60s —— 止血,不再把无关 PR 踢出合并队列 (#4850) - #4856
Conversation
packages/spec/vitest.config.ts never set testTimeout, so every case ran under vitest's 5000ms default. Twelve tests load the TypeScript compiler in-case and type-resolve the whole export surface (ts.createProgram + getTypeChecker), which is seconds of work by construction. Measured on an idle runner the slowest such case is 3.4s against a 5000ms budget — green on a PR branch, too thin on a merge-queue runner building several PRs at once. Five failures in one night, all inside the queue, each evicting an unrelated PR. Set at the config layer so all twelve are covered, and so a thirteenth is covered on arrival — PR #4506 set the same 60s value case-by-case and only covered the ones red at the time. Stop-the-bleeding only; the underlying per-run TypeScript compilation cost stays tracked in #4796. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015Br2xsJsczFsTR9bvbh2Ny
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 1 package(s): 106 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
复核通过 —— ACCEPT,已标 ready 并送合并队列派发时我给这一单加了三条 issue 正文没有的要求,因为「一个修没验证过的配置的 PR,如果自己也没验证,就是在犯同一种错」。三条逐条兑现了: 1. 核实这一行不会被别处遮蔽。 这是我最担心的失败模式 —— 加一行看似修好、实则被更高优先级配置吃掉。dev 逐个排除了:无根级 2. 证明新值真的作用到了。 临时 6000ms 探针用例,改前 3. 量了真实耗时,而且这个数改变了结论。
所以 5000ms 是「紧,但不是刚好」—— 余量只有 1.46 倍,而拥挤的队列 runner 正好把它吃掉。60s 是最慢用例的 ~17.5 倍,宽到能吸收争用,又不至于把真正的死循环掩盖成"跑得久"。这个数据本身就是 #4796 命中率的解释。 范围与边界都守住了2 个文件 / 44 行, #4796 保持打开这一点它做了主动核验 —— 不是"我没写 Fixes 所以应该没事",而是把存进 GitHub 的 PR 正文读回来确认 4796 附近没有任何 closing 动词、且正文没被 sanitizer 破坏。这正是本仓 它顺手报的一个数,把 #4796 的紧迫性钉死了dev 在 #4796 上留了测量数据:这 12 个文件 88% 的测试时间(44.2s 中的 39.0s)是纯 TypeScript 编译,每轮 CI 重复,且随导出面增长。并且明确指出:
说得对。这是止血,不是解。方向 2(把导出面解析提成构建期产物)能同时回收那 39 秒并且把一个非确定性超时变成确定性比对。#4796 仍归 spec 车道,建议按"仍然紧急"对待。
Generated by Claude Code |
Fixes #4850
Related: #4796(保持打开 —— 方向 2「把导出面解析提成构建期产物」仍归 spec 车道,本单只是它的止血)
改了什么
packages/spec/vitest.config.ts的test块加一行testTimeout: 60_000(带注释),外加一个 patch changeset。改动面仅此两个文件,不碰任何.zod.ts、测试逻辑、spec-changes.json、liveness 台账与生成基线。根因复核(我自己重新取证了一遍,不是照抄 issue)
三条都在
origin/main上确认过:testTimeout——git show origin/main:packages/spec/vitest.config.ts里test块只有globals/environment/include/coverage,吃 vitest 默认 5000ms。(await import('typescript')).default并ts.createProgram+getTypeChecker。我遍历origin/main上全部 282 个 spec 测试文件逐个 grep,命中数正好 12,与 issue 列的清单完全一致。origin/main63 个提交,直接在工作树里 grep 只会命中 0 个(那几段是后来的提交加的)。这类核查必须对origin/main做。vitest.config.*也没有vitest.workspace.ts;packages/spec的 test 脚本是裸vitest run(无--testTimeout);turbo.json的testtask 不传参;workflows 里没有任何VITEST_*/TEST_TIMEOUT覆盖。全仓已有testTimeout的 5 个包(metadata-fs、qa/http-conformance、client、driver-mongodb、plugin-auth)都是各自的包内配置,管不到 spec。所以这一行是真正生效的那一层,不是被更高优先级配置盖掉的空操作。验证「它真的生效了」
没有只靠读配置。临时加了一条
await new Promise(r => setTimeout(r, 6000))的探针用例:Error: Test timed out in 5000ms.—— vitest 自己在报错里提示configure it globally with "testTimeout"。Test Files 1 passed (1),Duration 6.36s。探针用例已删除,不在提交里(
git status干净,diff 只有上述两个文件)。这 12 个用例的实际耗时(issue 要求先测量再定数)
空载 runner 上跑这 12 个文件:
12 passed / 497 tests,用 JSON reporter 取单用例耗时:system/environment-artifact的导出面解析)结论:60s 余量充足,不薄。 同时这组数字正好解释了 issue 里那个「PR 分支一次没红过、5 次全发生在队列里」的现象 —— 空载最慢 3.4s 顶 5000ms 的预算,余量只有约 1.46 倍,队列 runner 同时构建多个 PR 批次时轻易被吃掉;而 60s 要被吃掉需要 17 倍的减速,属于真挂起才会触发,不会把真 bug 盖住。
但请注意方向 2 的紧迫性没有被这一行降低: 这 12 个文件里,耗时超过 800ms 的 16 条用例合计 39.0s,占这 12 个文件全部用例耗时(44.2s)的 88% —— 每次 CI 跑一遍就是近 40 秒纯 TypeScript 编译,而且随导出面增长。止血归止血,#4796 的本体仍然值得做。
为什么设在配置层而不是逐条加
PR #4506 就是逐条
{ timeout: … },只覆盖了当时红的那几条;池子有 12 个,而且新增的照样漏。配置层一次覆盖全部,第 13 个到达即被覆盖。60s 沿用 #4506 当初给同族用例定的值,不引入新数字。测试
均在
flock -w 7200 /tmp/os-heavy-verify.lock下、带NODE_OPTIONS=--max-old-space-size=4096与--maxWorkers=2执行:pnpm --filter @objectstack/spec test→Test Files 294 passed (294)/Tests 7362 passed (7362),Duration 102.26spnpm --filter @objectstack/spec typecheck→tsc --noEmit无输出(通过)未触及任何生成物对应的输入面(
.describe()、公共导出、authorable key、ADR-0087 registry、SKILL.md、react-blocks),故未重新生成 spec 的生成物。跨车道说明
packages/spec/**常态归另一个 PM 车道,本单是经维护者批准的跨车道止血,因此改动面严格限死在vitest.config.ts一行 + changeset。过程中在别处看到的问题一律只写进报告,未动手。🤖 Generated with Claude Code
https://claude.ai/code/session_015Br2xsJsczFsTR9bvbh2Ny
Generated by Claude Code