# 34-validator-scored-without-real-deliverable. coder-validator 在没有真实产物的情况下给了满分 > **日期**: 2026-08-22 > **状态**: 📝 **调研记录,非设计方案,§四 checklist 已全部查完**。§一/§二的核心 > 前提已被 §零 推翻大半——原始判断("index.html 从未被写出来")是错的,真实网站 > 文件其实存在,只是不在 `graph_files` 索引里。§五追加查完三件事,且 §5.1 中途 > 自我订正过一次:① 最初以为"validator 没有浏览器工具、物理上做不到检查"—— > **这个判断错了**,`bash` 能走到真实 Playwright(仓库自带该依赖),另一条对照 > 任务证明了这条路能走通;真正的差异是**有没有 agent 主动想到要这么做**, > 这次没有;② 确实有一份真实静态断言脚本代替了 5/6 维度的检查,不是空手套白狼; > ③ 抽查另外两个已存在的项目根后发现**验证严谨度完全不稳定**——同类任务里有的 > 做了真实 Playwright 级验证、有的只做了静态正则、有的没验证就被取消,"任务已 > 完成"背后的验收严谨程度全靠单次任务规划时 agent 会话即兴发挥与提示词是否填充 > 完整,没有系统性保证。顺带在 `unit-tester` 本体身上撞见一次 > [32 号文档](./32-hire-body-fill-reliability.md) 那类"招聘装配没填充完"的真实 > 样本——这很可能才是这次检查偏弱的**直接原因**,而不是工具限制。是否需要引擎级 > 前置闸门统一验证严谨度,留给下次设计。 > **触发**: `e2e-demo` 公司真实回归任务 `T-mt2r6fz0-125b`(goal `G-mt2r62ia-73af`, > root run `run_0e9074815130`)——[31 号文档](./31-work-graph-fail-fallback-coverage.md) > 兜底边修复 + [33 号文档](./33-needs-gate-role-filter-bug.md) 契约修复之后,把这条任务 > 真正推到 `completed`,回头查"最终产出在哪"时发现的 --- ## 零、2026-08-22 补充:原始判断错了一半——真实网站文件其实存在 写这份文档时只查了两处:`org-coder-impl`/`org-coder-test` 各自的节点私有目录 (`runs/{rootRunId}/nodes/{nodeRunId}/`)和 `graph_files` 索引表,两处都没有 HTML/CSS/JS,于是断言"首页从未被写出来"。 后来在**同一次会话里**给控制台加"任务产物汇总"面板(用户反馈的另一个需求)时, 读 `graph-engine.js` 的 W2 段落才发现:这个引擎给每个任务的代码分配了一个**跨节点 共享的项目根**(`ensureProjectRoot`,复用 DevLoop 的 `path-resolver.allocateProjectRoot`, 落在 `data/companies/{cid}/projects/{pid}/`),这个目录**不受 `graph_files`/ `indexNodeOutputs` 覆盖**——后者只扫每个节点自己的私有产出目录。真去看 `data/companies/e2e-demo/projects/p-v82tpc/` 才发现: ``` index.html 2.2KB 真实的 apple.com 风格单页站点(hero + 3 个卖点区块 + 平滑滚动导航) script.js 1.0KB styles.css 3.3KB tests/unit-tester.check.js workgraph-plan-T-mt2r6fz0-125b.md ``` 内容核对过:3 个卖点区块的标题与顺序(多智能体协作 → 全链路自动化 → Skill 竞技场) 与 `org-coder-impl` 自己 `_plan.md` 里写的验收对照表逐字对应,不是空壳/占位文件。 **这次查漏的教训**:`graph_files` 索引 + 节点私有目录,只是这个系统里**两个**产出 落点中的一个;第三个(项目根)当时完全没查。下面 §一/§二 保留原文作历史记录, 但"index.html 从未被写出来"这句话是错的,请按本节订正读。 ## 一、(原始记录,前提有误,见 §零) ## 一、现象 任务最终状态:`completed`,`org-planner` / `org-coder` / `org-validator` 三个 org 节点 全部 `success`。但查 `org-coder-impl`(`rn_e71be3641174`)的实际产出目录 (`data/companies/e2e-demo/runs/run_0e9074815130/nodes/rn_e71be3641174/`), 只有这些文件: ``` _plan.md agent 自己的规划笔记 _research.md agent 自己的调研笔记 coder.log agent 自己的执行日志 contract.json 跨节点契约快照 ``` **没有任何 HTML/CSS/JS 文件**——任务原文要求的"apple.com 风格官网首页"从未被写出来过。 `org-coder-test`(`rn_cd3e3a1c51e2`)同样只有 `_plan.md`/`_research.md`,没有测试对象。 ### `org-coder-validator` 的评分(`attempt-1.scores.json`) ```json { "hero_first_impression": 100, "pitch_sections_completeness": 100, "smooth_nav_no_anchor_jump": 100, "responsive_layout": 100, "resource_integrity": 100, "pipeline_auto_recovery": 100 } ``` 六维度全部满分,`overall_pass_threshold=82`,加权后自然通过。 ## 二、这份评分明显没有真的检查过产物 `goal-benchmark.json`(本次任务的验收契约)给每个维度都写了 `evidence_hint`, 其中 5 个维度**明确要求打开真实页面检查**: | 维度 | `evidence_hint` 原话(节选) | |---|---| | `hero_first_impression` | 「打开 `index.html`,桌面宽度截图首屏;量 h1 与 tagline 的计算字号比值」 | | `pitch_sections_completeness` | 「滚动到底数区块数量与顺序;逐个检查 h2+p+visual 三要素是否齐全」 | | `smooth_nav_no_anchor_jump` | 「开发者工具 Elements 检查导航元素;点击时观察地址栏与 Network/Console 有无 hashchange」 | | `responsive_layout` | 「浏览器依次设置视口宽度 375/768/1440px 检查横向滚动条与重叠」 | | `resource_integrity` | 「打开浏览器开发者工具 Console + Network 面板刷新页面检查」 | 这五项全都以"打开浏览器 / 打开 `index.html`"为前提——**当时以为** `index.html` 从没被写出来过,所以断言 validator 不可能真的执行了这些检查步骤。**这个前提错了** (见 §零):`index.html`/`styles.css`/`script.js` 其实都在 `projects/p-v82tpc/` 下真实存在,内容也对得上任务要求。 **订正后的结论**:不能再说这是"没有产物却给了满分"——产物是有的。真正没验证过的 是**更窄的一个问题**:`org-coder-validator` 是否真的照 `evidence_hint` 打开了这个 页面、量了字号比例、切了三档视口、开了 Console/Network 面板检查,还是即使产物 存在,它也只是读了读源码/自己的 `_plan.md` 就直接给了 100 分,没有真的做那些 `evidence_hint` 点名要求的浏览器级验证动作。这个问题现在的证据**不足以下结论**—— 六个维度全 100 分本身既可能是"真查过、页面确实做得不错",也可能是"没查、乐观估计", 两种情况从现有的 `attempt-*.json`/`remediationNote` 文本里区分不出来。 ## 三、影响面(订正后,仍未核实,留给下次) - 这不是 31/33 号文档改动引入的新问题——两次修复只是让流程**不再卡死**, 让这条原本会一直 blocked 的任务真的走到了 `completed`,才有机会去看"最终产出 在哪、验收是怎么做的"这件事。 - 真正独立于本文档、且已经确认修复的一个衍生问题:`graph_files`/`taskFiles` 索引**不覆盖项目根**,这意味着控制台原本设想的"任务级产物汇总"面板如果只读 `graph_files`,会永远看不到真实交付物(这正是 §零 发现问题的路径)。这一半 已经在同一次改动里修了:`graph-engine.readProjectRootRecord` 现在随 `GET /api/graph-runs/:id` 一起吐出来,控制台的「产物」按钮会分别列"最终交付物 · 项目根"和"节点产出索引"两节,见 `web/src/components/graph-console/TaskFilesPanel.vue`。 - 仍然悬而未决的是 validator **有没有真的做过视觉/交互检查**这件事本身——这需要 证据链(比如强制要求 validator 在 `attempt-*.json` 里回填它量出的具体数字: h1:tagline 字号比、三档视口下的滚动条状态等),而不是只回一个分数。 ## 四、留待下次调查的问题(不在本次范围内动手) - [x] `coder-validator` 是否有可用的浏览器工具(截图、DOM 检查)去真的执行 `evidence_hint` 里描述的那些检查?**没有**——见 §五.1,`config.json` 的 `toolPolicy.allowedTools` 只有 `bash`/`read_file`/`str_replace`,物理上做不到 "打开浏览器"。 - [x] `coder-validator` 本体的提示词里,评分前有没有一步强制要求"回填 evidence_hint 点名要量的具体数字"?**有替代方案,但不是这个形态**——见 §五.2, 实际靠的是一份零依赖的静态断言脚本(`unit-tester.check.js`),不是"回填数字", 是"跑一个真脚本、贴真实输出",与 `coder-validator/agent.md` Step 2 的既有要求 ("没跑过的测试等于不存在")同一个纪律,只是换了检查对象。 - [x] 抽查其他任务(`p-bkhylu`/`p-v1mpcl` 这两个已存在的项目根)的 validator 评分记录,看这次"用静态脚本代替浏览器检查"是这条任务的一次性即兴发挥, 还是已经是这类骨架的稳定行为——**是一次性即兴发挥,三条任务三种做法**, 完全不稳定。见 §五.3。 - [ ] 是否需要给"必须打开真实产物检查"的维度加一道**引擎级的前置闸门**:至少确保 被检查的文件(如 `index.html`)在 `evidence_hint` 点名的路径下真实存在 (现在项目根已经可查,这道闸门补起来比 §零 之前容易)。§五.2 的静态脚本已经 部分覆盖了这个诉求(1-5 维),但它是 agent **自己想出来**写的,不是引擎强制的—— 换一次任务、换一个 agent 会话,不保证还会有人主动写这份脚本。 ## 五、2026-08-22 追加调查:`coder-validator` 到底有没有真的检查 ### 5.1 工具权限:**这条判断错了,见 §5.3 订正**——没有"浏览器工具",但 `bash` 能到达真浏览器 `org-coder-validator` 这次跑的本体是 `coder-validator`(预置的 active 本体,非本次 新招聘)。它的 `agent.md`(10KB,读了全文)通篇讲的是**代码/契约正确性验证**—— `npx vitest run`、抓"假绿"五件套(空断言/`.skip`/只测 happy path/mock 掉被测对象/ 覆盖率灌水)、逐条核对 `acceptance_criteria`、`fail_reason` 只在 `impl_bug`/`input_underspecified`/`infra_flake`/`null` 四个取值里选——**整份提示词 没有一个字提到截图、视口、Console/Network 面板、字号比例这类视觉/交互检查**。 它的输出格式(`verdict`/`test_run`/`checks`/`fail_reason`/`remediation_note`)也完全 不是 `attempt-1.scores.json` 那种六维度打分形态(那份分数文件的形态更接近 `goal-benchmark.json` 的 rubric 结构,猜测是 `goal-contract.js run` 那条工具链算出来 落盘的,不是 `coder-validator` 手写)。 而这次任务给 `org-coder` 这条支线新招的两个本体(`coder`、`unit-tester`)的 `config.json` 都是同一句: ```json "cli": { "toolPolicy": { "mode": "restricted", "allowedTools": ["bash", "read_file", "str_replace"] } } ``` **没有专门的"浏览器/截图/DOM 检查"工具**。`goal-benchmark.json` 的 `evidence_hint` 要求"打开 `index.html`"、"开发者工具 Console + Network 面板"、"依次设置视口宽度"—— 乍看在这三个工具的权限范围内一件都做不到。**但这个判断本身是错的**,见 §5.3: `bash` 本身没有限制"能不能启动子进程",仓库自带 `playwright`(`package.json` 里 `"playwright": "^1.58.1"`,`node_modules/playwright` 真实存在),任何持有 `bash` 的 agent 理论上都能写一个 `node verify.mjs`(`require('playwright')` 沿目录树向上 能找到仓库根的 `node_modules`)去跑真实 headless Chromium——**这次任务的 agent 没有这么做,不是因为工具权限拦住了它,是因为它不知道该这么做**(见 §5.3 的 `unit-tester` 提示词空白问题)。 ### 5.2 但也不是纯粹的空手套:真有一份可运行的静态断言脚本 `data/companies/e2e-demo/projects/p-v82tpc/tests/unit-tester.check.js`——零依赖 Node 脚本,读 `index.html`/`styles.css`/`script.js` 三个真实文件做静态解析, 不是猜的,逐条对上 `goal-benchmark.json` 维度 1-5: - **hero_first_impression**:真解析 CSS 里 `.hero-title`/`.hero-tagline` 的 `clamp()` 表达式,换算出**真实的字号比例数字**去比 ≥3:1(不是"看起来大概行"); 另外查 `.hero-visual` 的 `width` 声明是否 ≥90vw。 - **pitch_sections_completeness**:正则抓三个 `
`, 核对**数量、顺序、标题原文**("多智能体协作→全链路自动化→Skill 竞技场") 与每个区块是否同时有 `

