knowhow_v1.md 10.3 KB

Hunt 调研报告 v1 — sdd-planning「接口契约与数据模型」章节强化

  • 目标本体:system/agents/sdd-planning(规划链第三环:PRD → SDD)
  • 训练重点:SDD 五类产出中的第 2 类(接口契约)与第 3 类(数据形态)
  • 调研范围:① 该 agent 当前方法论现状 ② 仓库内真实产出案例正反面 ③ 行业成熟方法论
  • 首次训练,无历史版本可比对

一、现状:sdd-planning 已经规定了什么

读 system/agents/sdd-planning/agent.md,第 2/3 类的判自己不合格信号已经写得很明确:

类别 现有描述 判不合格信号(agent.md 已写)
接口契约 函数/端点签名、入参、返回形态、错误形态 写"返回结果对象",没写有哪些键、类型、缺省
数据形态 表/字段/JSON schema/文件布局 只写"存起来",没写存哪、什么形状、谁读

contract.json 模板已经给了 interfaces[](含 signature + errors[])和 data_shapes[](含 where + shape)两个字段的示例形态,也有 error_mapping[] 把 PRD 的 error_cases 逐条落到技术处理方式。方法论骨架是齐的,问题在于执行深度——即:怎样才算把 errors 写全、shape 写实,而不是又滑回"返回结果对象"这种空话。这正是本次调研要补的部分。

判断标准已经写死:"org-coder 拿着它能直接开工,一行都不用回来问『这个接口返回什么』。做不到就是写虚了。" 这是我们评估案例好坏的唯一判据。


二、仓库内真实案例:e2e-demo 的 4 次 SDD 产出

四个案例都来自同一条 e2e-demo 产品线(一个 Apple 风格 landing page),因此"接口契约"这里体现为 DOM/JS 绑定契约而非服务端 API,但判据完全一致:签名要精确、错误要枚举、数据要有 schema。

案例路径(data/companies/e2e-demo/runs/.../nodes/.../):

  1. run_9168bd24f46c/rn_6bcda7e1fd6a — 3 轮 attempt,因契约质量本身被打回过一次(核心反面/正面对照案例)
  2. run_c7d233619784/rn_4618bc2aa72d — 1 轮 attempt 直接通过(正面案例)
  3. run_b962ea87f58f/rn_ad60c17f5160 — 5 轮 attempt,但均非契约质量问题(引擎误判 + 越权指控被正确拒收)
  4. run_0e9074815130/rn_9e72db5d696e — 4 轮 attempt,同上,均为下游越界诉求被正确拒收

案例 1(唯一因契约质量本身被打回的案例)——最有价值的反面教材

attempt-0 → attempt-1 的 remediation_note/addressed 原文(节选):

"I-4 把 M-6 明确降级为 coder 侧自检工具,并在 SDD 与 contract 两处写死『不得作为任何验收维度的判据』;同时新增 §7 / exports.verifiable_assertions(A-1..A-14),只用交付物文件内容表述判定语义,验收方可完全独立实现一份脚本"

暴露的问题:用实现方自己写的检查脚本 (checks/check.mjs) 冒充验收契约——相当于契约里写"我保证做对了"而不是"这是可独立复核的判据"。修复方式是把契约改写成 14 条可被第三方独立复现的断言(A-1..A-14),且明确声明自检脚本不算数。

"拆出 requires_browser_measurement(MB-1..MB-6),逐条注明 PRD 出处,并要求 DELIVERY.md 用实测数值对(scrollWidth/clientWidth 六档)而非结论句作为证据"

暴露的问题:用结论句代替实测数据——"三种宽度下无横向滚动"这类断言必须换成实际的 scrollWidth/clientWidth 数值对照表(6 个视口宽度各一行),否则下游没法验证契约是否真的被满足。

还新增了 content_fidelity_floor(挡住"全部用占位内容也能通过"的退化情形),以及把模糊的风格描述("字号档位杂乱")改写成可数指标:distinct font-size ≤ 6、--c-* 强调色 token ≤ 3,并挂到断言 A-14 上。

这一案例证明:接口契约写虚的最隐蔽形式不是"完全没写",而是「看起来很完整但无法被第三方独立复现」——结论句代替实测值、自检脚本冒充验收判据、风格描述没有数值上限。

案例 2(一次通过,最简洁完整的正面样板)

interfaces 条目直接给出精确签名 + 同一对象内嵌错误行为,不拆到附录:

scrollToTarget(targetId: string) -> void
errors: "目标元素不存在直接 return,不抛错"

data_shapes 用字段清单 + 约束描述而非"存起来":

3 组 {id, title(非空), desc(非空)}

要点:错误行为写在接口定义的同一个对象里,而不是甩到一个笼统的"异常处理"章节;数据形态给出了字段名 + 非空约束,即便只有 3 个字段也不省略。

案例 3、4(澄清"什么不属于契约质量问题")

两案例的多轮 retry 全部与接口契约/数据形态本身无关——是下游节点(goal-benchmark)的验收阈值配置 bug,或是下游提出让 SDD 承担"读取 timeline.ndjson 判断自愈収敛"这种越界诉求。两次 SDD 都在 addressed 里明确拒绝越权:

