SDD 能力底座
为什么不要复制粘贴
一条事实只在一个文档里写 —— SSoT 实操指南
写文档时最容易踩的坑:"这条业务规则 PRD 写过了,我在测试用例里再复述一遍方便看"。然后 PRD 改了,测试用例忘了改,对不齐就翻车。
Aiko IDE 用 SSoT(单一事实源) 准则解决这个问题:每条事实只能在一个文档里定义,其他文档只通过 ID 引用。
四条铁律
- 一处定义:一条事实只有一个主笔文档
- ID 引用:其他文档引用主笔的稳定 ID(
REQ-FN-007/ACC-012/ADR-003) - 延伸不重复:下游可以加新事实,不能复述上游
- 职责单一:每个文档只回答一个问题
这套约束被 ssot Validator 守门,违规直接 ERROR。
怎么知道事实归谁?事实归属表
PD 层 10 件
| 这条事实 | 归哪个文档写 | 用什么 ID 引用 |
|---|---|---|
| 问题陈述 / 目标 / 用户 / 范围 / 里程碑 | vision.md | VISION-* / GOAL-* / PERSONA-* / SCOPE-* / MILE-* |
| 用户场景 + 故事 | stories.md | SCEN-* / STORY-* |
| 系统功能能力 | requirements.md | REQ-FN-* / REQ-ALG-* / REQ-SEC-* / REQ-DOC-* |
| 非功能数字目标 | nfr.md | REQ-NFR-* |
| 验收门禁 | acceptance.md | ACC-* |
| 产品设计约束 | product-design.md | DESIGN-* / IA-* / INTERACT-* / INTEG-* / CONSTR-* |
| 风险 / 假设 / 依赖 | risks.md | ASSUM-* / DEP-* / RISK-* |
| 灰度 / 监控 / 告警 / 回滚 | rollout.md | ROLL-* / METRIC-* / ALERT-* / SOP-* |
| 术语定义 | glossary.md | GLOSS-* |
| AI 能力规约 | ai-spec.md | AI-FRAME-* / MODEL-* / DATA-* / EVAL-* / GUARD-* |
架构层 3 件
| 这条事实 | 归哪个文档 | ID |
|---|---|---|
| 系统架构边界 | architecture.md | ARCH-* |
| 关键技术决策 | adr.md | ADR-* |
| NFR 实现策略 | quality-attributes.md | QA-* |
开发层 4 件
| 这条事实 | 归哪个文档 | ID |
|---|---|---|
| 工程 change 说明 | proposal.md | change id |
| capability 行为契约 | specs/**/*.md | OpenSpec Requirement / Scenario |
| capability 内部实现 | design.md | 章节标题 + 上游 trace |
| 实施步骤 | tasks.md | checkbox / task id |
测试层 2 件
| 这条事实 | 归哪个文档 | ID |
|---|---|---|
| 测试用例 | test-cases.md | TC-* |
| 测试证据 | test-evidence.md | EV-* |
常见违规:你可能想这么写但不该这么写
❌ 在 vision.md 里写"登录页应有忘记密码按钮"
vision.md 是"为什么做",功能能力归 requirements.md。
对的写法:在 requirements.md 写 REQ-FN-005 登录页提供忘记密码入口,vision 里需要时只引 REQ-FN-005。
❌ 在 requirements.md 里写"TPS ≥ 1000"
具体数字是 NFR 目标值,归 nfr.md。
对的写法:requirements.md 只写"系统应支持高并发查询",nfr.md 写 REQ-NFR-PERF-003 p99 latency ≤ 100ms @ TPS=1000。
❌ 在 acceptance.md 里写"测试步骤:1. 打开浏览器..."
acceptance 写"怎样算达标"(Given/When/Then),具体执行步骤归 test-cases.md。
对的写法:
# acceptance.md
- id: ACC-012
given: 用户已登录
when: 提交订单
then: 订单创建成功 + 库存扣减# test-cases.md
- id: TC-007
satisfies: [ACC-012]
steps:
- 1. 打开浏览器,登录...
- 2. 添加商品到购物车...❌ 在 adr.md 里写"新增 order_status 字段"
adr 写"为什么选某个方案",普通工程任务归 tasks.md。
对的写法:
- adr.md:
ADR-005 订单状态选择枚举而非状态机表(理由 + 取舍) - tasks.md:
[ ] T-021 给 orders 表加 order_status 字段
❌ 在 test-cases.md 里重述"应能成功登录"
test-cases 写"怎么测",验收标准归 acceptance.md。
对的写法:
- id: TC-007
satisfies: [ACC-012] # 引用 acceptance.md 的 ACC-012
steps: [...]这样做有什么好处
- 改一处,下游自动跟改:改
REQ-FN-007,所有引用它的 spec / test / design 都被 trace Validator 标记 - AI 上下文清晰:让 AI 写 design 时只读 specs + adr,不被 PD 长篇业务背景污染
- 影响分析机器化:改一个 ID,trace graph 立刻列出受影响的下游,不用人工 grep
- 永远只有一份事实源:避免 5 个对不齐的副本,team 撕逼说"我看的是哪份"
实操技巧
想引用一条已存在的事实
直接写 ID 字符串:
- id: ACC-012
satisfies: [REQ-FN-007] # 引用 requirements.md
references_adr: [ADR-005] # 引用 adr.mdtrace Validator 自动检查这些 ID 真的存在。
想看 trace graph
./scripts/build-trace-graph.sh
# 自动生成 docs/trace-graph.md (mermaid)打开看引用关系图。
Workbench 内 hover ID 看上游
在 PD / dev sidebar 编辑器里,鼠标悬停一个 ID 显示主笔文档的对应段落(不用切文件)。
写完文档自检 3 个问题
- 这页文档"只回答一个问题"吗?回答不了就拆分
- 重复的内容能改成引用 ID 吗?能就改
- 主笔文档里的事实下游能正确引用吗?跑一遍
aiko-validate.sh看