SDD 质量评分基准 v1 — sdd-planning
生成者:innovator-digest(Phase 2 Digest) 输入:
../hunt/knowhow_v1.md(4个e2e-demo真实案例 + 4条可执行判据 + 8条缺陷模式表)+../hunt/sources.json日期:2026-08-23 首次训练(v1),训练重点:接口契约与数据形态两个维度的深度评分
〇、设计前提
这套 benchmark 不是重复 sdd-planning/agent.md 已有的「五类东西写没写」检查表——那份表
(模块划分/接口契约/数据形态/异常落点/执行顺序)本来就存在,本 agent 已经在用。knowhow §一
明确指出问题不在骨架有没有,而在执行深度:怎样才算把 errors 写全、shape 写实,而
不是滑回"返回结果对象"这种空话。
knowhow 唯一一个"因契约质量本身被打回"的真实案例(案例1,run_9168bd24f46c/rn_6bcda7e1fd6a)
证明了这套深度问题最隐蔽的形式:attempt-0 的契约字面上并不缺东西——六个模块、四个接口、
错误路径都写了——但下游 planner-validator 还是打回来了,因为契约里的关键判据是"自证式"的
(用实现方自己写的检查脚本冒充验收依据)、或是"结论句"的("三种宽度下无横向滚动"而非实测
数值)。这套 benchmark 要专门抓住"看起来完整"和"能被第三方独立复现"之间的差距,这正是
唯一一个真实反面案例揭示的、agent.md 现有检查表覆盖不到的盲区。
一、维度设计(5 维度 + 权重,满分 100)
| 维度 | 名称 | 判据来源 | 权重 |
|---|---|---|---|
| D1 | 接口签名完整性 | knowhow 判据①「签名完整」+ agent.md 表#2 | 20 |
| D2 | 判据可独立复现性(核心锚点) | knowhow 判据②「可独立复现」+ 案例1 attempt-0 四类缺陷 | 30 |
| D3 | 数据形态即业务语言 | knowhow 判据③「数据即业务语言」+ agent.md 表#3 | 20 |
| D4 | 异常路径技术落点覆盖度 | agent.md 表#4 + error_mapping 判据 |
15 |
| D5 | 职责边界纪律(越界诉求显式拒收) | knowhow 判据④ + 案例3/4 | 15 |
D2 单项权重 30,全场最高——理由见五、benchmark 自检:唯一真实反面案例(案例1 attempt-0)
在 D1/D3/D4 上都接近满分,只有 D2 暴露问题;如果 D2 只是普通加权项,这份写虚的契约会被
A 组的高分稀释成一个体面总分,重演 prd-methodology-trial 训练时踩过的同一个坑
(system/agents/prd-methodology-trial/train/digest/benchmark_v1.md 五、"76.4分"教训)。
因此本 benchmark 直接对 D2 引入封顶规则(见三、3.2),不只是调权重。
二、逐维度评分标准
D1 接口签名完整性(权重 20)
判据锚点(knowhow 判据①):入参类型、返回值完整键/类型、happy path 之外的每一种错误/边界 分支,写在同一个接口定义里,不拆到附录,不留"视情况而定"。
| 分数 | 判据 |
|---|---|
| 5 | 每条 interfaces[] 的 signature 给出完整入参类型 + 返回值键/类型/缺省;errors[] 与 signature 在同一对象内,穷举了本接口相关的边界分支(空值/未找到/超时等) |
| 4 | 签名完整,但 1-2 处 errors[] 遗漏了一个低频边界分支,不影响下游主路径开工 |
| 3 | 至少 1 条接口的 errors[] 与 signature 被拆到不同章节(如甩给笼统的"异常处理"一节),下游需要来回对照两处 |
| 2 | ≥2 条接口写"返回结果对象"/"返回处理结果"类空话,没有具体键名/类型 |
| 1 | 完全没有 interfaces[],或只有模块框图没有任何签名 |
判据来源:knowhow §四缺陷模式表「返回结果对象空话」「错误行为拆到附录」两条直接对应
本维度 1-2 分档;案例2(run_c7d233619784)的 scrollToTarget(targetId: string) -> void +
errors: ["目标元素不存在直接 return,不抛错"] 写在同一接口对象内,是 5 分档正面样板。
D2 判据可独立复现性(权重 30,核心锚点)
判据锚点(knowhow 判据②):契约里出现的每一条判定,必须是第三方拿着交付物就能验证的 (数值、文件路径、可枚举的键),而不是实现方自证的结论句或自检脚本。
逐项检查四类缺陷模式(均来自 knowhow §四缺陷模式表,对应案例1 attempt-0 的真实问题):
| 缺陷模式 | 判据 |
|---|---|
| 自证式验收 | 契约里是否存在"用实现方自己写的检查脚本作为验收判据"(如把 checks/check.mjs 的 exit code 当验收结果,而非明确降级为"仅供 coder 自查,不构成验收依据") |
| 结论句代替实测值 | "无横向滚动""对比度达标"这类断言是否给出了可复算的判定方式(数值对/计算公式/具体读取字段),而非停留在结论句 |
| 风格描述无上限 | "简洁""风格统一"这类主观描述是否被转成可数指标(数量上限、色值集合大小等) |
| 占位内容也能通过 | 契约里是否有防止"全部用占位内容/空实现也能过验收"的兜底条款(退化情形显式排除) |
| 分数 | 判据 |
|---|---|
| 5 | 四类缺陷模式在全部关键判据里均不出现;每条验收相关判据都能被下游或第三方脱离 coder 自带脚本独立复现 |
| 4 | 四类缺陷模式命中 1 处,且该处非契约核心判据(如仅某个次要边界样本描述偏结论句) |
| 3 | 命中 2 处,或命中 1 处但涉及核心判据(如主验收路径依赖自证式脚本) |
| 2 | 命中 3 处 |
| 1 | 命中全部 4 处,或整份契约的验收判据系统性建立在"我说做到了"而非可复核证据上 |
判据来源:案例1 attempt-0 的 remediation_note/addressed(../hunt/knowhow_v1.md §二
案例1)逐条对应上表四类缺陷:M-6 checks/check.mjs 被打回前作为验收依据(自证式验收)→
attempt-1 改写为 verifiable_assertions A-1..A-14 + 声明"不得作为任何验收维度的判据";
"三种宽度下无横向滚动"→ requires_browser_measurement MB-2 要求实测 scrollWidth/clientWidth
六档数值对;"字号档位杂乱"→ style_budget.distinct_font_sizes_max<=6;无退化兜底 →
content_fidelity_floor(占位比例上限 + 不可访问时按 inconclusive 上报而非满分)。
D3 数据形态即业务语言(权重 20)
判据锚点(knowhow 判据③):字段名对齐 PRD 术语或显式标注映射,约束(非空/枚举值/上限) 写在字段旁边而不是散落在正文。
| 分数 | 判据 |
|---|---|
| 5 | data_shapes[] 每一项都给出 where(具体存储位置/文件路径)+ shape(字段清单,每字段带类型/非空/枚举等约束),字段命名与 PRD 术语一致或显式标注映射关系 |
| 4 | where/shape 齐全,但 1 处字段命名与 PRD 术语不一致且未标注映射 |
| 3 | shape 只给了字段名没给约束(如只写 {id, title, desc} 不说明是否可空),或部分 data_shapes 缺 where |
| 2 | 多数 data_shapes 只写"存起来"/"保存数据"这类空话,没有字段清单 |
| 1 | 完全没有 data_shapes[] |
判据来源:agent.md 表#3「只写'存起来',没写存哪、什么形状、谁读」直接对应 2 分档;
案例2 {id, title(非空), desc(非空)} 是 5 分档样板——字段清单 + 非空约束同时给出,
即使只有 3 个字段也不省略约束。
D4 异常路径技术落点覆盖度(权重 15)
判据锚点:agent.md 表#4「PRD 写了异常,SDD 里找不到对应落点」。
| 分数 | 判据 |
|---|---|
| 5 | PRD 每条 error_cases/边界场景在 error_mapping[] 里都能指到具体 handled_by 模块 + 具体处理方式(非"做兜底处理"这类空话) |
| 4 | 覆盖全部 error_cases,但 1-2 条 how 描述较笼统 |
| 3 | 有 1 条 PRD 的 error_cases 在 error_mapping[] 里找不到对应条目 |
| 2 | ≥2 条 error_cases 缺落点,或 error_mapping[] 存在但普遍是"报错处理"类空话 |
| 1 | 完全没有 error_mapping[] |
判据来源:案例2 error_mapping[] 五条覆盖了 PRD 的视口边界/换行自适应/连续点击/JS禁用/
极端窄屏,每条 how 都给出具体技术处理方式(如"依赖浏览器原生 scrollIntoView smooth 的
可重入语义,最新一次调用覆盖前一次未完成动画,无需额外节流"),是 5 分档样板。
D5 职责边界纪律(权重 15)
判据锚点(knowhow 判据④ + 案例3/4):遇到不属于"模块/接口/数据形态/异常落点"这五类东西
的诉求(验收标准、日志语义判定等),应在 addressed/remediation_note 里说明分工边界,
而不是硬塞进契约里稀释质量。
| 分数 | 判据 |
|---|---|
| 5 | 越界诉求(如要求 SDD 定验收权重、判定日志/timeline 事件序列)被显式识别并拒收,addressed 或正文里写明"这不是本节点职责,属于 XX 节点";契约内容严格限定在五类东西范围内 |
| 4 | 越界诉求被拒收,但说明较简略(未指出应归属哪个节点) |
| 3 | 越界诉求被部分吸收进契约(如顺手写了一条验收阈值),但未系统性稀释核心判据 |
| 2 | 越界诉求被大量吸收,契约中出现明显不属于五类东西的内容(如验收权重表、UI 视觉打分标准) |
| 1 | 契约主体已经蜕变为验收脚本/测试用例集,五类东西本身反而模糊 |
判据来源:案例3/4(run_b962ea87f58f/run_0e9074815130)多轮 retry 中下游反复要求
SDD 承担"读取 timeline.ndjson 判断自愈収敛"这类验收职责,两次 SDD 均在 addressed/
remediation_note 里明确写"SDD 只负责把 PRD 翻译成模块/接口/数据形态/异常落点,不产出
验收标准,也不读取或判定 timeline.ndjson 事件序列"——是 5 分档正面样板。
三、总分计算方法
3.1 加权和
加权和 = Σ(维度得分/5 × 维度权重) (满分 100)
3.2 封顶规则(D2 天花板机制)
理由见〇:D2 是唯一真实反面案例暴露问题的维度,其余四维在该案例里接近满分。若不封顶, 加权和会把 D2 的低分稀释成一个仍然体面的总分,等于放行"看起来完整、实际不可复现"的契约。
若 D2 ≤ 2 → 总分上限 45
若 D2 = 3 → 总分上限 65
若 D2 ≥ 4 → D2 不封顶
最终得分 = min(加权和, D2 对应上限(如触发))
3.3 判定等级
| 分数区间 | 等级 | 处置建议 |
|---|---|---|
| ≥80 | 优秀 | 可直接进入 org-coder |
| 65-79 | 合格 | 可进入 org-coder,标记薄弱维度供关注 |
| 50-64 | 待改进 | 不建议进入 org-coder,需重写薄弱维度后重新评分 |
| 不合格 | 判定为"写虚了",需要重写核心维度 |
及格线(passing_score)= 65(合格档下限),依据见 industry_avg_score.md。
四、判据来源逐条对照表
| knowhow 判据/缺陷模式 | 落地维度 | 说明 |
|---|---|---|
| 判据①签名完整 | D1 | — |
| 判据②可独立复现 | D2 | 核心锚点,权重最高+封顶 |
| 判据③数据即业务语言 | D3 | — |
| 判据④越界诉求显式拒收 | D5 | — |
| 缺陷模式:自证式验收 | D2 | — |
| 缺陷模式:结论句代替实测值 | D2 | — |
| 缺陷模式:风格描述无上限 | D2 | — |
| 缺陷模式:占位内容也能通过 | D2 | — |
| 缺陷模式:返回结果对象空话 | D1 | — |
| 缺陷模式:只写"存起来" | D3 | — |
| 缺陷模式:错误行为拆到附录 | D1 | — |
| 缺陷模式:越权吸收验收职责 | D5 | — |
| agent.md 表#4 异常落点 | D4 | knowhow 未单独列判据,但 agent.md 现有判据里明确要求,且是五类东西之一,独立成维度避免被 D1/D2/D3 掩盖 |
八条缺陷模式全部有落点,四条判据全部有落点,没有遗漏。
五、benchmark 自检:对案例1 attempt-0 打分
样本:data/companies/e2e-demo/runs/run_9168bd24f46c/nodes/rn_6bcda7e1fd6a/
attempt-0(首轮契约,被 planner-validator 打回,触发 remediation)。
5.1 逐维度打分
D1 接口签名完整性 = 4
I-1~I-4 每条 signature 都给出精确 DOM/JS 契约,errors[] 与签名同对象内嵌
(如 I-3 "自写 scroll 补间会让 PRD E-5/E-6 立刻回归")。扣 1 分:I-4(M-6 自检脚本接口)
本身描述完整,但作为"验收依据"被使用时,其"错误"含义(脚本 fail 是否代表验收失败)
在 attempt-0 阶段未被划清界限——这处模糊后来在 D2 的问题里体现得更严重,此处只算签名
本身,故降 1 档而非更低。
D2 判据可独立复现性 = 1(关键维度) 四类缺陷模式全部命中:
- 自证式验收:
checks/check.mjs在 attempt-0 阶段作为核心验收依据,未声明"不得作为 验收维度判据"(remediation 要求"验收标准不得把判据外包给被验收方自带的 checks/check.mjs", 证明 attempt-0 确实这么做了) - 结论句代替实测值:remediation 要求"静态分析覆盖不到的项不许被当成已验证",说明 attempt-0 里"三种宽度下无横向滚动"等判据是结论句,没有实测数值对
- 风格描述无上限:"字号档位杂乱"这类描述缺少可数指标,remediation 要求补
style_budget(attempt-0 没有) - 占位内容也能通过:
content_fidelity_floor是 attempt-1 才新增的字段, 说明 attempt-0 没有防止"全站占位也能过"的兜底
命中全部 4 处 → 1 分档。
D3 数据形态即业务语言 = 4
data_shapes[] 六项均给出 where + shape(如"视口实测表"给出四列具体表头 + 六档必填
宽度值),字段与 PRD 术语(占位/文案出处/韧性样本)直接对齐。扣 1 分:部分 shape
描述(如"页面文案"一项)偏结构性描述,非空/格式类约束不如案例2的 {id, title(非空)}
这种逐字段标注精确。
D4 异常路径技术落点覆盖度 = 5
error_mapping[] 九条逐一对应 PRD 的 E-1~E-9,每条 how 都是具体技术处理方式
(如 E-6"is-in 只加不删并 unobserve,不重播不回退"),无空话。
D5 职责边界纪律 = 5 本案例本身不涉及越界诉求(越界诉求场景在案例3/4),attempt-0 契约内容严格限定在 五类东西范围内,无验收权重/日志判定等越界内容。
5.2 计算
加权和 = 4/5×20 + 1/5×30 + 4/5×20 + 5/5×15 + 5/5×15
= 16 + 6 + 16 + 15 + 15
= 68
不封顶结果 68 分,落在"合格"档——这正是任务书警告的失败信号:一份被
planner-validator 实际打回、需要重写关键判据的契约,如果只看加权和会被判定为"合格,
标记薄弱维度关注"即可放行,而不是"必须重写"。
触发封顶:D2 = 1(≤2)→ 总分上限 45。
最终得分 = min(68, 45) = 45
45 分落在"不合格"档,与真实历史事实一致——这份契约确实被下游打回,需要重写核心
判据后才产出了 attempt-1(现在的 contract.json)。
5.3 结论
- 自检证明:不封顶的纯加权和会把"被真实打回过的契约"误判为合格放行,与历史事实矛盾。
- 引入 D2 封顶规则后,评分(45,不合格)与历史事实(确实被打回重写)一致。
- 该结果同时用作
industry_avg_score.md的真实基线(不合格档)。