From cfda7f1b48e208c6b1f0895ed49266d1294496a5 Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Thu, 11 Jun 2026 18:34:23 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=BF=81=E7=A7=BB=20code-drive=20schem?= =?UTF-8?q?a=20=E4=B8=BA=E5=86=85=E7=BD=AE=E9=BB=98=E8=AE=A4=E6=B5=81?= =?UTF-8?q?=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/defaults/config.ts | 752 +++++++++++++++++++++++++++++++-- tests/core/assembler.test.ts | 18 +- tests/defaults/config.test.ts | 22 +- tests/integration/flow.test.ts | 11 + 4 files changed, 753 insertions(+), 50 deletions(-) diff --git a/src/defaults/config.ts b/src/defaults/config.ts index 8e38078..9ee84f9 100644 --- a/src/defaults/config.ts +++ b/src/defaults/config.ts @@ -232,62 +232,748 @@ rune status }, plan: { documents: [ + { + name: "requirements", + depend: [], + template: `## 背景与目标 + +## 讨论记录 + +### 已确认结论 + +### 用户偏好 + +### 被否决方案 + +## 功能需求 + +| 编号 | 需求 | 验收标准 | +| ---- | ---- | -------- | + +## 非功能需求 + +| 类别 | 要求 | +| ---- | ---- | + +## 技术需求 + +| 编号 | 类别 | 决策 | 理由 | 被否决方案 | +| ---- | ---- | ---- | ---- | ---------- | + +## 全局审查 + +### 与现有系统的关联 + +### 前置条件 +`, + prompt: `你正在撰写 requirements.md——需求确认与澄清文档。把"要解决什么、为什么、需要用户决策哪些业务和技术边界"固定为事实来源。 + +requirements.md 的职责是确认和澄清:通过对话把需求、边界、取舍和用户决策固定下来。design.md 负责把它们翻译为可执行方案——不要在 requirements 展开详细实现步骤、具体文件修改清单或任务 checkbox。 + +本阶段承接前序讨论和代码库调查结果。文档面向项目开发者,因此既要确认业务需求,也要确认技术需求:技术选型、架构方向、集成边界、代码约束、验收方式。 + +--- + +## 工具使用 + +- **todo 工具**(如 todowrite):复杂变更必须用它跟踪撰写流程,颗粒度细化到子步骤;简单变更(单一模块、单一决策点、预期 < 100 行文档)可省略 +- **question 工具**:触发提问流程时必须优先使用,而非让用户开放回答 +- **只读工具**(Read / Grep / Glob / Bash 只读命令):工作流任意步骤中允许使用,不视为决策型交互 + +--- + +## 向用户提问的标准流程(强制协议,适用于本阶段所有提问环节) + +本流程是 requirements 阶段用户决策唯一入口。任何步骤触发以下条件时必须按本流程执行,不得跳过、不得自行决定、不得延迟到下游。 + +### 触发条件(命中任一即必须启动提问流程) + +1. 检测到潜在冲突——任意两条需求/约束/决策之间存在矛盾、取舍未定、可解读不一致或可能相互排斥 +2. 遇到开放问题——任何形式的"开放问题""TBD""待确认""待讨论"章节或条目 +3. 技术决策点未定——技术选型有多个合理选项且未排除、架构方向存在分歧、集成边界或代码约束未确认 +4. YAGNI 取舍未定——某条需求是否真需要、是否应简化、是否应排除本次范围 +5. 需求边界不清——功能范围、行为定义、验收标准存在一种以上合理理解 +6. 依赖约束未定——上下游依赖、兼容性要求、外部约束未确认 +7. 范围过大需要拆细——本次变更涉及多个独立维度、子系统或大量决策点 +8. 最终确认(步骤 7)——即使前 7 条全部未命中,最终确认仍是强制提问 + +### 提问格式(强制) + +每次提问必须按以下格式输出,不得让用户从零开放回答: + +- 2-3 个候选选项:每个选项给出明确含义,避免无信息标签 +- 推荐方案:明确标注推荐哪一个,不得回避 +- 取舍说明:每个非推荐选项说明未选的理由;推荐选项说明取舍的代价 +- 使用工具:工具支持 question/choice 时必须使用结构化选项 + +### 决策归档规则 + +用户给出决策后: + +1. 按性质归入对应章节——功能需求 / 非功能需求 / 技术需求 / 被否决方案等 +2. 冲突本身不得以任何形式单独保留——不设"冲突解决记录"章节 +3. 被否决方案归入"讨论记录/被否决方案",并写明否决理由 +4. 新结论引发新冲突时回到触发条件 1,重新启动提问流程 + +--- + +## 工作流 + +### 步骤 1: 收集上下文、评估范围、拆细问题 + +合并"理解现状、判断范围、拆分提问粒度"三件事,避免在范围未定时就深入细节。 + +**子步骤 1.1: 收集上下文** + +- 读取相关讨论、代码库现状、用户原始请求,形成初步理解 +- 先读再问:不要询问代码库或文档中已经能确认的信息 + +**子步骤 1.2: 评估范围** + +- 判断本次变更是否涉及多个独立维度、子系统或大量决策点 +- 不涉及 → 进入步骤 2 +- 涉及 → 进入子步骤 1.3 + +**子步骤 1.3: 拆细问题** + +- AI 主动识别范围内的独立维度 +- 把每个维度拆成 1-3 个具体问题(每个问题独立可决策) +- 触发提问流程,按维度逐项让用户确认 +- 用户全部决策归档后进入步骤 2 + +### 步骤 2: 撰写初稿 + +按必需章节填写:背景与目标 / 讨论记录 / 功能需求 / 非功能需求 / 技术需求 / 全局审查。 + +撰写要求: + +- 面向看不到早期对话的人:必须保留关键上下文、用户偏好、已确认结论、约束和被否决方案 +- 功能需求必须带验收标准 +- 非功能需求只记录本次变更相关内容 +- 技术需求记录已确认的选型、架构方向、集成边界、代码约束或禁止事项 +- 不写具体文件修改步骤、代码结构、任务 checkbox 或详细实现计划 + +撰写过程中遇到触发条件 3/4/5/6 时,立即启动提问流程。 + +简单变更保持精炼;复杂或横切变更必须写足够细节,避免后续 design/plan/build 依赖未写入文档的聊天上下文。 + +### 步骤 3: 全局审查 + YAGNI 挑战 + +对初稿做两个角度的挑战: + +**子步骤 3.1: 全局审查** + +从系统边界、既有行为、相邻模块、配置、文档、迁移、兼容性、安全、性能和用户流程角度挑战当前需求。 + +**子步骤 3.2: YAGNI 挑战** + +对每条需求问——是否真的需要、能否更简单、是否存在更轻量替代方案、是否超出本次范围。 + +**子步骤 3.3: 结果分类处理** + +- 发现潜在冲突 → 进入步骤 4 +- 发现开放问题 / 技术决策未定 / YAGNI 取舍未定 / 边界不清 → 启动提问流程 +- 无问题 → 进入步骤 5 + +### 步骤 4: 冲突检测与解决 + +扫描任意两条需求/约束/决策之间是否存在矛盾、取舍未定、可解读不一致或可能相互排斥。 + +- 发现潜在冲突 → 立即暂停撰写,启动提问流程 +- 用户决策后,结论按性质归入对应章节,冲突本身不得以任何形式单独保留 +- 无冲突 → 进入步骤 5 + +### 步骤 5: 开放问题清零 + +全文扫描是否存在"开放问题""TBD""待确认""待讨论"章节或条目。 + +- 发现开放问题 → 启动提问流程 +- 某问题确实需要延续到 design 或 build 阶段才能解决 → 启动提问流程,让用户决定是否拆分变更或暂时排除本次范围 +- 全部问题已通过用户决策解决并归档 → 进入步骤 6 +- 不得在 requirements.md 中以"开放问题"形式保留任何条目 + +### 步骤 6: 自检 + +按以下清单逐项检查,发现问题立即修复后重跑该项: + +- 占位符扫描:无模板注释、英文模板句子、TBD、待补充、空表格行或"开放问题"章节 +- 章节完整性:必需章节齐全 +- 上下文一致性:讨论记录的"已确认结论"都已落入对应章节;被否决方案没有被复用 +- 冲突清零:所有需求、约束之间无矛盾/歧义/未决取舍 +- 待确认问题清零:全文无"开放问题""TBD""待确认""待讨论"等未决条目 +- 全局审查充分性:系统边界、既有行为、相邻模块、配置、迁移、兼容性都被审视过 +- YAGNI:每条需求都经过挑战,没有"未来可能需要但本次不必需"的功能 +- 范围合适:能用单一 design.md 承接,或已建议拆分为多个子变更 + +自检全部通过后进入步骤 7;任一项失败 → 修复后从该项重跑,必要时回到步骤 2-5。 + +### 步骤 7: 用户最终确认(不得跳过) + +强制触发提问流程,即使用户在前 6 步中已经多次决策。 + +提问内容: + +1. 展示关键决策点:功能需求、技术需求各一句话总结 +2. 仍有待确认内容(步骤 6 自检后发现遗漏)→ 按提问格式逐项提问 +3. 无任何待确认内容 → 必须输出最后一问:"当前已无更多内容待确认,是否进入下一步" + +结束条件: + +- 用户明确肯定 → 本阶段结束 +- 用户选择补充或修改 → 根据反馈调整内容,重跑步骤 6 + 步骤 7 + +--- + +## 完成标准 + +- 工作流步骤 1-7 全部走过 +- 步骤 6 自检 8 项全部通过 +- 步骤 7 收到用户明确肯定 +- 所有触发条件命中时都执行了提问流程 +`, + }, { name: "design", - prompt: `请先获取当前规划状态。 + depend: ["requirements"], + template: `## 代码库探索 -建议执行: rune status <变更名> +### 已有代码与模式 -请根据之前的讨论内容和状态输出,生成一份设计文档。 +### 依赖状态 -要求: -- 清晰描述背景和目标 -- 列出方案选项并给出推荐 -- 定义关键接口和数据结构 -- 考虑边界情况和错误处理 +### 开发规范约束 -请将文档写入指定路径。`, - template: `# 设计文档 +## 整体方案 -## 背景 +### 架构概览 -## 目标 +### 关键交互流程 -## 方案 +## 目标 / 非目标 -## 接口设计 +**目标:** -## 注意事项 +**非目标:** + +## 关键决策 + +| 决策 | 来源 | 理由 | +| ---- | ---- | ---- | + +## 影响范围 + +| 范围 | 变更类型 | 原因 | +| ---- | -------- | ---- | + +### 关键实现路径 + +## 依赖与约束 + +- 依赖: +- 兼容性: +- 质量门禁: +- 禁止事项: + +## 风险 / 权衡 + +## 验证方向 +`, + prompt: `你正在撰写 design.md——基于 requirements.md 和必要技术探索的概要技术设计文档。把 requirements.md 确认的需求翻译为概要技术方案——回答"采用什么总体技术方向、关键决策是什么、影响哪些范围"。 + +design.md 的职责是翻译与补充探索:基于 requirements.md 已确认的需求和技术方向,补充代码库层面的探索发现,固定为可执行的设计依据。不要在本阶段写详细实现步骤或任务 checkbox;详细实现属于 plan.md,checkbox 只属于 task.md。 + +--- + +## 工具使用 + +- **todo 工具**:复杂变更必须跟踪到工作流子步骤;简单变更可省略 +- **只读工具**:Read / Grep / Glob / Bash 只读命令可用于代码库探索,不视为决策型交互 +- **禁止**:不得使用 question / choice 发起决策型提问;决策型分歧必须走"回退上游流程" + +--- + +## 回退上游流程(强制协议) + +design 的默认行为是自治执行——AI 自己消化探索发现并写入 design.md,只在真正无法独立解决时才回流。 + +### AI 自决范围(不触发回退,直接处理并写入 design.md) + +以下情况 AI 自行决策并落地到 design.md 对应章节,不触发回退: + +- 代码可复用 → 优先复用,记录到"代码库探索/已有代码与模式" +- 依赖版本细节不符但兼容 → 选兼容方案 +- 次要模块需要触碰但不影响核心决策 → 纳入"影响范围" +- 实现层取舍(API 设计、数据结构、代码组织、命名)→ AI 给出理由 + 至少一个被否决方案,写入"关键决策" +- 全局审查发现的非核心边界 → 直接补全到"影响范围"或"风险/权衡" +- requirements.md 未明确但可从既有代码/项目规范推断 → 按推断方向走,标注"基于代码库规范推断" + +### 触发条件(命中任一即必须启动回退流程,仅 3 条) + +1. 核心方向决策真空——requirements.md 对本次变更的核心技术方向/架构方向/业务边界未给出唯一决策,存在 2 个以上互相排斥且都合理的选择,且选哪个会导致整体方案有本质差异 +2. 核心前提错误——代码库探索发现 requirements.md 的核心前提与事实不符,且这种不符会让整个方案失效 +3. 必须扩展本次业务范围或引入核心新依赖——发现要实现 requirements.md 已确认的功能,必须扩展本次变更的业务范围或引入 requirements.md 未确认的核心外部依赖 + +### 暂停报告格式(触发回退时) + +触发回退时,必须暂停撰写,按以下格式输出报告: + +- 触发条件编号 + 命中证据 +- 影响的设计章节 +- 回退到 requirements +- 需要在 requirements 补充的具体决策点(每个问题 2-3 个候选选项 + 推荐方案 + 取舍说明) +- 本阶段当前进度 + +### 强制语义 + +- 触发条件命中时必须启动回退流程 +- 不得在 design.md 中以"待确认""TBD""待讨论""开放问题"形式保留任何条目 +- 反向约束:未命中触发条件时不得主动询问用户——AI 自决范围内的情况一律自决 +- 用户在 requirements 阶段补充决策后,从步骤 1 重新评估 + +--- + +## 工作流 + +### 步骤 1: 读取上游并评估探索充分性 + +**子步骤 1.1: 读取 requirements.md 与前序讨论** + +- 完整读取 requirements.md,识别其中已确认的技术选型、架构方向、集成边界、约束 +- 识别 requirements.md 中已经做过的代码库探索发现 + +**子步骤 1.2: 评估探索充分性** + +按 3 个判断点逐一检查: + +- requirements.md 确认了技术选型,是否已检查项目中该依赖的安装状态或版本约束? +- requirements.md 确认了架构方向,是否已检查现有代码中可复用的组件、工具函数、数据结构或架构约定? +- 需求涉及的模块,是否在 requirements.md 或前序讨论中已被探索过? + +**子步骤 1.3: 判断是否需要补充探索** + +- 三项均已充分 → 直接进入步骤 3(跳过步骤 2) +- 任一项不充分 → 进入步骤 2 + +### 步骤 2: 代码库补充探索(仅当步骤 1.3 判断需要) + +- 检查依赖状态:验证 requirements.md 中确认的技术选型在项目中的实际状态 +- 检查可复用代码:探索现有组件、工具函数、数据结构、API 模式、架构约定 +- 检查项目规范约束:探索项目编码规范、命名约定、架构约束、质量门禁 +- 检查回退触发条件:探索发现先判断是否属于 AI 自决范围;不属于再判断是否命中触发条件 + +### 步骤 3: 撰写初稿 + +按模板章节顺序撰写:代码库探索 / 整体方案 / 目标·非目标 / 关键决策 / 影响范围 / 依赖与约束 / 风险·权衡 / 验证方向。 + +撰写要求: + +- 整体方案:描述模块、组件或流程如何组织和协作 +- 目标 / 非目标:目标对齐 requirements.md 的功能需求;非目标明确划界 +- 关键决策:引用 requirements.md 已确认的决策,仅补充实现层决策 +- 影响范围:列出受影响的模块、文件、配置、接口、文档、流程或外部依赖 +- 依赖与约束:依赖、兼容性、质量门禁、禁止事项四项必备 +- 风险 / 权衡:每条风险对应缓解措施 +- 验证方向:覆盖 requirements.md 的功能验收标准和非功能需求 + +撰写过程中遇到触发条件 1/2/3 时,立即启动回退流程。实现层取舍属于 AI 自决范围,直接写入"关键决策"章节。 + +### 步骤 4: 关键决策挑战 + +- 决策合理性检查:每个关键决策是否有理由,是否记录了至少一个被否决方案或主要取舍 +- 回退触发条件复查:全文扫描是否在撰写过程中暴露出触发条件 1/2/3 + +### 步骤 5: 自检 + +按以下清单逐项检查,发现问题立即修复后重跑该项: + +- 占位符扫描:无模板注释、TBD、待补充、空表格行或"待确认事项"章节 +- 需求覆盖:requirements.md 的每条功能需求都有决策覆盖 +- 决策合理性:每个关键决策有理由,并记录至少一个被否决方案或主要取舍 +- 代码库现实:设计基于代码库探索发现,而非从零假设 +- 验证方向对齐:验证方向覆盖 requirements.md 的功能验收标准和非功能需求 +- 待确认清零:全文无"待确认""TBD""待讨论""开放问题"等未决条目 + +--- + +## 完成标准 + +- 工作流步骤 1-5 全部走过 +- 步骤 5 自检 6 项全部通过 +- 未触发任何回退条件,或触发的回退已被解决并重新走过工作流 +- design.md 无任何形式的"待确认 / TBD / 待讨论 / 开放问题" +`, + }, + { + name: "plan", + depend: ["requirements", "design"], + template: `## 实现概览 + +## 涉及文件 + +| 文件路径 | 变更类型 | 所属阶段 | +| -------- | -------- | -------- | + +## 阶段 N: + +### 目标 + +### 前置条件 + +### 详细实现步骤 + +### 关键代码模式 + +**新增 / 修改的函数或方法:** + +**新增 / 修改的数据结构:** + +**调用顺序 / 流程:** + +**约定 / 模式:** + +### 验证方式 + +### 验收标准 + +### 关联需求 + +## 验证策略 + +## 回退 / 兼容性说明 + +- 回退策略: +- 错误处理: +- 兼容性: +- 迁移注意事项: +`, + prompt: `你正在撰写 plan.md——从 design.md 派生的详细实现计划文档。把 design.md 的概要设计展开为可独立理解、可验证、可执行的实现阶段——回答"分几个阶段实现、每阶段做什么、如何验证"。 + +plan.md 的职责是展开与具体化:把 design.md 的关键决策展开为具体阶段、文件、函数签名、调用流程,使 task.md 可以只写 checkbox 而不必重新设计实现方案。不要在本阶段写 checkbox;checkbox 只属于 task.md。 + +--- + +## 工具使用 + +- **todo 工具**:复杂变更必须跟踪到工作流子步骤;简单变更可省略 +- **只读工具**:Read / Grep / Glob / Bash 只读命令可用于核实函数签名、依赖路径,不视为决策型交互 +- **禁止**:不得使用 question / choice 发起决策型提问;决策型分歧必须走"回退上游流程" + +--- + +## 回退上游流程(强制协议) + +plan 的默认行为是自治执行——AI 自己把 design.md 展开为阶段,只在真正无法独立解决时才回流。 + +### AI 自决范围(不触发回退,直接处理并写入 plan.md) + +以下情况 AI 自行决策并落地到 plan.md 对应章节,不触发回退: + +- 阶段划分细节(design.md 未明确阶段顺序时)→ AI 给出阶段顺序并写明理由 +- 函数/数据结构具体化(design.md 给出方向但 plan 需要具体签名)→ AI 自决具体签名 +- 次要文件归类 → AI 直接归阶段 +- 验证方式细节 → AI 给出具体验证步骤 +- 阶段间依赖关系标注 → AI 自决并标注前置条件 +- 实现层取舍 → AI 给出理由 + 至少一个被否决方案 + +### 触发条件(命中任一即必须启动回退流程,仅 3 条) + +1. 核心实现方向决策真空——展开 design.md 时发现核心实现路径存在 2 个以上互相排斥且都合理的选择,且选哪个会导致整体阶段划分或文件结构有本质差异 +2. 核心前提错误——展开阶段细节时发现 design.md 的核心设计前提与代码库事实不符,且这种不符会让整个实现计划失效 +3. 必须扩展本次业务范围或引入核心新依赖 + +### 暂停报告格式(触发回退时) + +触发回退时,必须暂停撰写,按以下格式输出报告: + +- 触发条件编号 + 命中证据 +- 回退到 design(默认)或 requirements +- 影响 plan.md 哪些阶段或章节 +- 需要在上游补充的具体决策点(每个问题 2-3 个候选选项 + 推荐方案 + 取舍说明) +- 本阶段当前进度 + +### 强制语义 + +- 触发条件命中时必须启动回退流程 +- 不得在 plan.md 中以"待确认""TBD""待讨论""开放问题""待补充"形式保留任何条目 +- 反向约束:未命中触发条件时不得主动询问用户 +- 用户在上游补充决策后,从步骤 1 重新评估 + +--- + +## 工作流 + +### 步骤 1: 读取上游并评估展开充分性 + +- 完整读取 design.md,识别关键决策、影响范围、关键实现路径、验证方向 +- 完整读取 requirements.md,对齐功能需求与非功能需求的验收标准 +- 评估展开充分性:design.md 的关键决策是否细到可以拆出明确阶段?影响范围是否明确到文件级别?关键实现路径是否给出优先级? + +### 步骤 2: 阶段划分与"涉及文件"汇总 + +- 划分主要阶段:基于 design.md 的关键实现路径和影响范围识别主要实现阶段 +- 撰写每个阶段的"目标 / 前置条件 / 关联需求" +- 汇总"涉及文件":按阶段列出涉及的核心文件路径、变更类型 +- 检查回退触发条件 + +### 步骤 3: 撰写各阶段细节 + +逐阶段填写"详细实现步骤 / 关键代码模式 / 验证方式 / 验收标准"。 + +- 详细实现步骤:写清楚关键文件、函数、数据结构、流程或配置变化。不要使用 checkbox。步骤要具体到函数签名级别或调用流程级别 +- 关键代码模式:新增/修改的函数或方法签名、数据结构、调用顺序/流程、约定/模式 +- 验证方式 + 验收标准:本阶段如何独立验证,对齐 requirements.md 验收标准 + +撰写过程中遇到触发条件时,立即启动回退流程。 + +### 步骤 4: 撰写全局章节 + +- 实现概览:概述实现阶段、依赖顺序 +- 验证策略:汇总各阶段验证方式 + 整体验证 +- 回退/兼容性说明:回退策略 / 错误处理 / 兼容性 / 迁移注意事项 +- 检查回退触发条件 + +### 步骤 5: 自检 + +按以下清单逐项检查,发现问题立即修复后重跑该项: + +- design 覆盖:design.md 的每个关键决策在 plan.md 中都有实现路径 +- 阶段独立性:每个阶段能独立验证,或明确说明依赖哪个前置阶段 +- 占位符扫描:详细实现步骤和关键代码模式无含糊;"TBD""TODO""待补充""类似阶段 N"都必须用具体内容替换 +- 类型一致性:后续阶段引用的函数名、参数、类型签名与前置阶段定义的匹配 +- 验证闭环:每个阶段的验证方式能独立确认该阶段完成 +- 待确认清零:全文无"待确认""TBD""待讨论""待补充""开放问题"等未决条目 + +--- + +## 完成标准 + +- 工作流步骤 1-5 全部走过 +- 步骤 5 自检 6 项全部通过 +- 未触发任何回退条件,或触发的回退已被解决并重新走过工作流 +- plan.md 无任何形式的"待确认 / TBD / 待讨论 / 待补充 / 开放问题" `, }, ], }, task: { - prompt: `你是一位高级软件工程师,擅长将设计文档拆解为可执行的任务列表。 + prompt: `你正在撰写 task.md——从 plan.md 派生的可跟踪执行清单。把 plan.md 的实现阶段拆解为可执行动作——回答"每个阶段具体做哪几个动作、按什么顺序、何时验证"。 -请先读取变更目录下所有已有的规划文档(如 design.md),理解设计内容。 +task.md 的职责是拆解为可执行动作:每个任务是单个文件、单个函数或单个可验证行为级别的具体动作,build 阶段据此执行并跟踪进度。不要在本阶段重新发明实现方案——需要关键实现细节时引用 plan.md。 -然后将设计拆分为一份任务列表,写入 task.md。 +--- -要求: -- 将设计拆分为可独立执行的小任务 -- 每个任务应该足够具体,能直接编码实现 -- 任务之间有合理的依赖顺序 -- 使用 checkbox 格式:- [ ] 待完成,- [x] 已完成 -- 格式固定为 checkbox 列表,不需要模板 +## 工具使用 -请将任务列表写入指定路径的 task.md 文件。`, +- **todo 工具**:复杂变更必须跟踪到工作流子步骤;简单变更可省略(plan.md 阶段数 ≤ 2、单文件变更、预期 < 50 行文档) +- **只读工具**:Read / Grep / Glob / Bash 只读命令可用于核实文件路径、函数签名,不视为决策型交互 +- **禁止**:不得使用 question / choice 发起决策型提问;决策型分歧必须走"回退上游流程" + +--- + +## 回退上游流程(强制协议) + +tasks 的默认行为是自治执行——plan.md 已经把决策做完,AI 只需把决策拆为 checkbox,只在真正无法独立解决时才回流。 + +### AI 自决范围(不触发回退,范围最广) + +以下情况 AI 自行决策并落地到 task.md,不触发回退: + +- 任务拆分粒度(每阶段 3-6 任务如何分布) +- 任务描述措辞(动词 + 文件路径 + 具体动作) +- 测试穿插位置(哪个验证任务放在哪个阶段) +- 阶段内任务的依赖顺序 +- 任务编号 X.Y(X 跟随 plan 阶段编号) +- plan.md 未给出明确函数签名但暗示了方向 → AI 推断具体动作 +- "验证与收尾"分组的具体条目数(3-6 条之间调整) +- plan.md 的实现步骤较粗但可拆 → AI 自行拆分 + +### 触发条件(命中任一即必须启动回退流程,仅 3 条) + +1. plan.md 核心实现路径完全缺失——某个核心 plan 阶段完全没有"详细实现步骤"或"关键代码模式",AI 无法从中拆出任何具体动作 +2. 核心前提错误——plan.md 假设的核心接口、函数或数据结构与代码库事实不符,且这种不符会让整个阶段的任务无法执行 +3. 必须扩展本次业务范围或引入核心新依赖 + +### 暂停报告格式(触发回退时) + +触发回退时,必须暂停撰写,按以下格式输出报告: + +- 触发条件编号 + 命中证据 +- 回退到 plan(默认)或 design/requirements +- 影响 task.md 哪些分组或任务 +- 需要在上游补充的具体决策点(每个问题 2-3 个候选选项 + 推荐方案 + 取舍说明) +- 本阶段当前进度 + +--- + +## 工作流 + +### 步骤 1: 读取上游并评估可拆分性 + +- 完整读取 plan.md,识别阶段划分、每阶段的"详细实现步骤"和"关键代码模式" +- 对齐 requirements.md 的验收标准和 design.md 的关键决策 +- 评估可拆分性:每个 plan 阶段是否有足够细节拆出 3-6 个具体动作 + +### 步骤 2: 拆分各 plan 阶段任务 + +逐阶段处理。每个 plan 阶段生成一个 \`## X. <分组标题>\` 任务分组。 + +- 建立分组对应:每个 plan.md 阶段必须有一个对应的 \`##\` 编号任务分组,分组编号 X 与 plan 阶段编号一致 +- 拆分动作任务(3-6 个/阶段):每个任务必须是单行 checkbox:\`- [ ] X.Y 任务描述\`,粒度控制在单个文件、单个函数或单个可验证行为级别 +- 穿插验证任务:每个阶段必须有至少 1 个验证任务,穿插在阶段内(紧跟关键实现任务之后) +- 元任务(每阶段第一条):建议是"阅读 plan.md 阶段 N,确认涉及文件、关键代码模式和验收标准" + +### 步骤 3: 撰写"验证与收尾"分组 + +最后一个分组必须是"验证与收尾"(编号紧接前一阶段 +1)。 + +必需条目: +- 阅读 plan.md 验证策略,确认所有验证项已执行 +- 执行完整测试套件,确认无回归 +- 逐项对照 requirements.md 验收标准,确认全部满足 +- 检查 design.md 关键决策是否被正确实现 +- 如果行为、流程、接口、配置或使用方式发生变化,更新相关文档 +- 确认所有任务已标记为 \`[x]\` + +### 步骤 4: 自检 + +按以下清单逐项检查,发现问题立即修复后重跑该项: + +- checkbox 格式:每个任务都是 \`- [ ] X.Y 任务描述\` 单行格式 +- 分组对应:每个 plan.md 阶段都有对应的 \`##\` 分组 +- 占位符扫描:无模板注释、英文模板任务、"待补充""TBD""TODO"或占位任务文本 +- 粒度合理:每阶段 3-6 个具体动作任务 +- 测试穿插:每阶段至少 1 个验证任务,穿插在阶段内 +- plan 覆盖:plan.md 每个阶段的"详细实现步骤"和"关键代码模式"都被拆到任务里 +- 依赖顺序:任务按依赖顺序排 +- 待确认清零:全文无"待确认""TBD""待讨论""待补充""开放问题"等未决条目 + +--- + +## 完成标准 + +- 工作流步骤 1-4 全部走过 +- 步骤 4 自检 8 项全部通过 +- 未触发任何回退条件,或触发的回退已被解决并重新走过工作流 +- task.md 无任何形式的"待确认 / TBD / 待讨论 / 待补充 / 开放问题 / 模板注释" +- 所有 checkbox 都是 \`- [ ] X.Y 任务描述\` 格式 +`, }, build: { - prompt: `你是一位高级软件工程师。 -请按照任务列表,逐个完成编码任务。 + prompt: `你正在执行 build 阶段——按 task.md 的 checkbox 顺序执行变更。逐项实现任务、收集验证证据、标记完成状态,使本次变更落到代码库中并可被审计。 -要求: -- 严格按顺序执行,从第一个未完成的任务开始 -- 每完成一个任务,立即更新 task.md 中对应项为 [x] -- 遵循项目现有的代码风格和约定 -- 编写必要的测试 -- 完成所有任务后,提示用户可以使用 /rune-archive <变更名> 归档`, +build 的职责是执行而非设计:所有实现路径、函数签名、依赖选择、阶段划分都已在 plan.md / design.md / requirements.md 中确定;build 只负责把这些设计转化为代码、测试、配置或文档的实际变更。不要在本阶段重新决策实现方向。 + +--- + +## 工具使用 + +- **todo 工具**:必须跟踪执行进度;每个未完成任务标记为 in_progress 或 pending,完成后标记 completed,并同步回 task.md checkbox +- **subagent / task 派发工具**:用于并行执行独立任务(详见步骤 4) +- **读写工具**:Read / Edit / Write / Grep / Glob / Bash 是主要工具 +- **禁止**:不得使用 question / choice 发起决策型提问;决策型分歧必须走"暂停报告"流程 + +--- + +## 暂停报告机制(强制协议,适用于本阶段所有"无法独立解决"环节) + +build 的默认行为是按计划执行——只在真正无法独立解决时才暂停报告。暂停报告的成本是中断整个变更流程让用户介入,因此触发条件 reserved 给"AI 真处理不了的高价值错误"。 + +### AI 自决范围(不触发暂停报告,直接处理并落地到代码) + +以下情况 AI 自行决策并落地到代码实现,不触发暂停报告: + +- 函数体内部实现(plan.md 给出签名但未给出具体逻辑) +- 次要 bug 修复(执行过程中发现非核心 bug)→ 顺手修复,在 commit 信息中说明 +- 命名/格式/注释调整(plan.md 未限定时) +- 测试用例具体数据(plan.md 给出测试方向但未给数据) +- 错误消息措辞(plan.md 未限定时) +- 依赖路径或导入顺序调整(兼容范围内) +- plan.md 阶段内步骤的微调(不改变阶段目标或文件归属) +- 可从 design.md/requirements.md/既有代码规范推断的细节 + +### 触发条件(命中任一即必须暂停并报告,仅 3 条) + +1. 核心实现路径不可行——执行过程中发现 plan.md 的核心实现路径在代码库中无法落地,且没有可推断的替代路径 +2. 核心前提错误——执行过程中发现 requirements.md/design.md/plan.md 的核心假设与代码库事实不符,且这种不符会让整个变更方向失效 +3. 必须扩展本次业务范围或引入核心新依赖——执行过程中发现要落地已确认的设计,必须扩展本次变更的业务范围或引入未确认的核心外部依赖 + +### 暂停报告格式(触发时) + +触发时,必须暂停执行,按以下格式输出报告: + +- 触发条件编号 + 命中证据:明确指出命中了第几条触发条件,附上具体证据 +- 影响的任务:列出 task.md 中哪些任务因此无法继续 +- 需要在上游补充的具体决策点:列出上游需要补充回答的具体问题,每个问题 2-3 个候选选项 + 推荐方案 + 取舍说明 +- 当前进度:当前已完成到哪个任务 + +### 强制语义 + +- 触发条件命中时必须暂停并报告 +- 不得在 task.md 或代码注释中以"待确认""TBD""待讨论""开放问题"形式保留任何条目 +- 反向约束:未命中触发条件时不得主动询问用户——AI 自决范围内的情况一律自决 + +--- + +## 工作流 + +### 步骤 1: 加载上下文 + +按顺序读取:requirements.md → design.md → plan.md → task.md。 + +明确以下映射(后续步骤遇到分歧时按此优先级判断): + +- 需求 / 范围 / 验收 / 全局审查 → requirements.md +- 技术方向 / 关键决策 → design.md +- 实现计划 / 关键代码模式 → plan.md +- 执行进度 / 任务依赖顺序 → task.md + +### 步骤 2: 规划执行 + +- 扫描 task.md:识别所有未完成的 \`- [ ]\` 任务,按依赖顺序排序 +- 建立 todo 列表:每个未完成任务对应一个 todo item +- 检查暂停触发条件 + +### 步骤 3: 逐任务执行(核心循环) + +对每个未完成任务循环执行: + +1. **加载任务上下文**:读取该任务在 task.md 中的描述,读取 plan.md 对应阶段的"涉及文件""关键代码模式""验收标准" +2. **执行实现**:按 plan.md 的关键代码模式实现(修改代码、新增文件、调整配置等)。实现层取舍属于 AI 自决范围 +3. **收集验证证据**:运行 plan.md 该阶段"验证方式"指定的命令(测试、构建、lint、手动检查)。必须用实际命令输出、测试结果或可观察行为作为证据 +4. **标记完成**:任务执行完成且获得新的实际验证证据后,才能将 task.md 中对应行标记为 \`[x]\`。不得基于假设、推测或"应该可以"标记完成。同步更新 todo 工具状态为 completed +5. **检查触发条件**:本任务执行过程中是否暴露触发条件 1/2/3?命中 → 立即暂停并报告 + +### 步骤 4: 并行执行(如可用 subagent) + +仅在工具支持 subagent / task 派发时启用。 + +满足以下全部条件的任务可并行: + +- 与已派发或正在执行的任务没有文件依赖 +- 不依赖前置任务的输出或运行时副作用 +- 属于不同 plan.md 阶段或同阶段内明确独立的工作单元 + +每个 subagent 完成后必须返回:执行结果摘要、变更文件列表、验证证据。 + +主 agent 负责:合并 subagent 结果、更新 task.md checkbox(不让 subagent 直接写 task.md)、处理冲突。 + +### 步骤 5: 完成确认(最后一个任务后) + +- task.md 中所有任务都是 \`[x]\` +- todo 工具中所有 item 都是 completed +- 最后一个"验证与收尾"分组的所有验证任务都已通过 +- 最终一致性检查:残留的"待确认""TBD""待讨论"是否已清零 +- 输出完成报告:完成任务总数、变更文件列表、验证证据汇总 + +--- + +## 完成标准 + +- task.md 中所有任务都已标记为 \`[x]\` +- 所有任务都有实际验证证据(命令输出 / 测试结果 / 可观察行为) +- 代码库 / task.md / 任何文件中无"待确认 / TBD / 待讨论 / 待补充 / 开放问题"残留 +- 输出了完成报告 +`, }, archive: { prompt: `当前变更已进入归档阶段。 diff --git a/tests/core/assembler.test.ts b/tests/core/assembler.test.ts index 79b73de..f945379 100644 --- a/tests/core/assembler.test.ts +++ b/tests/core/assembler.test.ts @@ -42,26 +42,26 @@ describe("assembleDiscussPrompt", () => { describe("assemblePlanPrompt", () => { it("包含指定文档名称和提示词", async () => { - const prompt = await assemblePlanPrompt(defaultConfig, TMP_DIR, "user-auth", "design"); + const prompt = await assemblePlanPrompt(defaultConfig, TMP_DIR, "user-auth", "requirements"); expect(prompt).toContain("user-auth"); - expect(prompt).toContain("design"); + expect(prompt).toContain("requirements"); expect(prompt).not.toContain("task"); }); it("已有文档时引导 AI 读取而非内嵌内容", async () => { const changeDir = join(TMP_DIR, ".rune", "changes", "user-auth"); await mkdir(changeDir, { recursive: true }); - await writeFile(join(changeDir, "design.md"), "# 已有设计"); - const prompt = await assemblePlanPrompt(defaultConfig, TMP_DIR, "user-auth", "design"); + await writeFile(join(changeDir, "requirements.md"), "# 已有需求"); + const prompt = await assemblePlanPrompt(defaultConfig, TMP_DIR, "user-auth", "requirements"); expect(prompt).toContain("已有内容"); - expect(prompt).toContain("design.md"); - expect(prompt).not.toContain("# 已有设计"); + expect(prompt).toContain("requirements.md"); + expect(prompt).not.toContain("# 已有需求"); }); it("包含格式模板(纯静态文本)", async () => { - const prompt = await assemblePlanPrompt(defaultConfig, TMP_DIR, "user-auth", "design"); + const prompt = await assemblePlanPrompt(defaultConfig, TMP_DIR, "user-auth", "requirements"); expect(prompt).toContain("格式模板"); - expect(prompt).toContain("# 设计文档"); + expect(prompt).toContain("背景与目标"); expect(prompt).not.toContain("{{change-name}}"); }); @@ -82,7 +82,7 @@ describe("assemblePlanPrompt", () => { }); it("无依赖时不包含依赖说明", async () => { - const prompt = await assemblePlanPrompt(defaultConfig, TMP_DIR, "user-auth", "design"); + const prompt = await assemblePlanPrompt(defaultConfig, TMP_DIR, "user-auth", "requirements"); expect(prompt).not.toContain("依赖说明"); }); diff --git a/tests/defaults/config.test.ts b/tests/defaults/config.test.ts index 094b9f4..38418c7 100644 --- a/tests/defaults/config.test.ts +++ b/tests/defaults/config.test.ts @@ -43,17 +43,23 @@ describe("defaultConfig", () => { expect(prompt).toContain("task.md"); }); - it("plan 阶段包含 design 文档配置", () => { + it("plan 阶段包含三个文档配置(requirements/design/plan)", () => { const docs = defaultConfig.stages.plan!.documents; - expect(docs).toHaveLength(1); - expect(docs[0].name).toBe("design"); - expect(docs[0].prompt).toBeTruthy(); + expect(docs).toHaveLength(3); + expect(docs[0].name).toBe("requirements"); + expect(docs[0].depend).toEqual([]); + expect(docs[1].name).toBe("design"); + expect(docs[1].depend).toEqual(["requirements"]); + expect(docs[2].name).toBe("plan"); + expect(docs[2].depend).toEqual(["requirements", "design"]); }); - it("design 文档有 template", () => { - const designDoc = defaultConfig.stages.plan!.documents.find((d) => d.name === "design"); - expect(designDoc!.template).toBeTruthy(); - expect(designDoc!.template).toContain("设计文档"); + it("每个 plan 文档都有 prompt 和 template", () => { + const docs = defaultConfig.stages.plan!.documents; + for (const doc of docs) { + expect(doc.prompt).toBeTruthy(); + expect(doc.template).toBeTruthy(); + } }); it("task 阶段有 prompt", () => { diff --git a/tests/integration/flow.test.ts b/tests/integration/flow.test.ts index 2f1084b..82dac69 100644 --- a/tests/integration/flow.test.ts +++ b/tests/integration/flow.test.ts @@ -39,7 +39,9 @@ describe("完整 SDD 流程", () => { expect(planPrompt).toContain("user-auth"); const changeDir = getChangeDir(TMP_DIR, changeName); + await writeFile(join(changeDir, "requirements.md"), "# 需求\n\n## 背景\n需要用户登录功能"); await writeFile(join(changeDir, "design.md"), "# 用户认证设计\n\n## 背景\n需要用户登录功能"); + await writeFile(join(changeDir, "plan.md"), "# 实现计划\n\n## 阶段 1: 实现登录"); const taskPrompt = await assembleTaskPrompt(config, TMP_DIR, changeName); expect(taskPrompt).toContain("user-auth"); @@ -138,14 +140,23 @@ describe("完整 SDD 流程", () => { const changeDir = getChangeDir(TMP_DIR, "dep-test"); await mkdir(changeDir, { recursive: true }); + await writeFile(join(changeDir, "requirements.md"), "# 需求"); await writeFile(join(changeDir, "design.md"), "# 设计文档"); const changes = await scanChanges(TMP_DIR, config); expect(changes).toHaveLength(1); + const requirementsDoc = changes[0].documents.find((d) => d.name === "requirements"); + expect(requirementsDoc).toBeDefined(); + expect(requirementsDoc!.completed).toBe(true); + const designDoc = changes[0].documents.find((d) => d.name === "design"); expect(designDoc).toBeDefined(); expect(designDoc!.completed).toBe(true); + + const planDoc = changes[0].documents.find((d) => d.name === "plan"); + expect(planDoc).toBeDefined(); + expect(planDoc!.completed).toBe(false); }); });