| name | ddev-plan |
| description | 在已有规格或多步骤任务需求、且在动代码之前使用。若上游 ddev-pc-test 已产出测试用例,自动走 TDD 流程:先实现测试 demo 代码(红灯),再实现被测代码(绿灯),测试覆盖不到的部分直接开发。 |
编写计划
概述
ddev-plan 的职责是把上游已经确认的设计映射成可执行的实施顺序,避免展开成详细代码草稿。计划里要清楚说明:每个任务对应哪些已确认文档、允许改哪些文件、必须遵守哪些约束、完成后用什么证据证明实现结果与文档一致。
计划文档只正向描述本次实现要做什么、分别在哪一步做、做到什么结果。不要专门写“明确不做什么”或“范围外不做什么”的条目。凡是计划里没有列出的任务、步骤、文件改动和验证动作,默认都不属于这次实现范围。
要假设后续执行者是熟练开发者,但对当前仓库上下文并不熟,所以计划必须告诉他先读哪些 spec / detail / flow / dataflow 文档,以及这些文档在当前任务里分别约束什么。
这个 skill 只消费已经确认过的 spec 文档、结构设计文档和图,不负责重新决定架构,也不负责在计划阶段发明新的数据结构、状态流或接口契约。上游通常先经过 ddev-spec,图形细化则交给 ddev-diagram,结构和数据流细化则交给 ddev-detail。
如果上游已经为嵌入式 C / 纯 C 场景定义了”禁止业务全局变量、限制长链 if/else、优先 context/状态机/表驱动”的 spec 约束,这里必须原样传递到执行计划,不能在任务拆解时弱化成泛泛的”优化代码结构”。对于其他语言项目,同样需要原样传递上游定义的模块边界、接口契约和实现约束。
对于 C 项目(.c / .h),本阶段必须加载 ddev-c-pro 和 ddev-comment-gen skill,将设计规范、命名规范、Doxygen 注释标准、风格偏好作为实现约束写入计划,确保执行者明确知道编码规范要求。对于其他语言项目,如果有对应的编码规范 skill,也应在本阶段加载并写入计划约束。
开始时声明: “我正在使用 ddev-plan skill 来创建实现计划。”
上下文: 这个 skill 应该在专门的 worktree 里运行(由上游设计流程创建)。
计划保存到: docs/plans/YY-MM-DD_name/exec_plans/<feature-name>.md
范围检查
如果规格覆盖了多个彼此独立的子系统,那么在上游设计阶段就应该拆成多个子项目规格。如果没有拆,就应该建议拆成多个计划 - 每个子系统一个。每个计划都应该能独立产出可运行、可测试的软件。
如果 spec 文档、结构设计文档或流程图还没确认,或者还在反复改,就先回上游把设计定住,不要在 ddev-plan 里提前写实现细节。
范围写法也必须保持正向:只列本计划实际覆盖的子系统、文件、任务和验证。没有写进计划的内容,不补充、不顺带、不默认实现。
TDD 优先策略
如果上游 ddev-pc-test 已产出测试用例文档(detail/tests/)和测试 demo 代码大纲,计划必须走 TDD 流程。如果不存在测试用例,跳过本节,按常规流程直接规划实现。
判断步骤
- 检查
docs/plans/YY-MM-DD_<topic>/detail/tests/ 目录是否存在测试用例文档
- 如果存在,读取测试总览文档,确认覆盖了哪些接口/路径/状态
- 将测试用例映射到计划任务中:每个测试用例对应一个 TDD 子任务
TDD 任务编排
TDD 模式下的任务必须按红-绿-重构拆成三个连续子步骤:
- 红灯(Test First):先按
ddev-pc-test 的测试 demo 大纲,把测试脚本/测试代码写完整、跑通红灯(被测代码未实现,测试必然失败)
- 绿灯(Implement):再实现被测代码,跑通绿灯
- 重构(Refactor):最后在测试保护下清理代码结构
覆盖拆分
计划必须把本次改动拆成两块:
- 测试覆盖部分(TDD):测试用例能覆盖的接口/状态/路径,按 TDD 红-绿-重构顺序编排
- 测试未覆盖部分(直接开发):硬件依赖、中断时序、板级外设等测试无法覆盖的部分,按常规实现 → 验证 → 一致性核对编排
计划文档中必须显式标明每个任务属于哪一块,以及为什么某个部分无法走 TDD。
TDD 任务引用
TDD 任务在"必读文档"中必须额外引用:
docs/plans/.../detail/tests/<name>-overview.md:可测试性结论与覆盖范围
docs/plans/.../detail/tests/<name>-cases.md:具体测试用例及输入/预期输出
- 对应的测试 demo 代码路径(如
test/YY-MM-DD-<feature>/)
文档依赖原则
ddev-plan 不定义新的业务状态、接口契约、数据结构语义或流程分支
- 计划中出现的关键设计项,必须能追溯到已确认的 spec / detail / flow / dataflow 文档
- 每个任务都要明确列出执行前必须阅读的文档和章节,避免执行者只看计划不看设计
- 如果某个关键实现约束无法追溯到上游文档,就停止写计划,回到上游补文档,而不是在计划里临时补设计
代码现状验证(强制)
在编写计划的任务和文件结构之前,必须验证计划涉及的文件路径和符号是否存在于实际代码中。计划中的所有文件路径、函数名、结构体名必须能在源码中找到对应,或来自已确认的上游文档。
验证步骤
- 文件路径验证:对计划中要新建/修改的每个文件——
- 若是修改已有文件:用
Glob 或 codegraph_files 确认文件路径存在
- 若是新建文件:确认其父目录存在,不存在则标注需要在哪个任务中创建
- 符号验证:对计划中引用的函数名/结构体名/枚举名——
- 用
codegraph_search 确认在源码中的实际签名
- 如果符号来自上游 ddev-pc-test 的 API 签名清单或 ddev-detail 的代码分析,直接引用,无需重复搜索
- TDD 任务 API 验证:TDD 任务的测试代码引用的 API 签名必须——
- 来自 ddev-pc-test 产出的 API 签名清单,或
- 来自 ddev-detail 的代码现状收集结果
- 禁止在计划中凭空写出测试代码要调用的函数名
不通过时的处理
- 如果文件路径不存在且不是新建文件 → 回上游确认 spec/detail 是否覆盖了正确的代码范围
- 如果符号在源码中找不到 → 确认是拼写错误还是上游设计文档遗漏,修正后再继续
文件结构
在定义任务之前,先把需要创建或修改哪些文件、每个文件负责什么理清楚,并把它们和对应的上游设计文档绑定起来。这一步会把拆分决策固定下来。
- 设计边界清晰、接口明确的单元。每个文件都应该只有一个明确职责。
- 你最擅长处理能一次放进上下文里的代码,而且文件越聚焦,修改越可靠。优先小而专注的文件,不要用一个大文件做太多事。
- 需要一起变动的文件应该放在一起。按职责拆分,不要按技术层拆分。
- 在已有代码库里,要遵循既有模式。如果代码库本来就有大文件,不要擅自重构;但如果你要改的文件已经臃肿了,在计划里包含拆分是合理的。
- 如果存在
ddev-pc-test 产出的测试 demo 代码目录(test/YY-MM-DD-<feature>/),必须把测试脚本/测试代码文件列在对应的 TDD 任务里,并标注其为"红灯"阶段产物。
对于嵌入式 C / 纯 C 计划,还要把这些点写进任务拆分:
- 哪个步骤先定义
context / session / handle 结构体
- 哪个步骤把状态枚举和错误码落地
- 哪个步骤把长链条件改成
switch、状态机或表驱动
- 哪个步骤拆出私有
static 辅助函数,避免主函数吞下全部职责
- 哪个步骤验证没有新增业务全局变量和魔法状态值
对于其他语言项目,任务拆分应包含对应的结构约束(如 Rust 的 ownership 边界、Python 的类型注解策略、Go 的 error handling 约定等),由对应语言的编码规范 skill 决定具体约束项。
这个结构会影响任务拆分。每个任务都应该产出自包含、彼此独立、合理的改动,并能明确回答“本任务落实的是哪份设计文档的哪一部分”。
小步任务粒度
计划要拆到”可稳定执行、可独立验证、可明确对照设计”的粒度,但不需要把任务机械拆成 2-5 分钟的小动作,也不需要把上游文档已经写清楚的实现细节再重复展开成完整代码。
推荐的任务粒度是:
- 一个任务对应一个明确模块、流程段或一致性交付点
- 一个任务内可以包含”阅读文档 -> 实现 -> 验证 -> 一致性核对”这一组完整动作
- 如果两个步骤引用的设计文档、修改文件范围或验证方式明显不同,就拆成两个任务
计划文档头部
每个计划都必须以这个头部开始:
# [功能名] 实现计划
> **给代理型执行者:** 必需子技能:使用 `ddev-exec` 按任务逐步实现这个计划。步骤使用复选框(`- [ ]`)语法跟踪。
**目标:** [一句话描述这个功能做什么]
**架构:** [2-3 句说明方案,并注明设计以哪些已确认文档为准]
**技术栈:** [关键技术/库]
**设计依据:**
- `docs/plans/.../spec/...`
- `docs/plans/.../detail/...`
- `docs/plans/.../flow/...`
- `docs/plans/.../dataflow/...`(如有)
- `docs/plans/.../detail/tests/...`(如有,`ddev-pc-test` 产出)
- `ddev-c-pro` skill:编码规范、命名规范(C 项目必填,其他语言项目可选——如有对应 skill 则引用)
- `ddev-comment-gen` skill:Doxygen 注释标准(C 项目必填,其他语言项目可选——如有对应 skill 则引用)
**TDD 状态:** [存在测试用例 / 无测试用例]
- 若存在,标注测试覆盖范围:[接口/状态/路径];未覆盖范围:[硬件依赖/中断时序/...]
- 若不存在,简述原因:[不可 PC 测试 / 未触发 ddev-pc-test / 跳过]
---
任务结构
### 任务 N: [组件名]
**依赖:** [Task X, Task Y / 无]
**目标:**
- [本任务要落地的模块、流程或交付点]
**必读文档:**
- `docs/plans/.../spec/...`:章节 / 图 / 接口定义
- `docs/plans/.../detail/...`:结构体 / 状态 / 错误码 / 数据约束
- `docs/plans/.../flow/...`:流程节点 / 分支 / 状态迁移
- `docs/plans/.../dataflow/...`:数据流约束(如有)
**文件:**
- 新建:`exact/path/to/file.py`
- 修改:`exact/path/to/existing.py:123-145`
- 测试:`tests/exact/path/to/test.py`
**实现约束:**
- 保持 [context / 状态机 / 表驱动 / 接口契约] 方案
- 不得新增 [业务全局变量 / 长链 `if/else` / 范围外接口]
- 实现命名、错误码、状态值必须与引用文档一致
- C 项目须遵守 `ddev-c-pro` skill:`_t` 类型后缀、模块前缀、显式返回码、所有权明确(其他语言项目由对应编码规范 skill 约束)
- C 项目须遵守 `ddev-comment-gen` skill:Doxygen 注释完整性(公开 API/@file/结构体成员)(其他语言项目由对应注释规范 skill 约束)
- [ ] **步骤 1:阅读并核对引用文档**
确认本任务覆盖的输入、输出、状态、接口、流程和边界条件都能在上游文档中找到依据。
- [ ] **步骤 2:按既定设计修改目标文件**
实现时只允许在本任务列出的文件范围内落地设计,不得在计划外扩展新设计。
- [ ] **步骤 3:补齐本任务需要的验证**
运行:`pytest tests/path/test.py::test_name -v`
预期:通过,且结果与引用文档描述一致
- [ ] **步骤 4:做一致性核对**
逐项核对代码实现是否与引用文档里的结构、状态迁移、接口语义和流程节点一致;若不一致,先修正代码或回上游补文档。
- [ ] **步骤 5:写入实现笔记**
在 `implementation-notes.md` 中追加本任务的推理记录,按 Design Decisions / Deviations / Tradeoffs / Open Questions 四个维度记录。Design Decisions 和 Deviations 为强制维度——必须检查并记入;Tradeoffs 和 Open Questions 有则必写,无则标注"无"。
- [ ] **步骤 6:记录结果与未覆盖风险**
记录本任务已经覆盖的设计点、验证证据,以及仍需后续任务或最终门禁覆盖的风险。
**验证:**
- 运行:`exact verification command`
- 预期:`expected result`
- 人工核对:`与哪份文档的哪几个点保持一致`
**完成标准:**
- 引用文档中的设计点已经落地到代码
- 没有引入文档中不存在的新设计漂移
- 验证通过,且一致性核对完成
对于 C 项目,如果任务涉及控制流或状态管理,步骤里不能只写”实现逻辑”,要明确写出:
- 先补或定义状态枚举 / 上下文结构体
- 再根据已确认文档落地状态迁移和错误路径验证
- 再落地分发方式,不允许默认写成长链
if/else
- 按
ddev-c-pro skill 要求遵循命名规范和风格偏好
- 按
ddev-comment-gen skill 要求补 Doxygen 注释
- 最后检查是否出现共享可变全局状态、参数过多未封装、注释缺失等违规
对于其他语言项目,同样需要将对应语言的实现约束明确写在步骤中,不允许含糊的”实现逻辑”占位。
TDD 任务结构
当上游 ddev-pc-test 已产出测试用例时,对应任务改用以下 TDD 模板。一个 TDD 任务对应一个或一组紧密相关的测试用例。
### 任务 N: [组件名](TDD)
**类型:** TDD(测试覆盖)
**对应测试用例:** TC-01, TC-02(来自 `detail/tests/<name>-cases.md`)
**目标:**
- [本任务要落地的模块、流程或交付点]
**必读文档:**
- `docs/plans/.../spec/...`:章节 / 图 / 接口定义
- `docs/plans/.../detail/...`:结构体 / 状态 / 错误码 / 数据约束
- `docs/plans/.../detail/tests/<name>-overview.md`:可测试性结论与覆盖范围
- `docs/plans/.../detail/tests/<name>-cases.md`:测试用例 TC-0x 的输入/预期输出
**文件:**
- 测试代码:`test/YY-MM-DD-<feature>/host_sim/test_xxx.py`(红灯阶段产物)
- 被测代码:`src/path/to/module.c`(绿灯阶段产物)
**实现约束:**
- 保持 [context / 状态机 / 表驱动 / 接口契约] 方案
- 不得新增 [业务全局变量 / 长链 `if/else` / 范围外接口]
- 测试脚本的输入/预期输出来自 cases 文档,不得自行发明
- C 项目须遵守 `ddev-c-pro` skill(其他语言项目由对应编码规范 skill 约束)
- [ ] **步骤 1:阅读测试用例文档**
确认本任务覆盖的测试用例编号、输入数据、预期输出、前置条件都能在 cases 文档中找到。
- [ ] **步骤 2:红灯 — 先写测试代码**
按 cases 文档中的输入/预期输出,把测试脚本/测试 demo 代码写完整。**写入前必须先读取被测模块的头文件**,确认测试代码中调用的函数签名、结构体、枚举值与源码一致。运行测试,确认红灯(被测代码未实现,测试必然失败)。记录红灯输出。
- [ ] **步骤 3:绿灯 — 实现被测代码**
按 spec/detail 设计文档实现被测代码,用最小代码量让测试通过。运行测试,确认绿灯。
- [ ] **步骤 4:重构 — 测试保护下清理**
在绿灯保护下,清理重复代码、改善命名、拆分过长函数。每改一处就跑一次测试,保持绿灯。
- [ ] **步骤 5:做一致性核对**
逐项核对代码实现是否与引用文档里的结构、状态迁移、接口语义和流程节点一致;若不一致,先修正代码或回上游补文档。
- [ ] **步骤 6:写入实现笔记**
在 `implementation-notes.md` 中追加本任务的推理记录,按 Design Decisions / Deviations / Tradeoffs / Open Questions 四个维度记录。Design Decisions 和 Deviations 为强制维度——必须检查并记入;Tradeoffs 和 Open Questions 有则必写,无则标注"无"。
- [ ] **步骤 7:记录结果与未覆盖风险**
记录本任务覆盖的测试用例、红灯/绿灯输出摘要,以及本 TDD 任务无法覆盖的边界条件。
**验证:**
- 红灯验证:运行:`python test/.../test_xxx.py`,预期:FAIL(被测代码未实现)
- 绿灯验证:运行:`python test/.../test_xxx.py`,预期:PASS
- 人工核对:`与 cases 文档 TC-0x 的预期输出逐字段比对`
**完成标准:**
- 测试用例全部绿灯通过
- 被测代码实现与引用文档一致
- 没有引入文档中不存在的新设计漂移
- 测试输出可自动比对,无需人眼判断
不要留占位符
每一步都必须包含工程师真正需要的内容。以下都属于计划失败,绝对不要写:
- “TBD”“TODO”“后面再实现”“补充细节”
- “添加适当的错误处理” / “添加校验” / “处理边界情况”
- “参考前面的文档自行实现”(但没有写明具体文档和章节)
- “和任务 N 类似”(工程师可能不是按顺序读任务)
- 只说做什么、不说明要读哪些文档、改哪些文件、怎么验证一致性
- 引用了某个类型、状态、函数或方法,但这些东西无法追溯到已确认设计文档
记住
- 始终写清楚准确的文件路径
- 始终写清楚本任务依赖的文档路径、章节或图
- 命令要精确,预期输出也要精确
- 一致性校对点要精确,不能只写“和设计一致”这种空话
- DRY、YAGNI、频繁提交
自检
把完整计划写完后,要换个角度重新看一遍,对照规格和上游文档检查计划。这是你自己运行的清单,不是派发给子代理的任务。
1. 规格覆盖: 快速浏览规格的每个章节/要求。能不能指出一个对应的任务?把缺口列出来。
2. 文档映射: spec / detail / flow / dataflow 文档里的关键交付项、结构、状态和流程节点,能不能在计划里找到对应任务和验证动作?缺口列出来。
3. 占位符扫描: 在计划里找红旗 - 是否有上面“不要留占位符”里列出的模式?有就修掉。
4. 类型与约束一致性: 后续任务里使用的类型、方法签名、属性名、状态名、错误码,是否和上游文档里的命名一致?比如 detail 文档里叫 clearLayers(),计划里又变成 clearFullLayers(),这就是 bug。同时检查这些名称是否能在实际源码中找到对应的声明或定义。
5. 设计漂移检查: 计划里是否引入了上游文档没定义的新结构、新接口、新流程分支或范围外文件改动?如果有,删掉或回上游补设计,不要在计划里偷改架构。
6. 联动覆盖检查: 如果上游 spec/detail 文档中包含联动修改清单,计划是否已为每个联动点分配任务或明确说明为何不需要改?如果上游文档中没有联动修改清单,停止编写计划,回到 ddev-spec 阶段补充后再继续。计划中的任务是否覆盖了联动修改清单中的所有项目?
7. 代码路径存在性: 计划中列出的所有文件路径(新建/修改)是否真实存在于仓库中?新建文件的父目录是否存在?
8. 实现笔记步骤: 计划中每个任务是否都包含了"写入实现笔记"步骤?步骤描述是否指明了按 Design Decisions / Deviations / Tradeoffs / Open Questions 四个维度记录?
9. 语言结构纪律: 如果是 C 项目,计划里是否已经明确安排:
- 业务状态收敛到上下文结构体
- 状态值枚举化
- 长链
if/else 的替代方案
- 函数按职责拆分
- 对”未新增业务全局变量”的验证
- 对”实现是否仍与上游控制流文档一致”的核对
- 按
ddev-c-pro skill 要求遵循命名规范和风格偏好
- 按
ddev-comment-gen skill 要求补 Doxygen 注释
如果是其他语言项目,计划里是否已经明确安排该语言对应的结构约束(由对应编码规范 skill 决定)?
10. TDD 覆盖核对: 如果存在 ddev-pc-test 产出的测试用例:
- 每个测试用例是否都有对应的 TDD 任务?
- TDD 任务是否按红-绿-重构三步骤编排?
- 测试未覆盖的部分是否已显式标注为”直接开发”,并说明了不可测试的原因?
- TDD 任务的”必读文档”是否引用了 cases 文档和 overview 文档?
- 测试脚本的输入/预期输出是否来自 cases 文档,而非自行发明?
- 测试代码中调用的 API 签名是否能追溯到 ddev-pc-test 的签名清单或 ddev-detail 的代码分析?
如果发现问题,直接在原地修掉,不用重新审一遍,改完就继续。若发现某个规格要求没有对应任务,就补上任务。
执行交接
保存计划后,直接进入 ddev-exec。
执行要求:
- 使用
ddev-exec
- 按计划顺序逐步执行
- 在阶段性里程碑后做审查
默认收尾
当计划对应的实现完成后,不要只停在“代码写完”或“测试跑过”。
默认收尾顺序是:
- 用
verification-before-completion 补齐本轮结论所需的验证证据。
- 如需独立质量复核,用
ddev-code-review 做额外审查。
- 最后进入
ddev-gate,按 spec 文档、detail 文档、代码实现、验证证据做最终一致性验收;之后根据项目语言执行对应的编码规范审查(C 项目经 ddev-c-pro)和注释审查。
如果没有经过 ddev-gate,默认不应宣称“实现已经按设计完成”。