首页
/ Superpowers SDD 修复循环重构设计:让子代理驱动的评审-修复循环收敛且自主

Superpowers SDD 修复循环重构设计:让子代理驱动的评审-修复循环收敛且自主

2026-09-06 11:58:34作者:滑思眉Philip

本文基于 superpowers 仓库的设计规范 2026-07-15-sdd-fix-loop-redesign-design.md,系统讲解 subagent-driven-development(SDD)技能"评审-修复循环"的完整重构设计:如何用"resume 原实现者 + 范围限定的再评审 + 五轮断路器 + 控制器仲裁"四个机制,把原本无上限、可能无限打转的修复循环改造为结构性收敛且可自主执行的流程,并同步重构 SKILL.md 文档结构。读完后,你可以理解这套修复循环每一轮的精确规则(触发条件、轮次预算、再评审范围、仲裁路由),也能对照仓库中已落地的 SKILL.mdre-review-prompt.md 与配套脚本,在自己的 Agent 工作流中复刻同类的"收敛式评审-修复闭环"。

背景:SDD 评审-修复循环的四个真实问题

SDD 技能的工作方式是:每任务派发一个全新的实现者子代理,任务完成后派发一次任务评审(规格符合度 + 代码质量),全部任务完成后再做一次全分支终审。设计规范指出,旧版修复循环的循环体在字面上就是 "Repeat until approved"——没有轮次上限,且每轮再评审都是对完整 diff 的全量评审。设计文档记录了在真实会话中观察到的四个问题,它们是整个重构的出发点:

  1. 病理性评审循环。由于每次再评审都是一次全新的全量评审,非确定性的前沿评审模型每一轮都会提出新发现,而不是验证既有问题是否已修复。结果形成 implement → review → fix → review → review → fix → review → fix 的无限打转,没有任何断路器。此前 strict-cost 设计规范 独立测量过:评审循环次数是运行间成本方差的最大来源。
  2. 相互矛盾的修复政策。同一个技能里对"谁来修?"给出了三个答案:流程图与 "Constructing Reviewer Prompts" 小节要求派发专门的 fix 子代理;Red Flags 小节写 "Implementer (same subagent) fixes them";而 implementer-prompt.md 的 "After Review Findings" 一节又假定实现者会被重新唤起。
  3. 累赘的文档结构。旧 SKILL.md 有十三个顶层小节,同一活动的指导散落在其中四个;"Constructing Reviewer Prompts" 成了一个杂物筐,同时装着评审者指导、修复政策、终审政策和计划冲突仲裁。
  4. Red Flags 格式不一致。其余七个同级技能使用 | Excuse | Reality | 理性化对照表,唯独 SDD 使用 17 条 "Never" 清单加三个 "If X" 小段落。

六项设计决策

设计文档以表格形式给出了六项核心决策及其理由,这六条是整个方案的骨架:

