benchmark_v1.md 15.3 KB

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 的真实基线(不合格档)。