测试一直在写你的真实数据根
开发记录 · 2026-08-10 · RepoPilot
给权威层补 e2e 的时候,全量跑出 3 条红。重跑一遍,红的换了两条。再跑,全绿。
偶发红最烦人的地方不是它红,是它绿。
起因:三条"接线靠 typecheck"的欠账
README 的「尚未证明的」里攒了三条同型缺口:交叉审核收敛闭环、挽救封存、 failureClass ------ 语义各有单测钉着,但 authority 侧的真实接线没有独立验证, 靠的是类型检查。类型检查能证明函数签名对得上,证明不了"这条线真的通"。
所以写了 authority.e2e.test.ts:驱动整个 RunAuthority,真 ModelGateway、 真协议适配器、真 preflight、真 egress 记账、真命令执行(spawn node)、真落盘。 模型脚本化在 HTTP 层,按 origin 分路:
ts
const host = new URL(String(url)).host; // deepseek = 实现方,moonshot = 审核方
const queue = this.queues.get(host);
if (!queue || queue.length === 0) {
throw new Error(`${host} 的模型脚本已耗尽。最后请求:${bodyText.slice(-600)}`);
}
脚本耗尽即抛错并带上下文,不复读最后一条 ------ 复读会把死循环伪装成通过。
三条链路:黄金路径(→ SUCCEEDED,账本逐轮对账)、失败路径(自修复用尽 → FAILED
- failureClass + 挽救补丁,接受被状态门禁拒绝)、整改闭环(阻断 → 整改 → 重验 → 重封存 digest 变化 → 第二轮通过)。
后两条首跑即绿。这本身是个信息:之前那些单测钉住的语义,在真接线里一处都没对不上。
然后偶发红出现了
perl
× 端到端:Vite + React + TS 构建失败修复
→ expected 'PREVIEW' to be 'VERIFIED'
× 用户拒绝计划:结果是 PLAN_REJECTED,且工作区与宿主都零改动
→ EINVAL: invalid argument, copyfile '.../T/repopilot-scen-8OSv9R/package.json'
-> '~/Library/Application Support/RepoPilotPrototype/snapshots/snap_71c850...'
× exact-span replace > 唯一命中时原子提交,并推进 generation
→ ENOENT: no such file or directory, lstat '.../snapshots/snap_cc77b503...'
三条错得毫不相干:一条是 profile 支持度降级,一条 copyfile 参数非法, 一条快照目录不存在。但路径全都指向同一个地方 ------ ~/Library/Application Support/RepoPilotPrototype。
测试在往我的真实数据根里读写。
写个循环扫一遍谁没 mock:
bash
MOCKED src/core/patch.test.ts
REAL!! src/core/mutation.test.ts
REAL!! src/core/retention.test.ts
REAL!! src/core/agent.e2e.test.ts
... 11 个文件
11 个测试文件直接用真实数据根。而 retention.test.ts 是清理器 的测试 ------ 它会真的执行清扫。vitest 并行跑文件,于是:retention 正在删"无引用的快照", mutation 那边刚创建的快照撞上去了。ENOENT、EINVAL、profile 降级, 全是同一件事的不同表现。
这债不是这次欠的,是一直都在 ------ 只是文件少的时候撞不上。 「528 全绿的套件偶发红 3-4 条」的谜团,到这里破了。
修:统一注入私有数据根
11 个文件统一挂 vi.mock('./paths'),指向 mkdtemp 出来的进程私有目录。 vi.mock 会被提升到 import 之前,所以模块图里所有拿 PATHS 的地方都换掉了。
验证不能只看"绿了"------绿也可能是这次没撞上。用文件系统本身证明零写入:
bash
touch /tmp/marker-before
npx vitest run src/core/mutation.test.ts
find "$HOME/Library/Application Support/RepoPilotPrototype" -newer /tmp/marker-before
# (空)
整轮测试对真实数据根一次写入都没有。这条以前是不变式里写着的 (「自检和测试不能留下持久化改动」),现在才第一次有机器证据。
连续 4 轮全量 531 通过,之前那个组合再没出现过。
反向验证
新加的 e2e 得证明它真在管事。把 VERIFICATION_FAILED 分支的挽救封存接线拆掉:
scss
× 验证失败路径:自修复用尽 → FAILED + failureClass + 挽救补丁封存且不可接受
Tests 1 failed | 2 passed (3)
红了,接回去,绿。
可以带走的
- 偶发红是基建债的信号,不是运气问题。 三条互不相干的错,路径全指向 同一个目录 ------ 错误信息里最有用的往往不是错误类型,是那个共同的名词。
- 共享可变状态的测试没有"暂时没事"。 文件少的时候撞不上,只是采样不够。
retention那种会主动删东西的测试,一旦跑在共享根上,就是个定时器。 - "绿了"不是隔离的证据。 要证明隔离,得证明没有发生什么 ------
find -newer这种否定式检查比断言返回值更贴近命题本身。 - typecheck 证明签名对得上,证明不了线是通的。 那三条 README 里的 "靠 typecheck",补完 e2e 才变成真证据;而它们首跑即绿这件事, 反过来说明单测钉的语义是对的。