`+`

`+`.pitch-visual` 三要素。 - **smooth_nav_no_anchor_jump**:断言全文没有 ``,script.js 里没有 `location.hash =` 赋值、且确实调用了 `scrollIntoView({behavior:'smooth'})`—— 这组断言的判据与"点击导航不出现 # 片段、且平滑滚动"逐句对应,只是用静态代码 特征代替了真的在浏览器里点一下、看地址栏。 - **`responsive_layout`**:只断言 CSS 里存在 `1024px`/`480px` 两个媒体查询断点, **没有验证断点内的样式是否真的消除了横向滚动/重叠**——这条断言比前三条弱, 是"有没有做响应式的动作"而不是"响应式做得对不对"。 - **`resource_integrity`**:断言三个文件里没有外部 URL 引用、有 `` 声明——覆盖的是"会不会因为外链或缺 favicon 产生 404"这一类,**没有校验本地 引用的资源文件是否真实存在**(比如声明了本地图片但文件不存在,这条断言抓不住)。 **结论**:六维度里 5 项确实有真实、可复现的检查支撑,只是形态是"静态断言脚本 + 真跑输出",不是 rubric 字面写的"打开浏览器"——两者在**这次任务的具体验收点**上 基本等价(尤其是前 3 项,静态解析拿到的是比"人肉截图目测"更精确的数字), 但 `responsive_layout`/`resource_integrity` 两项的静态版本明显弱于浏览器版本, 真有边界情况(断点内样式写错、本地资源路径错误)会被这份脚本放过。 **这份脚本是谁写的、写它是不是稳定行为,没有查**:`unit-tester` 这个本体 (写测试的那个角色)的 `agent.md` **是没填充过的 `_base` 原始骨架**(开头带 `` 标记,见招聘装配可靠性那条—— [32 号文档](./32-hire-body-fill-reliability.md)),完全没有任何关于"该怎么测试 这类视觉需求"的角色指导;隔壁 `coder`(实现角色)的 `agent.md` 却正常填充过。 两个本体在同一次任务里、几乎同一分钟(17:54)被雇进来,一个填了一个没填—— 是 [32 号文档](./32-hire-body-fill-reliability.md) 那次异步装配可靠性问题的又一个 真实样本(发生在 17:54,32 号文档的修复提交 `6a18379` 在同一天 18:49 才落地, 所以这次踩到的是修复前的旧行为,不代表新机制仍有这个缺口,但没有再跑一次 验证新机制)。也就是说,这份相当机灵的静态断言脚本,很可能是 `unit-tester` **在没有任何角色指导的情况下、纯靠通用 four-phase 骨架的常识自己想出来的**—— 换一次任务、换一次会话,不保证还会有 agent 主动想到用这种方式弥补工具缺口。 ### 5.3 抽查另外两个已存在的项目根:三条任务三种做法,验证方式完全不稳定 `e2e-demo` 公司目前一共有三个项目根,正好覆盖三种局面: | 项目根 | 任务 | 状态 | 验证方式 | |---|---|---|---| | `p-v82tpc` | `T-mt2r6fz0-125b`(本文档,今天的回归任务) | completed | `tests/unit-tester.check.js`:静态正则解析 HTML/CSS/JS 文本,零浏览器 | | `p-bkhylu` | `T-msyu6u9b-939c`("做一个 lemonai 的官网") | completed | **真实 Playwright + headless Chromium**:六档视口量 `scrollWidth`/`clientWidth`、`getComputedStyle` 量字号、手算 WCAG 对比度、禁 JS/reduce-motion 验证、把项目整体挪到 `/tmp` 用 `file://` 重新打开验证可移植性 | | `p-v1mpcl` | `T-mt1qx0c4-95bf`("apple.com 风格官网",31 号文档卡住的那条原始任务) | **cancelled** | 无——只有 `index.html`/`script.js`/`style.css`,没有 `tests/`、没有 `DELIVERY.md`,任务在验收之前就被取消了,这批文件是留在项目根里的半成品 | **`p-bkhylu` 的证据链明显更扎实**:它的 `DELIVERY.md`(读了全文)逐维度贴了真实 测量数字(六档视口零溢出的表格、四组元素真实对比度数值、`.section__title` 真实 计算字号 48px),`content_fidelity` 维度因为"无法访问 lemonai.ai、内容全是占位" 这个真实限制,**老实评了 80 分而不是 100**(`run_9168bd24f46c` 的 `attempt-0.scores.json` 可查)——这正是"真查过"该有的样子:有一项做不到就如实 反映在分数里,不是全 100。`DELIVERY.md` 末尾还有一句"本轮…未运行或采信项目根内 不存在的 `checks/check.mjs`(本项目未创建该自证脚本),符合 SDD §0/§2 I-4 关于 验收独立性的要求"——**这条"不许自己写脚本自己判"的规则是那次任务的 SDD 自己写的 (`SDD §0/§2 I-4` 搜遍 `system/`/`docs/` 都没有这个条目),不是仓库级别的通用约束**, 换句话说:**要不要认真验证、认不认可自证脚本,取决于那次任务恰好由哪个 sdd-planning 会话规划、恰好写没写这条规矩,不是系统保证的**。 **关键订正**:`p-bkhylu` 那条任务的 `org-coder-impl` 用的是本体 `org-coder` (`system/agents/org-coder/config.json`),工具权限是 `{bash, read_file, str_replace, write_file}`——跟今天新招的 `coder`/`unit-tester` **几乎一样**(多一个 `write_file`),**同样没有专门的"浏览器工具"**。它能跑出真实 Playwright 测试,靠的是 `bash` 里 `node verify.mjs`,`require('playwright')` 沿目录树向上找到仓库根的 `node_modules/playwright`——这条路今天的 `coder`/ `unit-tester` 同样走得通,只是没人这么做。**所以 §5.1 说"没有浏览器工具、物理上 做不到"是错的,纠正为**:两条任务的 agent 拿到的工具权限本质相同,差的是 **有没有人(提示词/前序 agent)教它"该用 Playwright 写一份真实测试"这件事**—— `org-coder`/`coder-validator` 的 `agent.md` 都是正常填充过的成熟本体,`unit-tester` 是空白骨架(见下一段)。这把根因从"平台缺工具"改判为"这次没人教它、也没有指导它 主动想到",是一个不一样、也更能采取行动的结论。 **结论(回答 §四那条 checklist)**:`p-v82tpc` 这次"用静态脚本代替浏览器检查" **不是稳定模式,是这一条任务的即兴发挥**——同一个公司、同类任务,`p-bkhylu` 做到了真实浏览器级验证,`p-v82tpc` 只做到了正则解析文本,`p-v1mpcl` 干脆没做到 验证就被取消。三条任务的"完成"背后,验证严谨程度天差地别,而这个差异在任务列表 / 控制台上完全看不出来——三个都显示"已完成/已取消",不会告诉你其中一个的验收 证据比另一个扎实十倍。这本身就是 §三"影响面"那条判断的实锤:**"任务显示已完成" 与"真的做到了原始需求"之间的落差,在这个系统里目前完全依赖单次任务规划时 agent 会话的即兴发挥,没有系统性保证**。