# Testdata Validator 工具箱 五步:**验契约 → 读 case → 真的跑一遍 → 交执行器比对 → 写判决**。 > 🚨 **发 JSON 的铁律**:任何带 JSON 的内容,一律用**文件写入工具**直接写文件, > **绝不在 bash 命令里内联 JSON 字符串**(多重双引号会让工具调用崩溃并陷入死循环)。 > JSON 里不许有真实换行符。 以下命令里: ```bash R=data/companies/<公司ID>/runs/ # root run 目录 D=$R/nodes/<你的 nodeRunId> # 你自己的目录(提示词里给了绝对路径) n=<本轮 attempt 号> ``` --- ## 1. 验契约(决定你这一轮有没有活干) ```bash node server/services/goal-contract.js validate --run-dir $R ``` 看它打印的 `sections:` 一行有没有 `test_data`。**没有就 `skipped` 放行**,这是常态。 退出 `1` / `2` 都按 `input_underspecified` 判,把打印的 `[rule] detail` 原样抄进判决。 ## 2. 读 case(**只读**) ```bash cat $R/artifacts/acceptance.json # test_data 段,可能是 {"$ref": "goal-test-data/…"} ls $R/artifacts/goal-test-data/ ls <提示词给的被测产物目录> # 被测产物:路径由引擎在提示词里给 ``` ❌ **不要读提示词没给到的节点目录**(§四.A.5 隔离规则)。 ❌ **不要写 `$R/artifacts/` 下的任何文件**——共享产物区对你只读, 判决由 `run` 自动落到 `artifacts/verdicts/`。 ## 3. 真的跑一遍(本岗位唯一不可替代的动作) 按 `case.input` 驱动被测产物。允许起进程、调接口、跑脚本—— **这是本岗位唯一被允许"执行"的地方**,做法参照 DevLoop Integrator 起真实进程跑 e2e。 ```bash # 形态取决于被测产物;下面是三种常见起法 node <被测脚本> <按 case.input 拼的参数> curl -s -X POST http://localhost:3010/<接口> -d @/tmp/case-.json -H 'Content-Type: application/json' npx vitest run <被测产物里的测试文件> ``` > 🚨 需要发 JSON body 时,**先把 JSON 写成 `/tmp/case-.json` 再 `curl -d @文件`**, > 绝不在命令行里内联 JSON 字符串。 跑不通的 case 也要记(`{"error": "TIMEOUT"}` 之类),**不许省略、不许拿 `expect` 凑数**。 ## 4. 写结果文件 + 交执行器比对 用文件写入工具写 `$D/attempt-$n.results.json`,形如 `{"results": {"": <实际输出>, …}}`。 文件名后缀 `.results.json` 是有讲究的:引擎认判词只认严格的 `attempt-.json`, 而 `goal-contract.js` 能从这个文件名推出 `nodeRunId` 与 `attempt`。 ```bash node server/services/goal-contract.js run --run-dir $R \ --target $D/attempt-$n.results.json --run-id <本次 runId> --json ``` 退出码:`0` 判决 pass / `1` 判决 fail / `2` 跑不出判决。 **只读 `sections.test_data` 那一格**,顶层 `ok` 含别的 section,不是你的结论。 ```bash node server/services/goal-contract.js list --run-dir $R --only-failed --limit 10 node server/services/goal-contract.js show --run-dir $R --verdict-id ``` ## 5. 写判决回执 用文件写入工具写 `$D/attempt-$n.json`(形状见 `agent.md`「产出格式」,`schema: "work-validator/v1"`)。 **这份文件不写 = 引擎判「无法判定」= 直接按失败走兜底边** (节点名以 `-validator` 结尾,`graph-engine.js` 的 `requiresAttributionProduct` 强制要求它存在)。 **不要覆盖上一次 attempt 的文件。** 写完只回一句话总结:过没过 + 哪几条 case 挂了 + 一句理由。 --- ## 你**不该**用的工具 | 别用 | 为什么 | |---|---| | `goal-contract.js put …` | 那是**出题**(写样本集),不是你的活。样本错了要打回去 | | 任何写代码 / 改样本的工具 | 你跑卷,不出卷也不修卷 | | 任何写 `$R/artifacts/` 的动作 | 共享产物区对你只读;判决由 `run` 自动落盘 | | `node bin/lemon.js task dispatch`(尤其发给 `innovator`) | 判了 `skill_defect` 也只挂起等人工,L4 是 P3 非目标 | | 训练 / 进化 / retrain 相关的一切 | 同上 | | 直接写 `data/` 下的 sqlite | 状态由引擎从你的 JSON 里读走并落库 | | 读提示词没给到的节点目录 | 隔离规则 | | 给出「该怪哪个 org node」的最终归因 | 那是 `validator-triager` 的活;你只给本段的 `fail_reason` |