# 决策 理由
1 由原实现者修复自己的评审发现——就地 resume 它 它已经持有任务上下文;所有权胜过"路过的修理工"。全新的 "fix 子代理"要为每个发现重建上下文,且缺乏任务框架
2 再评审范围限定到具体发现(scoped re-review) 每轮全新的全量评审正是循环打转的发动机。范围限定的再评审让循环结构性收敛;最终的全分支评审仍是宽幅安全网
3 五轮修复断路器:先 resume 三次,再在更强模型上新派发两次 一次能扛过三次 resume 的循环,通常意味着实现者看不到自己的问题——全新派发同时完成"去锚定"与"能力升档"
4 断路器触发后由控制器仲裁并路由,不新增人工检查点;结构性失败走既有的 BLOCKED 停止条件 SDD 的卖点是自主执行。控制器持有计划与跨任务上下文,这些正是评审者所缺的;既有文本早已授权控制器 "adjudicate it in the review loop",只是从未规定机制
5 按生命周期重组 SKILL.md,保留 eval 调优过的句子 从根上解决"难以遵循"。内容移动到其使用点,与仓库近期提交的方向一致(把 recap 小节折叠进使用点)
6 Red Flags 转换为 ` Excuse

其中第 1 条是全文最重要的机制转变:修复不再是一个独立角色,而是把原实现者"叫醒"继续干。第 2 条把"验证修复"与"重新评审"拆成了两个不同契约——这是循环能够收敛的关键。第 3、4 条则回答了"修不好怎么办":不再依赖人工介入,而是让持有完整上下文的控制器做有据可查的仲裁。

修复循环:每一轮的精确规则

触发条件与轮次划分

循环的触发条件:任务评审返回 spec ❌,或出现任何 Critical/Important 级别发现。

第 1–3 轮:resume 原实现者。 将发现逐字(原文)发送给它——Critical/Important 发现加上规格缺口。实现者修复、重跑覆盖性测试,把修复报告追加到已有的报告文件中,并返回简短状态契约。对于不支持 agent resume 的 harness,"resume" 等价于一次携带 brief、报告文件路径和发现清单的全新派发——无论哪种实现,报告文件都是持久记忆。仓库中 implementer-prompt.md 的 "After Review Findings" 一节正是按 resume 语义重写的:

If the task review finds issues, you will be resumed with the findings.
Fix them, re-run the tests that cover the amended code, and append a fix
report to your report file: what you changed, the covering tests you
ran, the command, and the output. Reviewers will not re-run tests for
you — your report is the test evidence. Then reply with the same short
status contract as your first report.

第 4–5 轮:全新实现者 + 更强模型。 携带完整任务上下文:brief、报告文件、未关闭发现,以及一句接管框架——"a prior implementer attempted this N times; you own the task now"。设计文档的理由很直白:扛过三次 resume 的循环,通常意味着原实现者看不到自己的问题,全新派发一举完成"去锚定 + 能力升档"。

每一轮的再评审都是范围限定的。 再评审者收到四样东西:brief、更新后的报告、原始发现清单,以及一个修复范围的 diff 包——即 review-package FIX_BASE HEAD,其中 FIX_BASE 是上一位评审者最后看到的 head。仓库中的 scripts/review-package 本身就接受任意 commit 区间(生成 commit 列表、git diff --stat 和带 -U10 上下文的完整 diff,写出到按区间命名的文件),因此修复轮次的增量 diff 无需任何脚本改动即可支持。再评审者对每个发现给出 addressed / not addressed 判定,只检查修复 diff 中引入的新破坏;落在修复未触及代码上的新发现以非阻塞方式上报,由控制器记入台账留待终审。

完整性门禁与"不早退"

修复报告完整性门禁(既有规则,保留): 派发再评审之前,必须确认修复报告中写明了覆盖性测试、执行的命令、输出三要素,齐备才能派再评审。这一条堵住了"嘴上说修好了"的空洞修复报告。

不早退(no early exit): 控制器绝不能在到达轮次上限之前进行仲裁——提前仲裁会重新打开"预判决发现、省掉一轮评审"的口子,而这正是旧版内容刻意封堵的行为。唯一例外(与现状一致):与计划文本相冲突的发现立即上交给人类——这是计划权威问题,不是循环打转问题。

Minor 发现绝不进入循环: 按既有规则,随到随记入台账(Task <N>: minor (deferred): <one-liner>),指向终审去分诊。

断路器触发时的仲裁

第五轮失败后,控制器停止派发,对每个未关闭发现基于 brief、计划与跨任务上下文做判定,分三种路由:

  • 有争议或评审者错了 → 记入台账并附一行仲裁结论("controller: reviewer wrong because X"),继续执行。终审会同时看到双方立场。
  • 真实但不承重 → 记为 known-open,继续执行。后续触及该区域的派发会携带指向该台账条目的指针。
  • 真实且承重——后续任务建立在它之上,或它暴露了计划缺陷 → 触发既有的 BLOCKED 停止条件。"停放并继续(park-and-continue)"会把结构性失败推迟到成本最高的时点,还让依赖任务建立在它上面——因此结构性失败必须停下,走的是已经存在的停止条件,而不是新增检查点。

每一条仲裁都必须成为台账条目,静默丢弃被禁止。

文档重构:按生命周期重组,句子只搬不改

设计文档给出的新骨架严格按执行顺序排列,共 10 节:

  1. Intro——为什么用子代理、核心原则、旁白、连续执行
  2. When to Use——保持不变,含决策图
  3. The Process——流程图按新循环重绘
  4. Setup——worktree、台账检查/恢复、派发前计划审查、todos
  5. Model Selection——保持单一横切小节;每次派发都要参考它,折叠进各使用点会重复五遍
  6. The Task Loop——五个编号步骤:派发实现者(task-brief 脚本、五要素派发组合、模型行必填)→ 处理报告(DONE / DONE_WITH_CONCERNS / NEEDS_CONTEXT / BLOCKED)→ 评审任务(review-package 脚本、评审者派发组合、约束透镜、禁止预判、⚠️ 处理)→ 修复循环(上述机制)→ 完成任务(追加台账、更新 todo)
  7. Final Review——包、模型锁定、一次修复波、一次范围限定再评审、仲裁
  8. Finish——finishing-a-development-branch
  9. Common Rationalizations——理性化对照表
  10. Example Workflow——更新为展示基于 resume 的修复轮次与断路器不触发的路径

"Constructing Reviewer Prompts""File Handoffs""Durable Progress" 三个杂物筐小节被溶解到各自规则实际生效的步骤中。硬性约束是:每一句 eval 调优过的句子恰好落在一个新位置;实现计划中附一张 source → destination 的 move map,让评审可以逐行核验没有任何句子被丢弃或改写。这个"只搬不改"的纪律来自 SDD 技能本身被 eval 场景反复校验的事实——实现计划 的 Task 3 甚至逐行列出了旧文件每段文字的去向(Verbatim / Reworded / Superseded),并给出 grep 验证命令(如 "fix subagent" 全文只允许剩下一处命中,即终审刻意保留的 "ONE fixer" 规则)。

仓库当前落地的 SKILL.md 已完整呈现这一骨架,其中修复循环一节位于 SKILL.md 第 302–375 行,断路器仲裁位于 第 358–375 行,与流程图中的 "Fix round R of 5: R≤3 resume implementer; R≥4 fresh implementer, more capable model" 节点一一对应。

理性化对照表:借口配反驳

设计文档将 "Never" 清单中"借口形态"的条目转换为对照表行,并新增覆盖循环病理的行。设计稿(最终措辞在实现阶段定稿)包含六行:

Excuse Reality
"Close enough on spec compliance" Reviewer found gaps = not done.
"I'll fix it myself, dispatching is overhead" Controller fixes pollute your context and skip review. Resume the implementer.
"One more round will converge" Past the cap, rounds don't converge. Adjudicate.
"The reviewer will just find something new anyway" Scoped re-reviews check fixes, not taste. New findings on untouched code go to the ledger, not the loop.
"This finding is obviously wrong, I'll drop it" You adjudicate only at the cap, and every adjudication is a ledger entry. Silent discards are forbidden.
"The fix was small, skip the re-review" Unreviewed fixes are how regressions land.

不属于借口的硬性规则(绝不并行派发多个实现者、绝不无 diff 文件派发评审者、模型行必填、绝不重新派发已完成台账的任务)则移到各自的使用点执行。落地后的 SKILL.md "Common Rationalizations" 小节 扩展为八行,新增了 "Reviews slow the loop down" 与 "Ledger bookkeeping is overhead" 两行,并与其余技能(test-driven-development、systematic-debugging、verification-before-completion 等)的表格格式完全对齐。

提示模板:四个契约,各管一段

修复循环的每个角色对应独立的提示模板,这是消除旧版歧义的另一半:

  • implementer-prompt.md——"After Review Findings" 按 resume 语义重写:你会被带着发现唤起;修复、重跑覆盖测试、追加报告文件、返回简短契约(见上文引用)。
  • task-reviewer-prompt.md——只负责首次评审;原先尾部的再评审句被移出,不再混装两个契约。
  • re-review-prompt.md(新增)——范围限定的再评审契约。其输入为 brief、更新后的报告、原始发现、修复范围 diff 包;输出为逐发现判定(addressed / not addressed)、修复 diff 中的新破坏、以及范围外观察。占位符沿用既有方括号约定,并新增 [FINDINGS][FIX_BASE_SHA](见 模板占位符定义)。设计文档明确说明单独立模的原因:它是不同契约——把再评审塞进全量评审模板正是旧版歧义的产生原因。
  • 接管派发(第 4–5 轮)——由 implementer-prompt.md 加 SKILL.md 指导现场组合(brief、报告路径、未关闭发现、接管框架),不新增模板文件。

终审循环与台账恢复语义

终审(Final Review)主体不变: merge-base 包、最强模型、ONE fixer(携带完整发现清单——按发现逐个派发修理工会各自重建上下文、重跑测试套件,真实会话中终审修复波的花费超过了所有任务之和)。新增的是:修复波之后恰好一次范围限定的再评审,随后控制器仲裁;残余承重发现会在 finishing-a-development-branch 环节浮现到人类面前。分支的末端也因此获得了有界的循环。

与修复循环紧密耦合的还有台账(progress ledger)的恢复语义——设计文档要求"任务是 DONE 当且仅当存在 Task <N>: complete 行",且"最后一条是修复轮次的任务处于循环中段:从下一轮恢复"。台账行格式是精确到可被 grep 的(实现计划的 Global Constraints 列出了全部六种行格式,如 Task <N>: fix round <R>/5 (<X> addressed, <Y> open — …; commits <a7>..<b7>)),因为 eval 场景直接按这些格式断言。工作区则由 scripts/sdd-workspace 统一解析:每个计划拥有 .superpowers/sdd/<plan-basename>/ 独立目录(台账、brief、报告、评审包),脚本自注释说明了为何放在工作树而非 .git/ 下(见 脚本头部注释)。

Evals:三个新演练场景 + 前后对照

设计文档要求新机制必须携带演练证据(drill evidence),在独立的 evals/ 仓库中新增三个场景,并加跑既有 SDD 场景的前后对照以捕捉重组带来的回归:

  1. Resume, don't re-dispatch——任务评审返回发现后,控制器必须 resume 同一实现者,而不是派发 fix 子代理。
  2. Breaker trips——预置一个"永不满足"的评审者;控制器必须在第五轮失败后停止派发,执行仲裁、记入台账并继续——而不是继续打转。
  3. Structural finding stops——预置一个承重发现(后续任务依赖它);控制器必须走 BLOCKED 停下,而不是停放继续。

实现计划 进一步给出了这三个场景的目录名(sdd-fix-loop-resumes-implementersdd-breaker-adjudicates-at-capsdd-breaker-structural-blocks)与两个中循环台账 fixture 助手的设计:parked 变体预置一个"仅质量问题"的未关闭发现(三重复制的 pad-and-join 表达式,测试全绿),structural 变体预置一个计划矛盾(Task 2 定义 seconds 契约、Task 3 传 milliseconds),并在线程中精确到台账行格式——因为场景的 checks.sh 就是按这些行 grep 的。

非目标与适用前提

设计文档显式划定了三条非目标,值得在移植借鉴时注意:

  • 台账会话隔离——由 PR #1943 负责。本工作触及相同小节,实现计划中标注了碰撞风险(若 #1943 中途落地,需用 move map 重新放置其文字)。
  • 脚本改动——task-brief 与 review-package 已经满足新循环的需要(本仓库 review-package 接受任意区间的现状印证了这一点),不需要改。
  • executing-plans 与 requesting-code-review 的改动——仅保持终审指针继续可解析。

适用前提:该机制面向"控制器 + 子代理"的分层执行模型,且 harness 需支持(或可模拟)agent resume——设计文档为不支持 resume 的 harness 明确了降级路径(携带 brief、报告文件与发现的全新派发);报告文件在两种情况下都是持久记忆。断路器上限(5 轮)、仲裁路由与台账行格式均可视为该设计的可配置参数,但设计强调:轮次上限与"只在上限处仲裁"是一对——拆掉任何一边都会让循环退回非收敛状态。

小结:这套设计能迁移的方法论

SDD Fix-Loop 重构设计 抽象出来,它对任何"Agent 自动评审-修复"工作流可迁移的经验是五条:

  1. 验证与评审是不同契约——修复后应做"逐发现判定 + 只查修复 diff"的范围限定再评审,而不是再来一轮全量评审;这是循环收敛的结构性条件。
  2. 上下文所有权优先于新角色——修复者优先 resume 原实现者;确实要换新角色时(第 4–5 轮),同时完成"去锚定"与"能力升档"。
  3. 有界 + 有仲裁——任何自动修复循环都需要显式轮次上限,以及上限处一条把"修不好"分流为"仲裁/记台账/停下"的路由;停下的通道复用既有 BLOCKED 机制,不新增人工检查点。
  4. 一切裁决留痕——每次仲裁、每个停放发现都是台账条目,"静默丢弃禁止"是审计底线;台账同时是上下文压缩后的恢复地图(仓库中 sdd-workspace 脚本注释 记录的教训:误读旧台账会让控制器跳过整个任务序列)。
  5. 文档结构服从执行顺序——把散落的杂物筐小节溶解到规则生效的步骤里,而 eval 调优过的文字"只搬不改",用 move map 让重组本身可验证。

当前仓库中该设计已落地:SKILL.md 的 "The Task Loop" 第 4 步完整实现了五轮修复循环与断路器,re-review-prompt.md 提供了范围限定再评审的完整模板,示例工作流(SKILL.md 第 438 行起)演示了一次 resume 修复轮次从触发到台账收口的完整路径。

登录后查看全文
热门项目推荐
相关项目推荐