-
## 病症 agent-chat-tenant-isolation.test.js 每跑一次,往共享生产库 data/graph.sqlite 落 2 条 goal + 2 条 task。实测 29→31。库里 31 条 goal 里 **22 条是它的残留**, 测试期间一直全绿。 根因是批 5 的存储迁移留下的半截清理:/task/dispatch 的元数据从 system/tasklog/*.json 换进了 tasks 表,而这个用例的 afterAll 只会清那个目录 —— 清理代码还在、清的东西已经不在那儿了。 ## 这是第四次,但换了个方向进来 前三次(BENCHMARK_DB_PATH / USERS_DB_PATH / SKILLS_DIR,记在 test-isolation-env.test.js 文件头)都是「设了 env,生产代码不读」。 那条守卫查的正是这个形态。 这次是**一个字都没设** —— 没有可查的东西,守卫自然查不出来。 静态扫源码也判不出「这个测试会不会开库」(要跨 require 链推导)。 ## 修法 1. 用例自己开一次性库(fs.mkdtempSync + GRAPH_DB_PATH),afterAll 连目录删掉。 赋值必须在 require 路由**之前** —— graph-db.js 的 DB_PATH 是模块级 const。 2. graph-db.getDb() 加运行期闸门:VITEST 为真且没设 GRAPH_DB_PATH → 抛, 报错里点名 env、点明「要在 require 之前设」。 放在 getDb() 不放模块顶层:只为取常量而 require 是合法用法 (goal-task-model.test.js 就这么用),顶层抛会误伤。真正开库才是越界那一刻。 3. 守卫 graph-db-prod-guard.test.js,4 例:撞库要抛且报错可照做、设了 env 要能开、 没有 VITEST 时不生效(防止把生产一起锁死)、样本非空。 反向验过:注释掉闸门那一行,第 1 例立刻红。 ## 顺带修一条 flaky(我自己上一版留下的) agent-docs-port.test.js 先 walk 出文件清单再逐个读,中间别的用例把 zz-* 夹具的 运行态目录清掉 → ENOENT。**报错长得像端口违例,其实跟端口无关**,实测 8 次跑中 2 次红。 只放过 ENOENT 一种(文件没了),其它读错误照抛 —— 一律 try/catch 吞掉的话, 权限错、编码错会被当成「无违例」。 ## 存量清理 删掉生产库里 created_by LIKE 'zz-tenant-%' 的 22 goal + 22 task (备份 /tmp/graph.sqlite.bak-c3a5d46)。零 run 引用它们。 其余 9 条 goal 是真实数据,一条没动。 全量:136 文件 / 1276 测试,连跑 8 次全绿(改之前 8 次里红 2 次)。 跑完后生产库行数零增量。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>