两个读者
HTML 锚点协议(Claude Code 读取)
所有结构化信息都通过 data-* 属性暴露。Agent 用 cheerio 选择器即可机械抽取,无需 NLP。
| 属性 | 出现位置 | 含义 | 选择器示例 |
|---|---|---|---|
data-doc | 顶级 <article> | 文档类型:prd / sdd | article[data-doc="prd"] |
data-rev | article / section | 修订号,单调递增 | section[data-rev="3"] |
data-unit-id | SDD section | 本 section 描述的 Unit | section[data-unit-id="auth-be"] |
data-type | SDD section | Unit 类型:be / fe / mw / db | [data-type="be"] |
data-depends | SDD section | 本 Unit 依赖的其他 Unit id(空格分隔) | — |
data-contract | <pre> | 契约定义 (openapi / tsinterface) | pre[data-contract="openapi"] |
data-acceptance | <ul> | 验收标准列表 | — |
data-mvcp | 本套文档 SDD section | 所属 MVCP 象限 | [data-mvcp="model"] |
data-origin | PRD section | 本 section 来源(用户 + 时间) | — |
data-conflict | PRD <aside> | 与历史 section 矛盾的标记 | — |
data-changelog | PRD <footer> | 修订日志区 | — |
抽取示例 — units.json 怎么从 SDD 派生
// 给 Claude Code 的 cheerio 代码片段 const $ = cheerio.load(sddHtml); const units = $('section[data-unit-id]').map((_, el) => ({ id: $(el).attr('data-unit-id'), type: $(el).attr('data-type'), depends_on: ($(el).attr('data-depends') || '').split(/\s+/).filter(Boolean), contract: $(el).find('pre[data-contract]').text(), acceptance: $(el).find('ul[data-acceptance] li').map((_,li)=>$(li).text()).get(), })).get(); // → 直接落盘为 units.json 的 .units 字段
MVCP 抽取约定
SDD 四象限页(Model / View / Control / Process)使用统一的 5 字段结构。每个定义都带:
| 字段 | 含义 | 示例 |
|---|---|---|
| name | 唯一标识符 | units.json · DevLoopDashboard · LoopController.runProject |
| path | 预期落盘路径 | server/services/doc-store.js |
| shape | 结构定义(TS / TypeBox / Vue props) | 代码块 |
| contract | 行为契约(前置 / 后置条件) | 列表 |
| tests | 验收用例 | 列表 |
Claude Code 把 SDD 转成 Unit 任务时,每一条 MVCP 定义都可以独立映射到一个 Unit(或多个 Unit 共享)。
文档作为「构建清单」
把整套 PRD + SDD 看作一个机器可解析的 build manifest。复现流程:
具体的 prompt 模板见 plan-reproducibility。
本文档版本
| rev | 日期 | 变更摘要 |
|---|---|---|
| v0.1 | 2026-05-12 | 初版 24 页 · 单 HTML + 拆 24 页 |
| v0.2 | 2026-05-13 | 升级到 41 页:新增 PRD 标准章节、SDD MVCP 五页、原型补全、复现指南 |