From 0ab24dee8e5ab20745cb7127e35f512913bb5a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?AI=E4=B8=8D=E6=AD=A2=E8=AF=AD?= <12096460+jnMetaCode@users.noreply.github.com> Date: Fri, 7 Aug 2026 22:29:04 +0800 Subject: [PATCH] =?UTF-8?q?feat(sdd):=20=E5=90=8C=E6=AD=A5=E4=B8=8A?= =?UTF-8?q?=E6=B8=B8=20v6.2.0=20=E2=80=94=E2=80=94=20plan=20=E4=BD=9C?= =?UTF-8?q?=E7=94=A8=E5=9F=9F=E5=B7=A5=E4=BD=9C=E5=8C=BA=20+=20=E5=9F=BA?= =?UTF-8?q?=E4=BA=8E=E5=94=A4=E5=9B=9E=E7=9A=84=E4=BF=AE=E5=A4=8D=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF=EF=BC=88#19=20A=20=E5=9D=97=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 对齐上游 v6.1.1 -> v6.2.0 中 subagent-driven-development 的 6 个 commit (6df8ba1 / b8a2d84 / 2dbbaed / 87e4050 / ebdd4ec / 28882fc)。 这是 #19 拆分后的 A 块。注意 v1.7.1 刚对齐过 SDD,本次是那之后的新增量。 ## 为什么必须整块一起改 我们的 SKILL.md 里写的是旧脚本签名(review-package BASE HEAD)。脚本换成 plan 作用域签名后若不同步改文档,agent 会照旧签名调用直接吃 usage 错误 —— 比不同步更糟。所以脚本 + 文档 + 模板同批落地。 ## plan 作用域工作区(结构性修复) 原先所有计划共用 .superpowers/sdd/ 一个目录,一份过期账本被误读成当前进度, 会让控制者跳过整段任务序列 —— 上游称这是观察到的最昂贵失败。现在每个计划 一个 .superpowers/sdd/<计划文件名>/,从结构上消除这种误读。 - scripts/sdd-workspace 改为接收 PLAN_FILE,自忽略 .gitignore 上移到 .superpowers/sdd/;scripts/review-package 前置 PLAN_FILE 参数 - 两个脚本在我们这边与上游 v6.1.1 字节一致(从未汉化),直接取上游版 - scripts/task-brief 只手工应用上游那两处改动,保留我们的 fork 适配 (awk 同时匹配 "Task N" 与 "任务 N",因为本仓库 writing-plans 产出中文标题) - 账本新增身份行 `# SDD ledger — plan: <路径>`,并明确「第一行点名别的计划、 或旧扁平路径下的游离账本」都不是你的进度 实测(临时 git 仓库):两个计划各得独立目录;往 A 计划写 ledger 后 B 计划 目录仍为空(关键回归);.gitignore 落在 .superpowers/sdd/ 且 git status 干净; 中文「任务 2」经新路径抽取成功;review-package 旧签名正确报 usage 错误。 ## SKILL.md 全面重写(14 章 -> 生命周期结构) 上游把平铺的 14 节重组为「任务循环」五步 + 熔断机制,Red Flags / Advantages / Integration / File Handoffs / Durable Progress 等并入使用现场。逐节重译: - 修复循环:一轮 = 一次修复分派 + 一次定向复审,每任务上限五轮 第 1-3 轮唤回原实现者(context 完整),第 4-5 轮换全新实现者 + 高一档模型 - 熔断:第 5 轮仍有未解决发现则停止分派,逐条裁定 —— 搁置(附裁定)或在 承重项上 BLOCKED。只在上限处裁定,提早裁定等于换名字的预先定性 - Minor 发现与「计划要求的」发现两条路在循环外 - 新增「常见的合理化借口」表取代原「红线」清单 新增 re-review-prompt.md(106 行全文翻译):定向复审只核实发现是否解决 + 只看修复 diff 的新破坏,范围外观察进账本不延长循环。 implementer-prompt.md「审查发现之后」改写为基于唤回的修复轮次; task-reviewer-prompt.md 更新脚本签名并删除被 re-review-prompt.md 取代的结尾两句。 ## 顺手修掉一个既有缺陷 三个 SDD 文件末尾都残留着 `` —— v1.7.1 那次重写(PR #108, d7885ca) 留下的生成产物,上游没有。这些文件会整体进 agent 的 prompt,属于污染。已全部清除, 并全仓扫描确认无同类残留。 ## 验证 - 章节结构与上游 14 节一一对应;superpowers: 引用集与上游完全一致 - 26 项关键技术记号(脚本签名、账本行格式、四种状态、ADDRESSED/NOT ADDRESSED、 数值门槛)逐一确认存在,无漏译 - 两个 dot 图节点/边数与上游精确一致(6/6 与 23/28),且无幽灵节点、无孤立节点 (手工翻译 dot 标签最易在边里写错,会静默产生幽灵节点) - audit.sh 150 pass / 0 fail;verify-release.sh 82 pass / 0 fail - SDD 已从 audit 的上游漂移警告里消失(结构层级现已对齐) 注:audit PASS 由 153 降至 150,是上游有意删除 Integration 一节 (原列 executing-plans / test-driven-development / writing-plans 三个引用) 导致 Category 4b 少 3 项引用检查,非静默跳过 —— 已核对我们的引用集与上游一致。 --- skills/subagent-driven-development/SKILL.md | 453 +++++++++--------- .../implementer-prompt.md | 9 +- .../re-review-prompt.md | 100 ++++ .../scripts/review-package | 20 +- .../scripts/sdd-workspace | 34 +- .../scripts/task-brief | 7 +- .../task-reviewer-prompt.md | 6 +- 7 files changed, 382 insertions(+), 247 deletions(-) create mode 100644 skills/subagent-driven-development/re-review-prompt.md diff --git a/skills/subagent-driven-development/SKILL.md b/skills/subagent-driven-development/SKILL.md index c54d654..e270f3f 100644 --- a/skills/subagent-driven-development/SKILL.md +++ b/skills/subagent-driven-development/SKILL.md @@ -55,270 +55,287 @@ digraph process { subgraph cluster_per_task { label="每个任务"; "分派实现子智能体 (./implementer-prompt.md)" [shape=box]; - "实现子智能体有疑问?" [shape=diamond]; + "实现者有疑问?" [shape=diamond]; "回答问题,提供上下文" [shape=box]; - "实现子智能体实现、测试、提交、自审" [shape=box]; - "写出 diff 文件,分派任务审查子智能体 (./task-reviewer-prompt.md)" [shape=box]; - "任务审查者报告规格 ✅ 且质量通过?" [shape=diamond]; - "针对 关键/重要 问题分派修复子智能体" [shape=box]; - "在待办列表和进度账本中标记任务完成" [shape=box]; + "实现者实现、测试、提交、自审" [shape=box]; + "生成审查包,分派任务审查者 (./task-reviewer-prompt.md)" [shape=box]; + "规格 ✅ 且质量通过?" [shape=diamond]; + "发现与计划原文冲突?" [shape=diamond]; + "询问人类伙伴以哪个为准" [shape=box]; + "第 R/5 轮修复: R≤3 唤回原实现者; R≥4 换全新实现者 + 更强模型" [shape=box]; + "分派定向复审 (./re-review-prompt.md)" [shape=box]; + "所有发现都已解决?" [shape=diamond]; + "R = 5?" [shape=diamond]; + "逐条裁定未解决的发现" [shape=box]; + "存在承重的发现?" [shape=diamond]; + "停止: 向人类伙伴报告 BLOCKED" [shape=box]; + "把发现连同裁定搁置进账本" [shape=box]; + "往账本追加完成行,标记待办完成" [shape=box]; } - "读取计划,记录上下文和全局约束,创建待办" [shape=box]; - "还有剩余任务?" [shape=diamond]; - "分派最终代码审查子智能体 (../requesting-code-review/code-reviewer.md)" [shape=box]; + "准备: 工作树、查账本、读计划、起飞前审查" [shape=box]; + "还有任务?" [shape=diamond]; + "分派最终代码审查者 (../requesting-code-review/code-reviewer.md)" [shape=box]; + "最终审查有发现? 一次修复分派、一次定向复审、裁定残留项" [shape=box]; + "最终审查干净: 删除本计划的工作区" [shape=box]; "使用 superpowers:finishing-a-development-branch" [shape=box style=filled fillcolor=lightgreen]; - "读取计划,记录上下文和全局约束,创建待办" -> "分派实现子智能体 (./implementer-prompt.md)"; - "分派实现子智能体 (./implementer-prompt.md)" -> "实现子智能体有疑问?"; - "实现子智能体有疑问?" -> "回答问题,提供上下文" [label="是"]; - "回答问题,提供上下文" -> "分派实现子智能体 (./implementer-prompt.md)"; - "实现子智能体有疑问?" -> "实现子智能体实现、测试、提交、自审" [label="否"]; - "实现子智能体实现、测试、提交、自审" -> "写出 diff 文件,分派任务审查子智能体 (./task-reviewer-prompt.md)"; - "写出 diff 文件,分派任务审查子智能体 (./task-reviewer-prompt.md)" -> "任务审查者报告规格 ✅ 且质量通过?"; - "任务审查者报告规格 ✅ 且质量通过?" -> "针对 关键/重要 问题分派修复子智能体" [label="否"]; - "针对 关键/重要 问题分派修复子智能体" -> "写出 diff 文件,分派任务审查子智能体 (./task-reviewer-prompt.md)" [label="重新审查"]; - "任务审查者报告规格 ✅ 且质量通过?" -> "在待办列表和进度账本中标记任务完成" [label="是"]; - "在待办列表和进度账本中标记任务完成" -> "还有剩余任务?"; - "还有剩余任务?" -> "分派实现子智能体 (./implementer-prompt.md)" [label="是"]; - "还有剩余任务?" -> "分派最终代码审查子智能体 (../requesting-code-review/code-reviewer.md)" [label="否"]; - "分派最终代码审查子智能体 (../requesting-code-review/code-reviewer.md)" -> "使用 superpowers:finishing-a-development-branch"; + "准备: 工作树、查账本、读计划、起飞前审查" -> "分派实现子智能体 (./implementer-prompt.md)"; + "分派实现子智能体 (./implementer-prompt.md)" -> "实现者有疑问?"; + "实现者有疑问?" -> "回答问题,提供上下文" [label="是"]; + "回答问题,提供上下文" -> "实现者实现、测试、提交、自审"; + "实现者有疑问?" -> "实现者实现、测试、提交、自审" [label="否"]; + "实现者实现、测试、提交、自审" -> "生成审查包,分派任务审查者 (./task-reviewer-prompt.md)"; + "生成审查包,分派任务审查者 (./task-reviewer-prompt.md)" -> "规格 ✅ 且质量通过?"; + "规格 ✅ 且质量通过?" -> "往账本追加完成行,标记待办完成" [label="是"]; + "规格 ✅ 且质量通过?" -> "发现与计划原文冲突?" [label="否"]; + "发现与计划原文冲突?" -> "询问人类伙伴以哪个为准" [label="是"]; + "询问人类伙伴以哪个为准" -> "第 R/5 轮修复: R≤3 唤回原实现者; R≥4 换全新实现者 + 更强模型"; + "发现与计划原文冲突?" -> "第 R/5 轮修复: R≤3 唤回原实现者; R≥4 换全新实现者 + 更强模型" [label="否"]; + "第 R/5 轮修复: R≤3 唤回原实现者; R≥4 换全新实现者 + 更强模型" -> "分派定向复审 (./re-review-prompt.md)"; + "分派定向复审 (./re-review-prompt.md)" -> "所有发现都已解决?"; + "所有发现都已解决?" -> "往账本追加完成行,标记待办完成" [label="是"]; + "所有发现都已解决?" -> "R = 5?" [label="否"]; + "R = 5?" -> "第 R/5 轮修复: R≤3 唤回原实现者; R≥4 换全新实现者 + 更强模型" [label="否 - 进入下一轮"]; + "R = 5?" -> "逐条裁定未解决的发现" [label="是 - 熔断触发"]; + "逐条裁定未解决的发现" -> "存在承重的发现?"; + "存在承重的发现?" -> "停止: 向人类伙伴报告 BLOCKED" [label="是"]; + "存在承重的发现?" -> "把发现连同裁定搁置进账本" [label="否"]; + "把发现连同裁定搁置进账本" -> "往账本追加完成行,标记待办完成"; + "往账本追加完成行,标记待办完成" -> "还有任务?"; + "还有任务?" -> "分派实现子智能体 (./implementer-prompt.md)" [label="是"]; + "还有任务?" -> "分派最终代码审查者 (../requesting-code-review/code-reviewer.md)" [label="否"]; + "分派最终代码审查者 (../requesting-code-review/code-reviewer.md)" -> "最终审查有发现? 一次修复分派、一次定向复审、裁定残留项"; + "最终审查有发现? 一次修复分派、一次定向复审、裁定残留项" -> "最终审查干净: 删除本计划的工作区"; + "最终审查干净: 删除本计划的工作区" -> "使用 superpowers:finishing-a-development-branch"; } ``` -## 起飞前的计划审查 +## 准备 -在分派任务 1 之前,先把计划整体扫一遍,找出冲突: - -- 相互矛盾、或与计划"全局约束"矛盾的任务 -- 计划明确要求、但审查评分标准会判定为缺陷的东西(一个什么都不断言的测试、逐字重复的逻辑块) - -把你发现的所有问题**打包成一个问题**呈给你的人类伙伴——每一处发现都紧挨着强制它的计划原文,问哪一方说了算——在执行开始之前一次性问清,而不是在计划执行途中每发现一处就打断一次。如果扫描下来很干净,就不作声、直接开始。审查循环仍然是那些只有在实现时才暴露出来的冲突的兜底网。 - -## 模型选择 - -在能胜任每个角色的前提下,使用最弱的模型,以节省成本、提高速度。 - -**机械性实现任务**(隔离的函数、清晰的规格、1-2 个文件):使用快速、便宜的模型。当计划编写得足够详细时,大多数实现任务都是机械性的。 - -**集成和判断类任务**(多文件协调、模式匹配、调试):使用标准模型。 - -**架构和设计类任务**:使用最强的可用模型。最终的整分支审查就属于这一类——用最强的可用模型来分派它,而不是会话默认模型。 - -**审查类任务**:用同样的判断力去选模型,并按 diff 的规模、复杂度和风险来缩放。一个小的机械性 diff 不需要最强的模型;一处微妙的并发改动才需要。 - -**分派子智能体时永远显式指定模型。** 省略模型会默默继承你会话的模型——往往是最强也最贵的那个——从而悄悄让本节的努力落空。 - -**轮次数比 token 单价更重要。** 墙钟时间和上下文成本随子智能体所用的轮次数增长,而最便宜的模型在多步工作上常常要多花 2-3 倍的轮次——总成本反而更高。给审查者、以及从散文式描述开工的实现者,用中档模型作为下限。当任务的计划文本已经包含要写的完整代码时,实现就是誊写加测试:那种实现者用最便宜的档位。单文件的机械性修复也用最便宜的档位。 - -**任务复杂度信号(实现任务):** -- 涉及 1-2 个文件且有完整规格 → 便宜模型 -- 涉及多个文件且有集成考虑 → 标准模型 -- 需要设计判断或广泛的代码库理解 → 最强模型 - -## 处理实现者状态 - -实现子智能体会报告四种状态之一。对每种状态做相应处理: - -**DONE:** 生成审查包(在本技能目录下运行 `scripts/review-package BASE HEAD`——它会打印出自己写入的那个唯一文件路径;BASE 是你在分派实现者之前记录下来的那个提交——**绝不用** `HEAD~1`,那会悄悄丢掉多提交任务里除最后一个之外的所有提交),然后把打印出的路径交给任务审查者去分派。 - -**DONE_WITH_CONCERNS:** 实现者完成了工作但标记了疑虑。在继续之前先读这些疑虑。如果疑虑涉及正确性或范围,在审查前先解决。如果只是观察性说明(例如"这个文件越来越大了"),记录下来并继续进入审查。 - -**NEEDS_CONTEXT:** 实现者需要未提供的信息。补上缺失的上下文并重新分派。 - -**BLOCKED:** 实现者无法完成任务。评估阻塞原因: -1. 如果是上下文问题,提供更多上下文并用同一模型重新分派 -2. 如果任务需要更强的推理能力,用更强的模型重新分派 -3. 如果任务太大,拆分为更小的部分 -4. 如果计划本身有问题,上报给人类 - -**绝不**忽略一次上报,也绝不在不做任何更改的情况下强迫同一模型重试。如果实现者说卡住了,那就说明有什么东西需要改变。 - -## 处理审查者的 ⚠️ 事项 - -任务审查者可能会报告"⚠️ 无法从 diff 中核实"的事项——那些藏在未改动代码里、或横跨多个任务的需求。这些事项不会阻塞审查的其余部分,但在标记任务完成之前你必须逐一亲自解决:你手里握着计划和跨任务上下文,而审查者没有。如果你确认某一项确实是真实的缺口,就把它当作一次未通过的规格审查处理——退回给实现者并重新审查。 - -## 构造审查者提示词 - -每个任务的审查都是任务范围内的关卡。宽范围审查只发生一次,在最终的整分支审查。当你填写审查者模板时: - -- 不要在没有具体、任务专属理由的情况下,加入"检查所有用法"或"如果有用就跑竞态测试"这类开放式指令 -- 不要让审查者去重跑实现者已经在同一份代码上跑过的测试——实现者的报告已经带着测试证据 -- 不要替审查者预判发现——绝不指示审查者去忽略或不上报某个具体问题。如果你认为某个发现会是误报,那就让审查者提出来,在审查循环里裁定它。如果你正在写的提示词里出现了"不要标记""别把 X 当缺陷""顶多算 Minor""计划选择了"——停下:你在预判,通常是为了省掉一轮审查。 -- 你交给审查者的全局约束块是它的注意力透镜。从计划的"全局约束"一节或规格里**逐字**抄下有约束力的需求:精确的取值、精确的格式、以及组件之间被明确规定的关系("与 X 相同的布局""匹配 Y")。审查者的模板里已经带着流程规则(YAGNI、测试卫生、审查方法)——约束块是留给**本项目**规格所要求的东西的。 -- 把 diff 作为文件交给审查者:运行本技能的 `scripts/review-package BASE HEAD`,把它打印出的文件路径交给审查者(若没有 bash:对该区间跑 `git log --oneline`、`git diff --stat`、`git diff -U10`,重定向到一个唯一命名的文件)。这些输出永远不会进入你自己的上下文,而审查者在一次 Read 调用里就能看到提交列表、stat 摘要和带上下文的完整 diff。用你在分派实现者之前记录下的 BASE——**绝不用** `HEAD~1`,那会悄悄截断多提交任务。 -- 一份分派提示词描述的是**一个任务**,不是会话的历史。不要把累积的前序任务小结("任务 1-3 之后的状态")粘进后续分派里——真实会话里有一次分派冲到了 42k 字符,其中 99% 是粘进去的历史。一个全新的子智能体需要的是:它的任务、它要接触的接口、以及全局约束。别的都不要。 -- 针对 关键 和 重要 的发现分派修复子智能体。把 次要 的发现随手记进进度账本,并让最终的整分支审查指向那份清单,让它去分诊哪些必须在合并前修掉。没人读的汇总等于悄悄丢弃。 -- 一个被标为"计划强制"的发现——或任何与计划文本要求相冲突的发现——是人类的决定,就像任何计划矛盾一样:把发现和计划原文一起呈上,问哪一方说了算。不要因为计划强制了它就驳回这个发现,也不要在不问的情况下分派一个与计划相冲突的修复。 -- 最终的整分支审查也拿到一个审查包:运行 `scripts/review-package MERGE_BASE HEAD`(MERGE_BASE = 分支起点的那个提交,例如 `git merge-base main HEAD`),把打印出的路径放进最终审查的分派里,这样最终审查者读一个文件就行,不必用 git 命令重新推导整个分支的 diff。 -- 每一次修复分派都带着实现者契约:修复子智能体重跑覆盖其改动的测试并报告结果。在分派里点名覆盖它的测试文件——一行的修复不需要整个测试套件。在重新分派审查者之前,确认修复报告里包含覆盖用的测试、跑的命令、以及输出;三者齐全后再分派重新审查。 -- 如果最终的整分支审查返回了发现,分派**一个**修复子智能体,带上完整的发现清单——不要一个发现配一个修复者。逐发现的修复者每个都要重建上下文、重跑测试套件;某次真实会话的最终审查修复浪潮,花的比它所有任务加起来还多。 - -## 文件交接 - -你粘进分派提示词里的一切、以及子智能体打印回来的一切,都会在会话余下的时间里常驻在你的上下文中,并在之后的每一个轮次被重新读取。把产物作为文件来交接: - -- **任务简报:** 分派实现者之前,运行本技能的 `scripts/task-brief PLAN_FILE N`——它把该任务的完整文本抽取到一个唯一命名的文件并打印路径。组织你的分派,让这份简报保持为需求的唯一来源。你的分派应包含:(1) 一行说明这个任务在项目中的位置;(2) 简报路径,引入语为"先读这个——它是你的需求,里面有要逐字使用的精确取值";(3) 简报无从知晓的、来自前序任务的接口和决策;(4) 你对简报中注意到的任何歧义的裁定;(5) 报告文件路径和报告契约。精确取值(数字、魔法字符串、签名、测试用例)只出现在简报里。 -- **报告文件:** 把实现者的报告文件按简报来命名(简报 `…/task-N-brief.md` → 报告 `…/task-N-report.md`),并写进分派提示词。实现者把完整报告写在那里,只返回状态、提交、一行测试小结和疑虑。 -- **审查者输入:** 任务审查者拿到三个路径——同一份简报文件、报告文件、以及审查包——外加约束该任务的全局约束。 -- 修复分派把它们的修复报告(连同测试结果)追加到同一个报告文件,并返回一句简短小结;重新审查读取更新后的文件。 - -## 持久化进度 +确保工作发生在一个隔离的工作区里:用 superpowers:using-git-worktrees 创建一个,或者核实已有的那个。没有你人类伙伴的明确同意,绝不在 main/master 分支上开始实现。 会话记忆无法在上下文压缩(compaction)中存活。在真实会话里,丢失了位置的控制者曾重新分派整段已经完成的任务序列——这是观察到的最昂贵的失败。把进度记在一个账本文件里,而不只是记在待办里。 -- 技能启动时,检查是否有账本: - `cat "$(git rev-parse --show-toplevel)/.superpowers/sdd/progress.md"`。在那里被列为完成的任务就是完成了——不要重新分派它们;从第一个未标记完成的任务处继续。 -- 当某个任务的审查干净地返回时,在你做其他记账的同一条消息里,往账本追加一行: - `Task N: complete (commits .., review clean)`。 +- **每个计划拥有自己的工作区:** 技能启动时,运行本技能的 `scripts/sdd-workspace PLAN_FILE`——它会打印这个计划专属的、被 git 忽略的目录(`/.superpowers/sdd/<计划文件名>/`),**本计划**的一切产物都放在那里:账本、简报、报告、审查包。别的计划的目录不属于你,不读也不写。 +- 到 `<工作区>/progress.md` 查本计划的账本。如果它的第一行点名的是你的计划文件,那么带有 `Task : complete` 行的任务就是**已完成**——不要重新分派它们;从第一个没有该行的任务处继续。如果某个任务的最后一行是一轮修复,说明它正卡在修复循环中:从下一轮继续。如果账本第一行点名的是**另一个**计划文件——或者你在旧的扁平路径 `.superpowers/sdd/progress.md` 发现了一个游离的账本——那是别人的进度:原地别动,另起你自己的新账本。 +- 创建账本时,把它的身份写在第一行:`# SDD ledger — plan: <计划文件路径>`。 - 这个账本是你的恢复地图:它点名的那些提交,即使你的上下文已经不记得创建过它们,也确实存在于 git 中。压缩之后,相信账本和 `git log`,而不是你自己的记忆。 -- `git clean -fdx` 会毁掉这个账本(它是被 git 忽略的临时文件);万一发生了,就从 `git log` 恢复。 +- `git clean -fdx` 会毁掉这个工作区(它是被 git 忽略的临时文件);万一发生了,就从 `git log` 恢复。 -## 提示词模板 +把计划**读一遍**,记下它的上下文和全局约束,并为每个任务建一条待办。 -- [implementer-prompt.md](implementer-prompt.md) - 分派实现子智能体 -- [task-reviewer-prompt.md](task-reviewer-prompt.md) - 分派任务审查子智能体(规格合规性 + 代码质量) -- 最终整分支审查:使用 superpowers:requesting-code-review 的 [code-reviewer.md](../requesting-code-review/code-reviewer.md) +在分派任务 1 之前,把计划通扫一遍找冲突: + +- 互相矛盾的任务,或与计划的"全局约束"矛盾的任务 +- 计划明确要求、但审查标准会判为缺陷的东西(比如一个什么都不断言的测试、一整块逻辑的逐字复制) + +把你找到的所有问题**一次性打包成一个问题**呈现给你的人类伙伴——每条发现都并列上要求它的那段计划原文,问以哪个为准——在执行开始之前问,而不是执行过程中每发现一个就打断一次。如果扫描是干净的,就不要多说,直接开始。审查循环仍然是那些只有在实现中才浮现的冲突的兜底网。 + +## 模型选择 + +在能胜任的前提下,为每个角色选用最弱的模型,以节省成本、提升速度。 + +**机械性实现任务**(孤立的函数、清晰的规格、1-2 个文件):用快而便宜的模型。计划写得好时,大多数实现任务都是机械性的。 + +**集成与判断类任务**(跨文件协调、模式匹配、调试):用标准模型。 + +**架构与设计类任务**:用可用的最强模型。覆盖整个分支的最终审查就属于这一类——用可用的最强模型去分派它,不要用会话默认模型。 + +**审查任务**:用同样的判断来选模型,并按 diff 的体量、复杂度和风险来缩放。一个小的机械性 diff 不需要最强模型;一个微妙的并发改动需要。小修复 diff 的定向复审用便宜到中档的层级即可。 + +**修复循环的升级(第 4-5 轮)**:用比那个卡住了的实现者**至少高一档**的模型。 + +**分派子智能体时永远显式指定模型。** 省略模型会继承你会话的模型——往往是最强也最贵的那个——这会悄无声息地让本节的努力全部失效。 + +**轮次数比 token 单价更要紧。** 墙钟时间和上下文成本是随子智能体花掉多少轮次而增长的,而最便宜的模型在多步工作上经常要花 2-3 倍轮次——总账反而更贵。审查者、以及依据散文式描述工作的实现者,都以中档模型为下限。当任务的计划原文里已经包含了要写的完整代码时,实现就是抄写加测试:这种实现者用最便宜的层级。单文件的机械性修复也用最便宜的层级。 + +**任务复杂度信号(实现类任务):** +- 涉及 1-2 个文件且规格完整 → 便宜模型 +- 涉及多个文件且有集成考量 → 标准模型 +- 需要设计判断或对代码库的广泛理解 → 最强模型 + +## 任务循环 + +你粘进分派提示词里的一切、以及子智能体打印回来的一切,都会在本次会话余下的时间里常驻你的上下文,并且在之后每一轮被重新读一遍。**产物要用文件来交接。** + +### 1. 分派实现者 + +分派之前记录 BASE(`git rev-parse HEAD`)——审查包和各轮修复的 diff 都要用它。 + +- **任务简报:** 分派实现者之前,运行本技能的 `scripts/task-brief PLAN_FILE N`——它把该任务的完整文本抽取到一个唯一命名的文件并打印路径。组织你的分派,让这份简报保持为需求的唯一来源。你的分派应包含:(1) 一行说明这个任务在项目中的位置;(2) 简报路径,引入语为"先读这个——它是你的需求,里面有要逐字使用的精确取值";(3) 简报无从知晓的、来自前序任务的接口和决策;(4) 你对简报中注意到的任何歧义的裁定;(5) 报告文件路径和报告契约。精确取值(数字、魔法字符串、签名、测试用例)只出现在简报里。**绝不**让子智能体去读整个计划文件。 +- **报告文件:** 实现者的报告文件按简报来命名(简报 `…/task-N-brief.md` → 报告 `…/task-N-report.md`),并写进分派提示词。实现者把完整报告写在那里,只回传状态、提交、一行测试小结和疑虑。 +- 一个分派提示词描述的是**一个任务**,不是会话的历史。不要把累积的前序任务小结("任务 1-3 之后的状态")粘进后面的分派——真实会话里曾出现过 42k 字符的分派,其中 99% 是粘贴的历史。一个全新的子智能体需要的是:它的任务、它要碰的接口、以及全局约束。别无其他。 +- 如果前面某个任务把一条发现搁置在本任务要碰的区域,就在分派里带上指向那条账本记录的指针。 +- **记下分派结果里实现者的智能体身份**——第 1-3 轮修复要唤回这个智能体。 +- 绝不并行分派多个实现子智能体(会冲突)。 + +模板:[implementer-prompt.md](implementer-prompt.md) + +### 2. 处理报告 + +实现子智能体会回传四种状态之一。分别处理: + +**DONE:** 生成审查包(在本技能目录下运行 `scripts/review-package PLAN_FILE BASE HEAD`——它会打印出自己写入的那个唯一文件路径;BASE 是你在分派实现者之前记录下来的那个提交——**绝不用** `HEAD~1`,那会悄悄丢掉多提交任务里除最后一个之外的所有提交),然后把打印出的路径交给任务审查者去分派。 + +**DONE_WITH_CONCERNS:** 实现者完成了工作但提出了疑虑。继续之前先读这些疑虑。如果疑虑关乎正确性或范围,在审查之前先处理掉。如果只是观察(比如"这个文件变大了"),记下来,继续走审查。 + +**NEEDS_CONTEXT:** 实现者需要没被提供的信息。补上缺失的上下文并重新分派。 + +**BLOCKED:** 实现者无法完成任务。评估这个阻塞: +1. 如果是上下文问题,补充上下文并用同一个模型重新分派 +2. 如果任务需要更多推理,用更强的模型重新分派 +3. 如果任务太大,拆成更小的块 +4. 如果是计划本身错了,上报给人类 + +**绝不**忽视一次上报,也**绝不**在什么都没改的情况下强迫同一个模型重试。如果实现者说它卡住了,那就一定有东西需要改变。 + +如果实现者提问——不论是开始前还是任务中途——清楚完整地回答,需要时补充上下文,不要催着它进入实现。 + +### 3. 审查任务 + +逐任务审查是**任务范围内的关卡**。宽范围审查只做一次,在最终的整分支审查那里。绝不跳过任务审查,也绝不接受一份缺少任一结论的报告——规格合规性**和**任务质量两者都必须有。实现者的自审永远不能替代任务审查;两者都需要。 + +- **把 diff 作为文件交给审查者:** 运行本技能的 `scripts/review-package PLAN_FILE BASE HEAD`,把它打印出的文件路径交给审查者(若没有 bash:对该区间跑 `git log --oneline`、`git diff --stat`、`git diff -U10`,重定向到一个唯一命名的文件)。这些输出永远不会进入你自己的上下文,而审查者在一次 Read 调用里就能看到提交列表、stat 摘要和带上下文的完整 diff。用你在分派实现者之前记录下的 BASE——**绝不用** `HEAD~1`,那会悄悄截断多提交任务。**绝不**在没有 diff 文件的情况下分派任务审查者。 +- **审查者的输入:** 任务审查者拿到三个路径——同一份简报文件、报告文件、审查包——外加约束该任务的全局约束。 +- 你交给审查者的全局约束块是它的**注意力透镜**。从计划的"全局约束"一节或规格里**逐字**抄下有约束力的需求:精确的取值、精确的格式,以及组件之间被明确规定的关系("与 X 相同的布局"、"匹配 Y")。审查者的模板里已经带了流程规则(YAGNI、测试卫生、审查方法)——约束块是用来装**这个项目**的规格所要求的东西的。 +- 不要在没有具体的、任务专属的理由时,加上"检查所有用法"或"有用的话跑一下竞态测试"这类开放式指令 +- 不要让审查者重跑实现者已经在同一份代码上跑过的测试——实现者的报告承载着测试证据 +- **不要替审查者预先给发现定性**——绝不指示审查者忽略或不要标记某个具体问题。如果你认为某条发现会是误报,让审查者提出来,然后在审查循环里裁定它。如果你正在写的提示词里出现了"不要标记"、"不要把 X 当缺陷"、"顶多按 Minor 处理"、"计划选择了"——停下:你正在预先定性,而且通常是为了让自己少走一轮审查循环。 + +任务审查者可能报告"⚠️ 无法从 diff 核实"的条目——那些活在未改动代码里、或者跨任务的需求。这些不阻塞审查的其余部分,但在标记任务完成之前**你必须自己逐条解决它们**:你掌握着审查者所缺的计划和跨任务上下文。如果你确认某一条是真实的缺口,就把它当作规格审查失败来处理——它和其他发现一起进入修复循环。 + +模板:[task-reviewer-prompt.md](task-reviewer-prompt.md) + +### 4. 修复循环 + +当审查报告规格 ❌、任何 Critical 或 Important 发现、或者你确认为真实缺口的 ⚠️ 条目时,循环触发。 + +循环开始之前,有两条路会立刻离开它: + +- **Minor 发现**随手记进进度账本(`Task : minor (deferred): <一句话>`),并把最终的整分支审查指向那份清单,让它去甄别哪些必须在合并前修掉。**没人读的汇总等于静默丢弃。** Minor 发现永远不进入循环。 +- 被标为"计划要求的"发现——或任何与计划原文所要求的内容冲突的发现——和任何计划矛盾一样,属于**人类的决定**:把这条发现和那段计划原文一起呈现,问以哪个为准。不要因为计划要求就驳回这条发现,也不要在没问过的情况下分派一个与计划相违的修复。 + +其他一切都进入循环。**一轮修复 = 一次修复分派 + 一次定向复审。每个任务最多五轮。** + +**第 1-3 轮——唤回原来那个实现者(resume)。** 把未解决的发现**逐字**发给它。它的上下文是完整的:它知道任务、知道代码、知道自己做过的选择。如果你的运行环境无法给一个活着的子智能体再发消息,就分派一个全新实现者,带上简报路径、报告文件路径和那些发现——无论走哪条路,报告文件都是那份持久化记忆。 + +**第 4-5 轮——用更强的模型分派一个全新实现者**(按"模型选择"),带上简报路径、报告文件路径、未解决的发现,以及这样的框定语:"某个此前的实现者尝试过这个任务 [N] 次;现在它归你了。读报告文件了解已经试过什么。"一个熬过三次唤回的循环,通常意味着实现者看不见自己的问题——换新眼睛加提升能力,一步到位。 + +**每一轮,无论走哪条路:** 实现者修复、重跑覆盖被改动代码的测试、把修复报告追加到**同一个**报告文件、回传那个简短契约。重新分派审查者之前,先确认修复报告里含有覆盖用的测试、跑过的命令、以及输出;三者齐备才分派复审。在修复消息里点名覆盖用的测试文件——一行的修复不需要整包套件。 + +**复审是定向的。** 运行 `scripts/review-package PLAN_FILE FIX_BASE HEAD`,其中 FIX_BASE 是上一次审查所看到的那个 head,然后用 [re-review-prompt.md](re-review-prompt.md) 分派,附上发现清单、简报、报告文件和打印出的 diff 路径。复审者对每条发现给出 ADDRESSED 或 NOT ADDRESSED 的结论,并且**只**标记修复 diff 里的新破坏。修复 diff 里新出现的 Critical/Important 破坏加入未解决发现清单。范围外的观察作为延后的 Minor 进账本——它们永远不延长循环。 + +**每轮结束后**往账本追加: +`Task : fix round /5 ( addressed, open — <发现的一句话概括>; commits ..)` + +**绝不在控制者会话里自己修发现**——你的上下文要保持干净以供协调,而且控制者的修复会跳过审查。 + +**熔断。** 当第 5 轮的复审仍然留下未解决的发现时,**停止分派**。你自己逐条裁定这些未解决的发现——你掌握着审查者所缺的计划和跨任务上下文: + +- **审查者错了,或者这一点是可争议的:** 搁置它——`Task : parked — <发现> — ruling: <为什么代码可以维持原样>`。最终审查会看到双方说法。 +- **是真实的,但下游没有任何东西建立在它之上:** 同样搁置,裁定里写明它是真的、被延后了。 +- **真实且承重**——后面的任务建立在它之上,或者它揭示了一个计划缺陷:**停止**。追加 `Task : BLOCKED — <原因>`,并连同这条发现、与之冲突的计划原文、以及修复历史一起报告给你的人类伙伴。把一个结构性失败搁置掉,会让每个依赖它的任务都建立在它之上,并且把一个最终审查同样无法修复的问题丢给最终审查。 + +**只在触及上限时才裁定。** 为了结束循环而提早裁定,只是换了个名字的"预先定性"。每一次裁定都是一条账本记录——**静默丢弃是禁止的**。 + +### 5. 完成任务 + +当审查干净地返回——或者在触及上限时每条未解决的发现都已带着裁定被搁置——在你做其他记账的同一条消息里,往账本追加完成行: + +- `Task : complete (commits .., review clean)` +- 熔断触发过的话:`Task : complete (commits .., parked)` + +然后标记待办完成,继续下一个。**绝不**在审查还有未解决的 Critical/Important 问题、而它们既没被修复也没在上限处带裁定搁置时,就进入下一个任务。 + +## 最终审查 + +覆盖整个分支的最终审查也拿到一个审查包:运行 `scripts/review-package PLAN_FILE MERGE_BASE HEAD`(MERGE_BASE = 分支起点的那个提交,例如 `git merge-base main HEAD`),把打印出的路径放进最终审查的分派里,这样最终审查者读一个文件就行,不必用 git 命令重新推导整个分支的 diff。用可用的最强模型分派(见"模型选择"),使用 superpowers:requesting-code-review 的 [code-reviewer.md](../requesting-code-review/code-reviewer.md)。把它指向账本里那些"延后的 Minor"和"已搁置"的行,让它甄别哪些必须在合并前修掉。 + +如果覆盖整个分支的最终审查返回了发现,用**一个**修复子智能体带着**完整的**发现清单去分派——不要一条发现一个修复者。逐条发现各派一个修复者,每个都要重建上下文、重跑测试套件;真实会话里,一次最终审查的修复浪潮花掉的成本超过它全部任务的总和。然后对这波修复跑**恰好一次**定向复审(对修复区间跑 `scripts/review-package PLAN_FILE FIX_BASE HEAD`,用 [re-review-prompt.md](re-review-prompt.md))。残留的发现按任务循环里熔断那套来裁定:带裁定搁置,或者在承重项上停下。**没有第二波修复**——残留的承重发现会在 finishing-a-development-branch 呈现选项时浮到你人类伙伴面前。 + +## 收尾 + +当覆盖整个分支的最终审查干净、且它的修复已合并时,删除**本计划**的工作区(`rm -rf <工作区>`)——现在 git 历史就是记录了。同级目录属于别的计划,别去动它们。 + +使用 superpowers:finishing-a-development-branch。 + +## 常见的合理化借口 + +| 借口 | 现实 | +|------|------| +| "规格合规性上差不多就行了" | 审查者发现了规格差距 = 未完成。修掉,或者走到上限去裁定——只有这两个出口。 | +| "我自己修就好了,分派是额外开销" | 控制者的修复会污染你的上下文并跳过审查。唤回实现者。 | +| "再来一轮就收敛了" | 过了上限,轮次不会收敛——那个失败是结构性的。裁定并分流。 | +| "反正审查者总会再挑出新东西" | 定向复审只核实修复,它不能到处乱逛。未改动代码上的新发现进账本,不进循环。 | +| "这条发现明显错了,我直接丢掉" | 你只在上限处裁定,而且每条裁定都是账本记录。静默丢弃是禁止的。 | +| "修复很小,跳过复审吧" | 未经审查的修复正是回归产生的方式。每一轮都以一次定向复审结束。 | +| "审查把循环拖慢了" | 没有审查的循环只是未经核实的空转。审查是这个循环的刹车和方向盘。 | +| "记账本是额外开销" | 账本是能在压缩中存活下来的东西。没有账本的控制者曾重新分派整段已完成的任务序列。 | ## 示例工作流 ``` -你:我正在使用子智能体驱动开发来执行这个计划。 +你:我正在用子智能体驱动开发来执行这个计划。 -[一次性读取计划文件:docs/superpowers/plans/feature-plan.md] +[准备:工作树已核实] +[把计划文件读一遍:docs/superpowers/plans/feature-plan.md] +[解析工作区:scripts/sdd-workspace docs/superpowers/plans/feature-plan.md —— 里面没有账本,全新开始] [为所有任务创建待办] 任务 1:Hook 安装脚本 [对任务 1 运行 task-brief;分派实现者,附带简报 + 报告路径 + 上下文] -实现者:"在我开始之前——hook 应该安装在用户级别还是系统级别?" +实现者:"开始之前——这个 hook 应该装在用户级还是系统级?" -你:"用户级别(~/.config/superpowers/hooks/)" +你:"用户级(~/.config/superpowers/hooks/)" -实现者:"明白了。现在开始实现……" -[稍后] 实现者: +实现者:[稍后] - 实现了 install-hook 命令 - - 添加了测试,5/5 通过 - - 自审:发现遗漏了 --force 参数,已添加 + - 加了测试,5/5 通过 + - 自审:发现漏了 --force 标志,已补上 - 已提交 -[运行 review-package,把打印出的路径交给任务审查者去分派] -任务审查者:规格 ✅ - 所有需求已满足,无多余内容。 - 优点:测试覆盖好,代码整洁。问题:无。任务质量:通过。 +[运行 review-package PLAN_FILE BASE HEAD;把打印出的路径交给任务审查者去分派] +任务审查者:规格 ✅ —— 所有需求都满足,没有多余的东西。 + 优点:测试覆盖良好,代码整洁。问题:无。任务质量:通过。 -[标记任务 1 完成] +[账本:Task 1: complete (commits a1b2c3d..d4e5f6a, review clean)] 任务 2:恢复模式 [对任务 2 运行 task-brief;分派实现者,附带简报 + 报告路径 + 上下文] -实现者:[无疑问,直接开始] -实现者: - - 添加了 verify/repair 模式 +实现者:[无疑问] + - 加了 verify/repair 模式 - 8/8 测试通过 - - 自审:一切正常 - 已提交 -[运行 review-package,把打印出的路径交给任务审查者去分派] +[运行 review-package PLAN_FILE BASE HEAD;把打印出的路径交给任务审查者去分派] 任务审查者:规格 ❌: - - 缺失:进度报告(规格要求"每 100 项报告一次") - - 多余:添加了 --json 参数(未被要求) - 问题(重要):魔法数字(100) + - 缺失:进度上报(规格说"每 100 项上报一次") + 问题(Important):魔法数字(100) -[分派修复子智能体,带上所有发现] -修复者:移除了 --json 参数,添加了进度报告,提取了 PROGRESS_INTERVAL 常量 +[第 1 轮修复:唤回原实现者,带上这两条发现] +实现者:加了进度上报,把 PROGRESS_INTERVAL 提成了常量。 + 重跑了 test/recovery.test.js —— 10/10 通过。修复报告已追加。 -[任务审查者再次审查] -任务审查者:规格 ✅。任务质量:通过。 +[运行 review-package PLAN_FILE FIX_BASE HEAD;分派定向复审] +复审者:缺失进度上报 —— ADDRESSED(src/recovery.js:41)。 + 魔法数字 —— ADDRESSED(src/recovery.js:7)。新破坏:无。 + 结论:所有发现均已解决。 -[标记任务 2 完成] +[账本:Task 2: fix round 1/5 (2 addressed, 0 open; commits d4e5f6a..b7c8d9e)] +[账本:Task 2: complete (commits d4e5f6a..b7c8d9e, review clean)] ... -[所有任务完成后] -[分派最终代码审查者] -最终审查者:所有需求已满足,可以合并 +[所有任务之后] +[运行 review-package PLAN_FILE MERGE_BASE HEAD;分派最终代码审查者,用最强模型] +最终审查者:所有需求都满足。延后的 Minor 已甄别:没有阻塞合并的。 -完成! +[删除本计划的工作区 —— 现在记录活在 git 里] + +搞定!使用 superpowers:finishing-a-development-branch。 ``` - -## 优势 - -**与手动执行相比:** -- 子智能体自然遵循 TDD -- 每个任务全新上下文(不会混淆) -- 并行安全(子智能体不会互相干扰) -- 子智能体可以提问(工作前和工作中都可以) - -**与 Executing Plans 相比:** -- 同一会话(无交接) -- 持续进展(无需等待) -- 审查检查点自动化 - -**效率提升:** -- 控制者精确策划所需的确切上下文;大块产物以文件而非粘贴文本的方式流动 -- 子智能体预先获得完整信息 -- 问题在工作开始前就被提出(而非工作结束后) - -**质量关卡:** -- 自审在交接前发现问题 -- 任务审查给出两个结论:规格合规性和代码质量 -- 审查循环确保修复确实有效 -- 规格合规防止过度/不足构建 -- 代码质量确保实现构建良好 - -**成本:** -- 更多子智能体调用(每个任务需要实现者 + 审查者) -- 控制者需要更多准备工作(预先抽取所有任务) -- 审查循环增加迭代次数 -- 但能及早发现问题(比后期调试更省成本) - -## 红线 - -**绝不:** -- 未经用户明确同意就在 main/master 分支上开始实现 -- 跳过任务审查,或接受一份缺少任一结论的报告(规格合规性 **和** 任务质量两者都必须有) -- 带着未修复的问题继续 -- 并行分派多个实现子智能体(会冲突) -- 让子智能体去读整个计划文件(改为给它任务简报——`scripts/task-brief`) -- 跳过场景铺设上下文(子智能体需要理解任务在哪个环节) -- 忽视子智能体的问题(在让它们继续之前先回答) -- 在规格合规性上接受"差不多就行"(审查者发现了规格问题 = 未完成) -- 跳过审查循环(审查者发现问题 = 实现者修复 = 再次审查) -- 让实现者的自审替代正式审查(两者都需要) -- 告诉审查者不要标记什么,或在分派提示词里预先给某个发现定级严重度("顶多按 Minor 处理")——计划里的示例代码是起点,不是它的弱点是被有意选择的证据 -- 在没有 diff 文件的情况下分派任务审查者——先生成它(`scripts/review-package BASE HEAD`),并在提示词里点名打印出的路径 -- 在审查还有未解决的 关键/重要 问题时就进入下一个任务 -- 重新分派一个进度账本已标记完成的任务——在任何压缩或恢复之后,都要查账本(和 `git log`) - -**如果子智能体提问:** -- 清晰完整地回答 -- 必要时提供额外上下文 -- 不要催促它们进入实现阶段 - -**如果审查者发现问题:** -- 实现者(同一子智能体)修复 -- 审查者再次审查 -- 重复直到通过 -- 不要跳过重新审查 - -**如果子智能体任务失败:** -- 分派修复子智能体并提供具体指令 -- 不要尝试手动修复(上下文污染) - -## 集成 - -**必需的工作流技能:** -- **superpowers:using-git-worktrees** - 确保隔离的工作区(创建一个,或核实已有的) -- **superpowers:writing-plans** - 创建本技能所执行的计划 -- **superpowers:requesting-code-review** - 用于最终整分支审查的代码审查模板 -- **superpowers:finishing-a-development-branch** - 所有任务完成后收尾 - -**子智能体应使用:** -- **superpowers:test-driven-development** - 子智能体对每个任务遵循 TDD - -**替代工作流:** -- **superpowers:executing-plans** - 用于并行会话而非同会话执行 - - diff --git a/skills/subagent-driven-development/implementer-prompt.md b/skills/subagent-driven-development/implementer-prompt.md index ed600ad..8b66d7e 100644 --- a/skills/subagent-driven-development/implementer-prompt.md +++ b/skills/subagent-driven-development/implementer-prompt.md @@ -106,9 +106,11 @@ Subagent (general-purpose): ## 审查发现之后 - 如果审查者发现了问题、你也修复了,就重跑覆盖被改动代码的测试, - 并把结果追加到你的报告文件里。审查者不会替你重跑测试—— - 你的报告就是测试证据。 + 如果任务审查发现了问题,你会被带着那些发现重新唤起(resume)。 + 修复它们,重跑覆盖被改动代码的测试,然后往你的报告文件里追加一份 + 修复报告:你改了什么、你跑了哪些覆盖用的测试、命令是什么、输出是什么。 + 审查者不会替你重跑测试——你的报告就是测试证据。然后用与第一份报告 + 相同的那个简短状态契约回复。 ## 报告格式 @@ -136,4 +138,3 @@ Subagent (general-purpose): 如果你无法完成任务,使用 BLOCKED。如果你需要未提供的信息, 使用 NEEDS_CONTEXT。绝不默默产出你不确定的工作。 ``` - diff --git a/skills/subagent-driven-development/re-review-prompt.md b/skills/subagent-driven-development/re-review-prompt.md new file mode 100644 index 0000000..835303f --- /dev/null +++ b/skills/subagent-driven-development/re-review-prompt.md @@ -0,0 +1,100 @@ +# 定向复审提示词模板 + +在一轮修复之后分派复审时使用此模板。复审者核实那些发现是否已被解决, +并检查修复 diff 有没有引入新的破坏。这**不是**一次全新审查——完整审查 +早已做过了。 + +**目的:** 核实上一次审查的每一条发现都已解决,且修复本身没有破坏任何东西。 + +``` +Subagent (general-purpose): + description: "复审任务 N 第 R 轮修复" + model: [模型 —— 必填:按 SKILL.md 的"模型选择"来选;省略模型会默默 + 继承会话里最贵的那个] + prompt: | + 你正在复审一个任务的一轮修复。之前的审查产生了一批发现, + 一个实现者已经尝试修复它们。你的工作是给每条发现下结论、 + 并检查这次修复的 diff——仅此而已。 + + ## 任务 + + 读取任务简报:[BRIEF_FILE] + + ## 待核实的发现 + + [FINDINGS] + + ## 修复 + + 读取实现者的报告(修复报告追加在文件末尾): + [REPORT_FILE] + + **修复基线:** [FIX_BASE_SHA](上一次审查所看到的那个 head) + **Head:** [HEAD_SHA] + **diff 文件:** [DIFF_FILE] + + 把 diff 文件一次读完——它包含修复的提交、stat 摘要,以及带上下文的 + 修复 diff。不要重新跑 git 命令。如果 diff 文件不存在,自己取 diff: + `git diff --stat [FIX_BASE_SHA]..[HEAD_SHA]` 和 + `git diff [FIX_BASE_SHA]..[HEAD_SHA]`。 + + 你的审查对这个 checkout 是只读的。不要以任何方式改动工作树、索引、 + HEAD 或分支状态。 + + ## 范围 + + 你的范围就是那份发现清单和这次修复的 diff。**每一条发现都要给结论。** + 检查修复 diff 里有没有修复本身引入的新问题。**不要**去复审这次修复 + 没有碰过的代码:如果你注意到一个完全在修复 diff 之外的问题, + 把它写进"范围外的观察"——它不阻塞本任务,也不会延长修复循环。 + 覆盖整个分支的宽范围审查会在所有任务完成后另行进行。 + + ## 测试 + + 实现者已经重跑了覆盖被改动代码的那些测试,并把结果追加到了报告文件里。 + 把报告当作**未经核实的声明**来对待:确认修复报告点名了覆盖用的测试 + 并给出了它们的输出,再拿这些声明去对照 diff 核验。不要为了确认它的报告 + 而重跑整个测试套件。只有当读代码引出了某个现有运行结果无法回答的 + 具体疑问时才跑测试——而且只跑一个聚焦的测试,绝不跑整包套件。 + + ## 输出格式 + + 你的最终消息就是报告本身:直接从第一条发现的结论开始。每一行都应该是 + 一个结论、一条带 file:line 的发现,或者一项你实际做过的检查—— + 不要开场白,不要过程旁白。 + + ### 各条发现的结论 + + 按"待核实的发现"里的顺序,逐条给出: + - **[发现的一句话概括]** —— ADDRESSED(已解决)| NOT ADDRESSED(未解决), + 附 file:line 证据。"尝试过了"不算已解决:那个具体缺陷必须已经不存在。 + + ### 修复 diff 里的新破坏 + + 修复本身破坏或引入的任何东西,附严重度(Critical/Important/Minor) + 和 file:line。干净就写"无"。 + + ### 范围外的观察 + + 你注意到的、完全位于修复 diff 之外的问题。不阻塞;控制者会把这些 + 记进账本留给最终审查。没有就写"无"。 + + ### 结论 + + **本轮修复:** [所有发现均已解决,无新的 Critical/Important 破坏 | + 仍有发现未解决] —— 把未解决的那些列出来。 +``` + +**占位符:** +- `[MODEL]` —— 必填:审查者模型,按 SKILL.md 的"模型选择"来选;小修复 diff + 的定向复审用便宜到中档的层级即可 +- `[BRIEF_FILE]` —— 任务简报文件(与实现者所依据的是同一个文件) +- `[FINDINGS]` —— 上一次审查里的 Critical/Important 发现和规格差距, + 逐字抄下来,每条一个 bullet +- `[REPORT_FILE]` —— 实现者的报告文件(修复报告追加在其末尾) +- `[FIX_BASE_SHA]` —— 上一次审查所看到的那个 head +- `[HEAD_SHA]` —— 当前提交 +- `[DIFF_FILE]` —— `scripts/review-package PLAN_FILE FIX_BASE HEAD` 打印出的那个路径 + +**复审者返回:** 逐条发现的结论(ADDRESSED / NOT ADDRESSED)、 +修复 diff 里的新破坏、范围外的观察,以及一个本轮结论。 diff --git a/skills/subagent-driven-development/scripts/review-package b/skills/subagent-driven-development/scripts/review-package index 33bb20f..31852e2 100755 --- a/skills/subagent-driven-development/scripts/review-package +++ b/skills/subagent-driven-development/scripts/review-package @@ -4,26 +4,28 @@ # call. Using the recorded per-task BASE (not HEAD~1) keeps multi-commit # tasks intact. # -# Usage: review-package BASE HEAD [OUTFILE] -# Default OUTFILE: /.superpowers/sdd/review-...diff +# Usage: review-package PLAN_FILE BASE HEAD [OUTFILE] +# Default OUTFILE: /.superpowers/sdd//review-...diff # (named per range, so a re-review after fixes gets a distinct fresh file). set -euo pipefail -if [ $# -lt 2 ] || [ $# -gt 3 ]; then - echo "usage: review-package BASE HEAD [OUTFILE]" >&2 +if [ $# -lt 3 ] || [ $# -gt 4 ]; then + echo "usage: review-package PLAN_FILE BASE HEAD [OUTFILE]" >&2 exit 2 fi -base=$1 -head=$2 +plan=$1 +base=$2 +head=$3 +[ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; } git rev-parse --verify --quiet "$base" >/dev/null || { echo "bad BASE: $base" >&2; exit 2; } git rev-parse --verify --quiet "$head" >/dev/null || { echo "bad HEAD: $head" >&2; exit 2; } -if [ $# -eq 3 ]; then - out=$3 +if [ $# -eq 4 ]; then + out=$4 else - dir=$("$(cd "$(dirname "$0")" && pwd)/sdd-workspace") + dir=$("$(cd "$(dirname "$0")" && pwd)/sdd-workspace" "$plan") out="$dir/review-$(git rev-parse --short "$base")..$(git rev-parse --short "$head").diff" fi diff --git a/skills/subagent-driven-development/scripts/sdd-workspace b/skills/subagent-driven-development/scripts/sdd-workspace index ea9bb08..4e2d168 100755 --- a/skills/subagent-driven-development/scripts/sdd-workspace +++ b/skills/subagent-driven-development/scripts/sdd-workspace @@ -1,22 +1,40 @@ #!/usr/bin/env bash -# Resolve and ensure the working-tree directory SDD uses for its short-lived -# artifacts: task briefs, implementer reports, review packages, and the -# progress ledger. Print the directory's absolute path. +# Resolve and ensure the working-tree directory SDD uses for one plan's +# short-lived artifacts: task briefs, implementer reports, review packages, +# and the progress ledger. Print the plan directory's absolute path. +# +# One directory per plan (.superpowers/sdd//) so a follow-up +# plan in the same working tree can never read or overwrite another plan's +# artifacts. A stale ledger misread as current progress makes controllers +# skip whole task sequences — plan-scoping removes that failure structurally. # # The workspace lives in the working tree (not under .git/) because Claude Code # treats .git/ as a protected path and denies agent writes there — which blocks # an implementer subagent from writing its report file. A self-ignoring -# .gitignore keeps the workspace out of `git status` and out of accidental -# commits without modifying any tracked file. +# .gitignore at .superpowers/sdd/ keeps every plan's workspace out of +# `git status` and out of accidental commits without modifying any tracked file. # # Single source of truth for the workspace location, so task-brief and # review-package cannot drift to different directories. # -# Usage: sdd-workspace +# Usage: sdd-workspace PLAN_FILE set -euo pipefail +if [ $# -ne 1 ]; then + echo "usage: sdd-workspace PLAN_FILE" >&2 + exit 2 +fi + +plan=$1 +[ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; } + +slug=$(basename "$plan" .md) +[ -n "$slug" ] && [ "$slug" != "." ] && [ "$slug" != ".." ] \ + || { echo "cannot derive a workspace name from: $plan" >&2; exit 2; } + root=$(git rev-parse --show-toplevel) -dir="$root/.superpowers/sdd" +base="$root/.superpowers/sdd" +dir="$base/$slug" mkdir -p "$dir" -printf '*\n' > "$dir/.gitignore" +printf '*\n' > "$base/.gitignore" cd "$dir" && pwd diff --git a/skills/subagent-driven-development/scripts/task-brief b/skills/subagent-driven-development/scripts/task-brief index 879ba35..9df9346 100755 --- a/skills/subagent-driven-development/scripts/task-brief +++ b/skills/subagent-driven-development/scripts/task-brief @@ -4,8 +4,9 @@ # through the controller's context. # # Usage: task-brief PLAN_FILE TASK_NUMBER [OUTFILE] -# Default OUTFILE: /.superpowers/sdd/task--brief.md -# (per worktree; concurrent runs in the same working tree share it). +# Default OUTFILE: /.superpowers/sdd//task--brief.md +# (per plan and per worktree; concurrent runs of the SAME plan in the same +# working tree share it). # # 中文 fork 适配:上游只识别英文任务标题 "## Task N",而 superpowers-zh # 的 writing-plans 产出的是 "### 任务 N:..."。下方 awk 同时匹配 @@ -24,7 +25,7 @@ n=$2 if [ $# -eq 3 ]; then out=$3 else - dir=$("$(cd "$(dirname "$0")" && pwd)/sdd-workspace") + dir=$("$(cd "$(dirname "$0")" && pwd)/sdd-workspace" "$plan") out="$dir/task-${n}-brief.md" fi diff --git a/skills/subagent-driven-development/task-reviewer-prompt.md b/skills/subagent-driven-development/task-reviewer-prompt.md index 02d51c0..c42a786 100644 --- a/skills/subagent-driven-development/task-reviewer-prompt.md +++ b/skills/subagent-driven-development/task-reviewer-prompt.md @@ -158,12 +158,8 @@ Subagent (general-purpose): - `[BASE_SHA]` —— 本任务之前的提交 - `[HEAD_SHA]` —— 当前提交 - `[DIFF_FILE]` —— 必填:控制者写入审查包的那个路径 - (`scripts/review-package BASE HEAD` 会打印它写入的唯一路径; + (`scripts/review-package PLAN_FILE BASE HEAD` 会打印它写入的唯一路径; 审查包永远不会进入控制者的上下文) **审查者返回:** 规格合规性结论(✅/❌/⚠️)、优点、问题 (关键/重要/次要)、任务质量结论 - -一次修复分派可以同时处理规格差距和质量发现;修复后的重新审查 -覆盖两个结论。 -