实现规格工作流
作用
在进行代码修改(新增、重构、修复)前,先出 spec 图,用图讲清改动边界、模块关系、接入点和主流程,再进入编码。本 skill 仅用于代码改动场景,项目的整体架构文档初始化请使用 ddev-arch。
边界声明:本 skill 仅产出设计文档,不得直接修改代码。所有代码修改必须在本 skill 产出 spec 文档并获得确认后,通过 ddev-plan 拆解执行计划,再由执行计划驱动编码实现。
如果仓库已存在 docs/architecture/,本 skill 必须先读取项目级架构规范,并让本次 spec 显式遵守其中的模块职责、允许依赖、状态所有权和允许修改范围。
触发条件与落盘开关(默认关闭)
本 skill 的文档产出默认关闭:用户没有明确开口要文档时,不生成、不落盘、不入库任何过程文档(spec、报告、核对表、implementation-notes 都不写),分析结论、边界图与验收口径直接在对话里给出。
- 唯一开关是用户显式要求:只有用户明确说"出个 spec""写份设计文档""落盘到 docs/plans"这类指令时,才产出 spec 文档并按下文规则落盘;不得以"流程要求""惯例如此""方便留痕"为由自行开启。
- 删除即信号:用户删掉同类文档、或指出文档多余之后,视为明确关闭信号——不要再生成一份替代品,继续在对话中给结论即可。
- 纯结构整理免写:注释整理、
static收敛、成员搬家、删死代码这类行为等价改动不需要任何 spec 文档;改完直接给行为等价证据——diff 逐处复核 + 编译告警前后比对 + 链接/引用反证(nm、map、符号引用搜索)。 - 落盘前自查:先确认"用户这次明确要文档了吗"与"这次是否属于纯结构整理";任一答案为否就不落盘,也不把文档和代码改动混在同一次提交里。
- 本节优先级高于本文其他章节的默认表述:"默认先出 spec 图""默认落盘到
docs/plans/..."仅在开关打开时适用。
文档表达原则
spec 文档默认采用”图优先,文辅佐”表达。只保留两类内容:
- 图: 这次改动要做什么
- 文: 每张图补充少量约束和验收口径
能画图说明的内容,不要改写成长段文字。文字只补图里不适合承载的约束、判定条件和验收口径。
不要专门写“明确不做什么”“范围外什么不做”这类反向清单。文档里没有写到的事项,默认就是这次改动不做,不需要额外声明。
如果某件事容易和本次改动混淆,不要写“这个不做”;直接补一张边界图、入口图或对比图,正向说明这次实际落地范围。
spec 文档拆分规则
在确实要写 spec 文档时,一次改动只写一份,覆盖这次要做的全部内容。
只有同时满足以下条件时,才拆成两份独立 spec:
- 两个需求属于完全不同的子系统或职责面,不共享接口、数据结构、状态和流程;
- 可以各自独立设计、独立实现、独立验证、独立回滚;
- 合并在一份文档里会变成两个互不相干的主题,图也无法共用。
以下情况一律保持一份 spec,不拆:
- 同一改动的多个模块、多个入口、多条流程;
- 同一功能的不同层次(边界图、接入点图、流程图、结构说明);
- 通过章节或图就能在一份文档里讲清的内容。
拆分时按“改动面”拆,不按图表类型、章节数量或文档长度拆;拆出的每份 spec 都必须能独立驱动一份实现计划。
图怎么画、怎么命名、怎么渲染、怎么同步维护:
⚠️ 硬门禁:画图前必须先加载 ddev-diagram
在任何 ASCII 图动笔之前,必须执行 Skill("ddev-diagram") 加载绘制规范。加载完成前禁止写任何 ASCII 图。
spec 文档只在用户明确要求落盘时才写到 docs/plans/YY-MM-DD_name/spec/<feature-name>.md;用户未要求时(含纯结构整理改动)不生成、不落盘,结论直接在对话中给出。
默认优先用于嵌入式 C / 纯 C / Rust / HTML / Python 的改动,尤其是 BSP、驱动、协议、板级初始化和静态页面这类需要看边界的工作。
对于 C 项目(.c / .h),本阶段必须加载 ddev-c-pro 和 ddev-comment-gen skill,将其中的设计规范、命名规范、注释规范作为 spec 约束一并写入文档,不得留到编码阶段临场决定。对于其他语言项目,如果有对应的编码规范 skill,也应在本阶段加载并写入 spec 约束。
对于嵌入式 C / 纯 C 改动,这一步不只是”把模块关系画出来”,还要提前约束 AI 和实现者的结构选择,避免后续编码阶段直接滑向全局变量、长链 if/else 和职责混杂的大函数。对于其他语言,同样需要提前约束模块边界和职责划分。
联动顺序
- 如果仓库存在
docs/architecture/,先阅读01_架构总览.md和相关模块文档,确认本次改动是否在项目级架构规范允许范围内。 - 先做代码现状分析(强制),了解现有模块结构、公开接口和文件布局。
- 再做现有框架对齐分析(强制),确定设计如何嵌入现有框架——复用哪些扩展点、沿用哪些模式、新增哪些机制及理由。
- 先出本次 spec 图,并标出遵守了哪些项目级约束和框架对齐结果。
- 再交给
ddev-diagram,按规范手写 ASCII 图到.md。 - 图确认后,可选进入
ddev-pc-test,判断本次修改是否可在 PC 上写测试 demo 直接验证;如果可以则产出测试用例文档和 demo 代码。若不需 PC 测试或不可测试,直接跳过本步骤。 - 若无需 PC 测试或跳过步骤 6,进入
ddev-detail继续细化结构体和数据流;若步骤 6 已产出测试,仍可按需进入 detail 补充实现细节。 - 再进入
ddev-plan,把已确认设计拆成执行计划。 - 实现完成并拿到验证证据后,默认进入
ddev-gate,按图对照代码实现是否一致。若步骤 6 产出了测试 demo,ddev-gate阶段必须跑通该 demo。 - 在 spec 设计过程中出现方向性修改、方案取舍时,将决策记录到 spec 文档本身或
implementation-notes.md中;spec 最终定版时,写入设计依据摘要。
⚠️ 阶段交接硬门禁
本 skill 完成后,禁止 agent 自动进入下游阶段(ddev-detail / ddev-plan / ddev-exec / ddev-gate)。
- 完成 spec 文档后,向用户报告产出路径和关键结论。
- 提示用户可选的下一步(如"进入 ddev-detail 细化结构体"、"进入 ddev-pc-test 评估可测试性"),但必须等待用户明确确认后再加载对应 skill。
- 用户未明确说"进入下一步""继续""开始 detail/plan/exec/gate"等指令前,停留在当前阶段,不自行推进。
- 跨工作项串行门禁:当前工作项的改动未提交、未获得用户确认前,禁止开始下一项改造——不做方案分析、不做分期(P0~P3)、不做范围选型。先用
git commit收掉当前改动,确认工作区干净后,再启动下一项,避免两类变更混在同一工作区,把提交边界和回滚粒度搞乱。
基本流程
- 先判断这次改动属于哪一类:
- 现有代码修改
- 从零搭建新系统
- 新增独立功能模块
- 代码现状分析(强制):在画图之前,先从实际源码中了解现有模块结构、公开接口和文件布局。不完成此步骤不得开始画图。 详见下方”代码现状分析”章节。
- 现有框架对齐分析(强制):在了解代码现状后,分析本次设计应该如何嵌入现有框架——优先复用现有扩展点和模式,新建必须有充分理由。不完成此步骤不得开始画图。 详见下方”现有框架对齐分析”章节。
- 如果存在
docs/architecture/,先做项目级架构越界检查:- 本次改动属于哪些模块
- 是否落在模块文档的”允许修改范围”内
- 是否新增或改变跨模块依赖
- 是否改变公共接口、外部行为或状态所有权
- 是否触发项目级”架构变更门禁”
- 先出图,后补文。
- 按
ddev-diagram绘制规范手写所有 ASCII 图。 - 检查是否做到”看图即可理解主信息”。
- 在每张 ASCII 图上方标注图的用途和来源。
- 如果看不清,优先重画,不优先补长文。
代码现状分析(强制)
在画任何图之前,必须先从源码中理解”代码现在长什么样”。spec 图里画的模块边界、接口方向和文件路径必须与代码实际结构一致。
搜索范围
- 本次改动涉及的模块或目录的文件结构
- 相关模块的公开头文件(
*.h)和关键源文件 - 已有的公开接口、结构体和类型定义
- 模块之间的实际依赖关系和 include 链
搜索方法(优先级递减)
Glob查看涉及的目录和文件结构- code-review-graph(
mcp__crg__query_graph_tool查callers_of/callees_of/references_to/imports_of)摸清符号依赖与调用关系;无图先code-review-graph build grep兜底:搜索关键符号和 include 关系Read打开关键头文件确认接口
产出(嵌入 spec 图/文)
不要求单独文档,但 spec 文档中必须包含:
- 图中标注的模块名必须能对应到实际源码路径
- 图中标注的接口必须能在实际头文件中找到
- 如果 spec 计划修改模块边界或接口,必须在图中显式标注”现状 → 目标”的差异
强制约束
- 如果代码的实际模块边界与 spec 预期不符,必须在 spec 文档中显式标注,并说明是沿用现状还是计划调整
- 不得凭空画出不存在的模块或接口,除非明确标注为”新增”
- 如果项目过大无法完整分析,至少分析本次改动直接涉及的目录和文件
- 设计修改插入点前,必须
Read目标函数的完整代码(不是 grep 片段),确认完整 if-else 分支结构和已有错误/异常处理块后,再定插入位置
现有框架对齐分析(强制)
在代码现状分析完成后、开始画图之前,必须回答一个核心问题:本次设计是在现有框架里扩展,还是在现有框架之外另起炉灶?
原则:默认扩展,例外新建。优先在现有模块、现有接口、现有模式上扩展;新建模块/接口/模式必须有充分理由。
分析步骤
识别现有扩展点:当前涉及的模块已提供了哪些扩展机制?
- 回调注册 / 钩子函数
- 命令表 / 消息分发表追加
- 枚举新增值
- 配置项追加
- 子类继承 / 接口实现
- 构建目标追加(
CMakeLists.txt、Makefile中的源文件列表)
识别现有模式:同类功能在代码库中是怎么组织的?
- API 命名惯例(前缀、后缀、动词-名词结构)
- 错误处理模式(返回码类型、错误传播路径、集中/分层处理)
- 状态管理模式(上下文结构体、状态机、全局/局部状态归属)
- 内存管理惯例(谁分配谁释放、内存池/堆、引用计数)
- 文件组织方式(一对
.c/.h、模块目录结构、测试文件位置)
识别参考实现:找到仓库中与本次改动最相似的已有功能作为设计模板,标注其文件路径和关键符号。找不到时显式声明"本仓库无类似实现可参考"。
功能等价搜索:对本次设计中每个核心功能点(按功能语义,不是按模式),在代码库中搜索已有实现——
- 同名/近名函数(用核心动词 grep 搜索函数名)
- 同类型/同数据结构操作函数(搜索操作同一数据结构的已有函数)
- 同语义的状态存储(搜索已有 context/全局变量是否已管理相关状态)
- 同功能的工具/辅助函数(搜索可能被复用而非重写的通用逻辑)
搜索结果写入 功能复用决策清单:
功能点 候选已有实现 决策 理由 打印机状态管理 prt_ctx_t.statusinprt_core.h:45扩展已有 新增枚举值即可,不需新字段 命令解析 无 新建 仓库中无类似命令格式解析器 决策分三档:复用(直接调用已有)/ 扩展已有(修改已有接口或结构体)/ 新建(确认无等价实现)。新建必须给出"为什么不能复用/扩展"的理由。
逐项对齐检查:对本次设计的每个关键决策,核对——
- 新增模块/文件是否可用现有目录扩展代替?
- 新增接口是否符合现有 API 命名和签名惯例?
- 新增数据结构是否复用了现有类型定义?
- 错误处理、状态管理、内存管理是否沿用了现有模式?
产出(嵌入 spec 文档)
- 复用清单:本次设计复用了哪些现有框架机制(扩展点、模式、类型、接口)
- 新建清单:本次设计新增了哪些框架机制,以及为什么不能复用现有机制(每条必须给出理由)
- 参考模板:参考了哪个已有实现作为模式模板,或声明"本仓库无类似实现可参考"及设计模式来源(外部标准/团队约定/从零设计)
强制约束
- 任何"全新模块/全新接口/全新模式"必须在 spec 中标注,并给出不能复用的理由
- 找不到参考实现时,必须显式声明并说明设计模式来源,不得沉默跳过
- 未完成框架对齐分析,不得开始画图
- 如果分析过程中发现现有框架无法支撑本次需求(如扩展点不足、模式不适用),必须在 spec 中显式标注为"框架缺口",并评估是否需要先做框架级重构
联动影响分析(强制)
在画图之前,必须搜索并识别本次改动需要联动修改的所有位置。不完成此步骤不得开始画图。
触发条件
当改动属于以下类别之一时,必须执行联动分析:
- 新增模块/驱动/平台适配
- 新增指令/消息类型
- 新增枚举值/配置项
- 新增回调/事件处理
- 新增源文件(
.c/.h)
搜索范围
⚠️ 硬门禁:联动分析前必须先读取 cross-cutting-patterns.md
进入联动搜索前,必须用 Read 读取 references/cross-cutting-patterns.md,加载完整的模式列表、搜索关键词和判断标准。禁止凭记忆或猜测选择搜索模式。
从已加载的 cross-cutting-patterns.md 中提取模式列表,按模式逐一搜索:
- 指令/消息分发表(
cmd_table,extra_cmd,msg_handler等) - 回调/钩子注册(
callback_register,event_handler,hook_list等) - 枚举↔字符串/枚举↔函数映射表
- 模块/驱动注册数组(
driver_list,module_init等) - 配置项初始化列表(
default_config,cfg_default等) - 条件编译开关链(
#ifdef FEATURE_*/#if defined(HAS_*)) - 构建/编译系统联动(
CMakeLists.txt,Makefile,Kconfig,*.mk)
参考文档:ddev-spec/references/cross-cutting-patterns.md,包含每种模式的详细搜索关键词、grep 正则和判断标准。
搜索方法(优先级递减)
- code-review-graph(
mcp__crg__query_graph_tool查callers_of/callees_of/references_to/imports_of)搜已知符号及其调用/引用关系;无图先code-review-graph build grep兜底:搜索已知符号名及其模式(函数/变量/宏/表/结构体)grep逆向追踪:搜索引用同名模块/同目录文件的所有调用点Read打开目标文件确认调用点和函数体
产出(嵌入 spec 文档)
联动修改清单,每个联动点标注:
- 文件路径
- 符号名(函数/变量/宏/表名)
- 需要添加什么(具体条目)
- 不确定时标注 "待确认" 并给出怀疑理由
强制约束
- 如果搜索到明确的注册表/回调表/映射表,必须在 spec 中标注并说明本次是否需要修改
- 如果判断"不需要修改",必须给出理由(如"该表只覆盖 X 类型,本次新增的是 Y 类型")
- 不确定时标注 "待确认" 而非沉默忽略
- 如果所有搜索返回空(非标准命名项目),须显式输出"未发现标准化联动模式,需人工确认"并附搜索过程(用了哪些关键词、搜了哪些目录),不得直接跳过
编码设计约束前置
根据项目语言,在 spec 阶段将对应的编码规范约束前置写入 spec 文档,不得留到编码阶段临场决定。
C 项目(.c / .h)
必须先加载 ddev-c-pro skill,本阶段把以下约束写进 spec 文档:
- 模块运行状态默认封装到
context/ session / handle 结构体,禁止把业务状态设计成全局变量 - 需要跨调用保存的状态,必须写清所有权、生命周期、谁能修改、谁能读取
- 主流程如果预计会出现多路分发或阶段迁移,优先在 spec 里判断是
switch、表驱动、状态机还是策略函数,不接受默认长链if/else - 配置、运行时状态、输入载荷、输出结果要分开建模,不要混在一个无语义大结构体里
- 需要共享的状态必须说明为什么不能下沉到局部变量、文件内私有状态或上下文对象
- 函数边界必须先按职责切开,避免后续出现”校验 + 解析 + 决策 + 执行”全塞进一个函数
- 参数超过 4–5 个的函数,spec 阶段就要规划用结构体封装
- 模块命名、类型命名(
_t后缀)、API 前缀、错误码枚举必须按ddev-c-pro规范提前约定 - 缓冲区大小、容量等大数字(≥1024)必须写成
N * 1024/N * 1024 * 1024可读表达式并命名宏(如MOD_TX_BUF_SIZE (16 * 1024)),禁止在示例代码或接口契约里裸写大数 - 公开 API 的 Doxygen 注释标准(
@brief/@param/@return)在 spec 文档中就要明确要求,参照ddev-comment-genskill
如果这些点在 spec 阶段说不清,说明还不该进入实现计划。
spec 文档必须回答的 C 设计问题
对于 C 项目,spec 文档至少要额外回答:
- 这次改动的核心状态属于哪个结构体,而不是属于哪个全局变量
- 状态迁移如何表达,是显式状态机、表驱动还是简单守卫式流程
- 哪些判断是真正的业务分支,哪些只是坏数据结构导致的补丁式分支
- 是否存在超过 4 个固定分支的分发点;如果有,准备采用什么替代长链
if/else - 哪些接口是对外暴露的,哪些函数必须保持
static私有 - 错误码和异常出口是集中处理还是分层返回
- 模块公开 API 命名前缀、类型
_t后缀、宏命名规则是否已按ddev-c-pro规范约定 - Doxygen 注释是否已在 spec 约束中明确要求(参照
ddev-comment-genskill)
图怎么选
- 架构规划: 组件图、边界图
- 接入点: 编号接入点图
- 功能流程: 流程图或活动图
- 修改对比: before / after 对照图
如果不确定,优先选”架构规划”,再补接入点和流程图。
Delta Summary(强制)
spec 文档头部必须包含一张 Delta Summary 表,用 ADDED / MODIFIED / REMOVED 三段显式列出本次改动相对现有代码的变更面。这张表的数据来自前面已完成的代码现状分析和联动影响分析——不引入新分析,只做格式化汇总。
格式
## Delta Summary
| 类型 | 对象 | 说明 | 复用决策 |
|------|------|------|---------|
| ADDED | `usb_hid_report_ctx_t` | 新增上下文结构体,管理 HID report 生命周期 | 扩展 `usb_core_ctx_t` 不可行:生命周期不同(HID report 在 EP 回调内,core ctx 跨请求) |
| ADDED | `src/usb/usb_hid.c` | 新增 HID 类驱动实现文件 | 新建:仓库无 HID 类驱动可复用 |
| MODIFIED | `usb_ep_handler()` in `src/usb/usb_core.c` | 增加 report ID 分派逻辑,原数据路径不变 | — |
| MODIFIED | `CMakeLists.txt` | 追加 `usb_hid.c` 到 SRC_FILES | — |
| REMOVED | `g_usb_tx_buffer` in `src/usb/usb_core.c` | 全局发送缓冲废弃,改为 ctx 内嵌 | — |
填写规则
- ADDED:本次新增的模块、文件、结构体、枚举、函数、接口、配置项、构建目标
- MODIFIED:本次修改的已有符号或文件,必须注明文件路径和修改要点(不是”改了 X 文件”而是”在 X 文件中改了 Y”)
- REMOVED:本次删除或废弃的符号、文件、全局变量、配置项
- 复用决策(ADDED 行必填,MODIFIED / REMOVED 行填”—“):说明为何不能复用/扩展已有实现。来自功能等价搜索的结论——复用/扩展已有/新建,新建必须给理由
- 每行必须能从代码现状分析或联动影响分析中找到依据,不得凭空列出
- 如果某一类为空,写”无”而不删掉该段
强制约束
- Delta Summary 表必须出现在 spec 文档正文最前面(标题和目的概述之后、第一张图之前)
- 表中的每个对象必须能在后续的图或联动修改清单中找到对应
- ddev-gate 一致性验收时,Delta Summary 是对照检查的第一入口
最低验收
在实现开始前,文档至少要通过图讲清楚:
- 改什么
- 交付什么
- 接到哪里
- 主流程怎么走
- 前后差了什么
- Delta Summary:是否已在文档头部包含 ADDED / MODIFIED / REMOVED 三段式变更汇总表,且每项都能追溯到代码现状分析或联动分析
- 每张 ASCII 图是否按 ddev-diagram 规范绘制
- 联动修改清单:是否已列出所有本次改动需要同步修改的注册表/回调表/映射表/枚举入口/编译开关/构建文件;未发现标准化模式时是否已显式标注并附搜索过程
- 框架对齐清单:是否已列出复用的现有扩展点和模式;新增模块/接口/模式是否已给出不能复用的理由;是否已标注参考实现或声明无类似实现可参考
如果仓库存在 docs/architecture/,还必须讲清楚:
- 本次改动对应的项目级架构文档路径
- 本次改动涉及哪些模块,以及是否在各模块"允许修改范围"内
- 是否新增或改变跨模块依赖
- 是否改变公共接口、外部行为或状态所有权
- 是否触发架构变更门禁;如果触发,必须先更新
docs/architecture/再进入实现计划
如果是 C 项目,还必须能看出:
- 运行时状态是否已经收敛到明确的上下文对象
- 关键分支是否已经选定为守卫式返回、
switch、表驱动或状态机,而不是含糊留给实现时发挥 - 是否已经识别需要避免的全局变量、魔法状态值和职责过载函数
- 命名规范是否已按
ddev-c-proskill 在 spec 约束中明确;Doxygen 注释要求是否已按ddev-comment-genskill 在 spec 约束中明确
对于其他语言项目,必须能看出模块边界、接口契约和关键流程分发策略。具体编码规范由对应语言的审查 skill 决定,不需要在 spec 中堆砌语言无关的编码规范。
自检
spec 文档完成后,必须逐项核对:
- 代码一致性:图中标注的模块/接口是否能在实际源码中找到对应文件/符号?如果有不存在的模块/接口,是否已标注为"新增"?
- 边界真实性:图中的模块边界和依赖方向是否与实际代码结构一致?如果不一致,是否已在 spec 中显式标注差异?
- 无凭空设计:是否存在源码中完全没有对应、也未标注为"新增"的模块名或接口名?
- 图优先:是否做到了"看图即可理解主信息"?文字是否只补充了约束和验收口径?
- 设计约束前置:C 项目的上下文收敛、分支策略、命名规范是否已在 spec 中明确?其他语言项目的模块边界和接口契约是否已明确?
- 联动覆盖:是否已搜索过项目中存在的注册表/回调表/映射表/条件编译链/构建文件?每个联动点是否已在 spec 中标注处理方式(需要修改/不需要修改及理由/待确认)?所有搜索返回空时是否已显式标注并附搜索过程?
- 框架对齐:本次设计是否优先复用了现有扩展点和模式?新增模块/接口/模式是否有充分理由并标注在 spec 中?是否标注了参考实现或声明了"无类似实现可参考"?
- Delta Summary 完整:Delta Summary 表中 ADDED / MODIFIED / REMOVED 是否完整覆盖了本次改动的所有变更面?每项是否都能在联动修改清单或图中找到对应?空类是否已标注"无"?
- 全局变量合理性:ADDED 符号中是否包含文件级/全局级变量?如有,每个是否已给出无法收敛到已有 context / 局部变量的理由?
- 接口去重:每个 ADDED 函数是否已在功能等价搜索中确认无已有等价实现?可扩展的已有函数是否被误判为"不可复用"?
- 依赖方向:新增 include / 调用是否出现底层依赖上层、工具层依赖业务层等反向依赖?(无正式架构文档时,基于目录层级推断并标注"未做正式越界检查")
- 拆分合理:是否默认保持一份 spec 文档?如果拆成多份,是否确实满足"完全不同的子系统或职责面、无共享接口与流程、可独立交付验证"的拆分条件?拆分是否按改动面而非图表类型或章节数量?
如有任一项不通过,必须在修复后再交给下游。