"SDD 只负责把 PRD 翻译成模块/接口/数据形态/异常落点,不产出验收标准,也不读取或判定 timeline.ndjson 事件序列"

这是一个重要的反向教训:正确的应对不是"为了让下游满意而把设计文档写成验收脚本",而是在 addressed/remediation_note 里清楚说明这不是本节点的职责边界,把球踢回给该负责的节点。否则契约会被不断稀释成什么都想覆盖、什么都覆盖不深的大杂烩。


三、行业方法论:怎样的接口契约才能不用回来问问题

1. Contract-first / API-first(OpenAPI + JSON Schema 生态,2026 现状)

核心原则:契约在实现代码之前先定稿,作为团队间的显式共享 artifact,驱动文档/测试/代码生成。可直接吸收进 SDD 方法论的几条:

  • 每个接口必须同时给出成功路径和错误路径的形态,不能只写 happy path。OpenAPI 3.1 对齐 JSON Schema 2020-12 后,oneOf/anyOf/if-then-else 可以精确表达"某个字段存在时另一字段的形态不同"这类条件契约——SDD 里遇到"返回值形状随入参变化"的场景,应显式列出每种分支的键/类型,而不是笼统写"视情况返回不同结构"。
  • 命名一致性:字段命名风格(camelCase / snake_case)、集合命名(复数名词)全文档统一,SDD 里的 data_shapes 应该跟仓库现有代码的命名风格对齐,而不是自造一套。
  • 分页/过滤/排序/错误形态要在契约定稿阶段就定死,不能留给实现阶段"看着办"——对应到 SDD 的判据就是:I/O 边界处的所有变体(空列表、超量、非法参数)都要在 interfaces[].errors 里枚举,不能只写主路径。

2. DDD 数据建模:契约的精确性来自"通用语言"(Ubiquitous Language)

DDD 的核心贡献不是建模工具本身,而是"精确术语,含义唯一"这个纪律——同一个词在 PRD、SDD、代码里必须指向同一个东西。落到 SDD 写作上:

  • data_shapes 里的字段名如果和 PRD 里的业务术语对不上(比如 PRD 说"下单人",SDD 写成 userId 而不说明两者关系),下游就会来问"这个 userId 是下单人还是操作人"。字段命名要么直接复用 PRD 术语,要么显式写一行映射关系。
  • DDD 强调"模型是可执行的、精确的中间语言,让产品/工程都能读懂并达成一致"——对应 SDD 的落地要求是:data_shapes 不能只是给工程师看的技术 schema,也要能让不懂代码的人从字段名看出业务含义(这也是为什么案例 2 里 {id, title(非空), desc(非空)} 比一个纯技术 schema 更好——它同时携带了业务约束)。

3. 两条思路收敛到同一个可执行判据

结合仓库案例和行业方法论,"下游不用回来问问题"的契约需要同时满足:

  1. 签名完整:入参类型、返回值的完整键/类型、以及 happy path 之外的每一种错误/边界分支,写在同一个接口定义里(不拆到附录,不留"视情况而定")。
  2. 可独立复现:契约里出现的每一条判定,必须是第三方拿着交付物就能验证的(数值、文件路径、可枚举的键),而不是实现方自证的结论句或自检脚本。
  3. 数据形态即业务语言:字段名对齐 PRD 术语或显式标注映射,约束(非空/枚举值/上限)写在字段旁边而不是散落在正文。
  4. 越界诉求要显式拒收:契约深度不等于契约范围无限扩张,遇到不属于"模块/接口/数据形态/异常落点"这五类东西的诉求(如验收标准、日志语义判定),应在 addressed/remediation_note 里说明分工边界,而不是硬塞进契约里稀释质量。

四、常见缺陷模式汇总(供后续训练素材复用)

缺陷模式 表现 来源
自证式验收 用实现方自己写的检查脚本冒充可独立复现的验收判据 案例1 attempt-0
结论句代替实测值 "三种宽度下无横向滚动"而非实际 scrollWidth/clientWidth 数值表 案例1 attempt-0
风格描述无上限 "字号档位杂乱"缺少可数指标 案例1 attempt-0
占位内容也能通过 缺少 content_fidelity_floor 这类退化情形兜底 案例1 attempt-0
返回结果对象空话 未列出具体键/类型/缺省值(agent.md 已列为判据) agent.md 现状
只写"存起来" 数据形态未给出字段/schema/文件布局(agent.md 已列为判据) agent.md 现状
错误行为拆到附录 错误分支与接口定义分离,下游要来回对照两处 对照案例2的反例(案例2把errors放进同一接口对象,做对了)
越权吸收验收职责 为满足下游诉求把 SDD 写成验收脚本,稀释契约本身 案例3/4 正确应对方式的反面推演

五、下一步(供 Digester/Trainer 阶段参考)

  • 可将「案例1 attempt-0→1 的完整 diff」做成具体训练样例:给定同一份 PRD 片段,对比"写虚的契约"与"改写后的契约"两个版本。
  • 可把「4 类判据」(签名完整/可独立复现/数据即业务语言/越界拒收)转成 SDD 自检 checklist,插入 agent.md 强制思维隔离部分。