From 1c1759199f904fa2ad1b7f8b0afdc9a15a160018 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, 17 Jul 2026 11:57:49 +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=20=E5=AD=90=E6=99=BA=E8=83=BD=E4=BD=93=E9=A9=B1?= =?UTF-8?q?=E5=8A=A8=E5=BC=80=E5=8F=91=E9=87=8D=E5=86=99=EF=BC=88=E5=90=88?= =?UTF-8?q?=E5=B9=B6=E5=AE=A1=E6=9F=A5=E8=80=85=20+=20scripts/=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 对齐 obra/superpowers v6.0.0+(当前 v6.1.1)对 subagent-driven-development 的重写: - 双审查者(规格 + 代码质量)合并为单个 task-reviewer-prompt.md,一次读 diff 出两个结论 - 新增 scripts/:review-package(生成审查包)、sdd-workspace(工作树临时区)、task-brief(抽取单任务简报) - SKILL.md 补齐 v6 新增章节:起飞前计划审查、处理审查者 ⚠️ 事项、构造审查者提示词、文件交接、持久化进度(ledger) - implementer-prompt.md 改为简报文件 + 报告文件契约、model 必填、TDD RED/GREEN 证据 - 删除 v5 遗留的 spec-reviewer-prompt.md / code-quality-reviewer-prompt.md 中文 fork 适配:task-brief 的 awk 同时匹配英文 "Task N" 与中文 "任务 N" 标题, 使 writing-plans 产出的中文计划也能抽取任务。review-package / sdd-workspace 与上游逐字节一致。 关联 #89 #19 --- skills/subagent-driven-development/SKILL.md | 200 +++++++++++------- .../code-quality-reviewer-prompt.md | 26 --- .../implementer-prompt.md | 56 +++-- .../scripts/review-package | 44 ++++ .../scripts/sdd-workspace | 22 ++ .../scripts/task-brief | 44 ++++ .../spec-reviewer-prompt.md | 61 ------ .../task-reviewer-prompt.md | 169 +++++++++++++++ 8 files changed, 441 insertions(+), 181 deletions(-) delete mode 100644 skills/subagent-driven-development/code-quality-reviewer-prompt.md create mode 100755 skills/subagent-driven-development/scripts/review-package create mode 100755 skills/subagent-driven-development/scripts/sdd-workspace create mode 100755 skills/subagent-driven-development/scripts/task-brief delete mode 100644 skills/subagent-driven-development/spec-reviewer-prompt.md create mode 100644 skills/subagent-driven-development/task-reviewer-prompt.md diff --git a/skills/subagent-driven-development/SKILL.md b/skills/subagent-driven-development/SKILL.md index 63217489..c54d6544 100644 --- a/skills/subagent-driven-development/SKILL.md +++ b/skills/subagent-driven-development/SKILL.md @@ -10,11 +10,15 @@ metadata: # 子智能体驱动开发 -通过为每个任务分派一个全新的子智能体来执行计划,每个任务完成后进行两阶段审查:先审查规格合规性,再审查代码质量。 +通过为每个任务分派一个全新的实现子智能体来执行计划:每个任务完成后做一次任务审查(规格合规性 + 代码质量),全部任务结束后再做一次覆盖整个分支的宽范围审查。 -**为什么用子智能体:** 你将任务委派给具有隔离上下文的专用智能体。通过精心设计它们的指令和上下文,确保它们专注并成功完成任务。它们不应继承你的会话上下文或历史记录——你要精确构造它们所需的一切。这样也能为你自己保留用于协调工作的上下文。 +**为什么用子智能体:** 你把任务委派给具有隔离上下文的专用智能体。通过精心设计它们的指令和上下文,确保它们专注并成功完成任务。它们绝不应继承你会话的上下文或历史记录——你要精确构造它们所需的一切。这样也能为你自己保留用于协调工作的上下文。 -**核心原则:** 每个任务一个全新子智能体 + 两阶段审查(先规格后质量)= 高质量、快速迭代 +**核心原则:** 每个任务一个全新子智能体 + 任务审查(规格 + 质量)+ 结尾宽范围审查 = 高质量、快速迭代 + +**旁白:** 工具调用之间最多说一句简短的旁白——进度账本和工具结果本身就是记录。 + +**持续执行:** 不要在任务之间停下来向你的人类伙伴确认。不间断地执行计划里的所有任务。唯一该停下的理由是:你无法解决的 BLOCKED 状态、确实妨碍推进的歧义,或所有任务已完成。"我该继续吗?"之类的询问和进度小结都在浪费他们的时间——他们让你执行计划,那就执行。 ## 何时使用 @@ -39,7 +43,7 @@ digraph when_to_use { **与 Executing Plans(并行会话)的对比:** - 同一会话(无上下文切换) - 每个任务全新子智能体(无上下文污染) -- 每个任务后两阶段审查:先规格合规性,再代码质量 +- 每个任务后做审查(规格合规性 + 代码质量),结尾做宽范围审查 - 更快的迭代(任务间无需人工介入) ## 流程 @@ -54,65 +58,73 @@ digraph process { "实现子智能体有疑问?" [shape=diamond]; "回答问题,提供上下文" [shape=box]; "实现子智能体实现、测试、提交、自审" [shape=box]; - "分派规格审查子智能体 (./spec-reviewer-prompt.md)" [shape=box]; - "规格审查子智能体确认代码匹配规格?" [shape=diamond]; - "实现子智能体修复规格差距" [shape=box]; - "分派代码质量审查子智能体 (./code-quality-reviewer-prompt.md)" [shape=box]; - "代码质量审查子智能体通过?" [shape=diamond]; - "实现子智能体修复质量问题" [shape=box]; - "在 TodoWrite 中标记任务完成" [shape=box]; + "写出 diff 文件,分派任务审查子智能体 (./task-reviewer-prompt.md)" [shape=box]; + "任务审查者报告规格 ✅ 且质量通过?" [shape=diamond]; + "针对 关键/重要 问题分派修复子智能体" [shape=box]; + "在待办列表和进度账本中标记任务完成" [shape=box]; } - "读取计划,提取所有任务的完整文本,记录上下文,创建 TodoWrite" [shape=box]; + "读取计划,记录上下文和全局约束,创建待办" [shape=box]; "还有剩余任务?" [shape=diamond]; - "分派最终代码审查子智能体审查整体实现" [shape=box]; + "分派最终代码审查子智能体 (../requesting-code-review/code-reviewer.md)" [shape=box]; "使用 superpowers:finishing-a-development-branch" [shape=box style=filled fillcolor=lightgreen]; - "读取计划,提取所有任务的完整文本,记录上下文,创建 TodoWrite" -> "分派实现子智能体 (./implementer-prompt.md)"; + "读取计划,记录上下文和全局约束,创建待办" -> "分派实现子智能体 (./implementer-prompt.md)"; "分派实现子智能体 (./implementer-prompt.md)" -> "实现子智能体有疑问?"; "实现子智能体有疑问?" -> "回答问题,提供上下文" [label="是"]; "回答问题,提供上下文" -> "分派实现子智能体 (./implementer-prompt.md)"; "实现子智能体有疑问?" -> "实现子智能体实现、测试、提交、自审" [label="否"]; - "实现子智能体实现、测试、提交、自审" -> "分派规格审查子智能体 (./spec-reviewer-prompt.md)"; - "分派规格审查子智能体 (./spec-reviewer-prompt.md)" -> "规格审查子智能体确认代码匹配规格?"; - "规格审查子智能体确认代码匹配规格?" -> "实现子智能体修复规格差距" [label="否"]; - "实现子智能体修复规格差距" -> "分派规格审查子智能体 (./spec-reviewer-prompt.md)" [label="重新审查"]; - "规格审查子智能体确认代码匹配规格?" -> "分派代码质量审查子智能体 (./code-quality-reviewer-prompt.md)" [label="是"]; - "分派代码质量审查子智能体 (./code-quality-reviewer-prompt.md)" -> "代码质量审查子智能体通过?"; - "代码质量审查子智能体通过?" -> "实现子智能体修复质量问题" [label="否"]; - "实现子智能体修复质量问题" -> "分派代码质量审查子智能体 (./code-quality-reviewer-prompt.md)" [label="重新审查"]; - "代码质量审查子智能体通过?" -> "在 TodoWrite 中标记任务完成" [label="是"]; - "在 TodoWrite 中标记任务完成" -> "还有剩余任务?"; + "实现子智能体实现、测试、提交、自审" -> "写出 diff 文件,分派任务审查子智能体 (./task-reviewer-prompt.md)"; + "写出 diff 文件,分派任务审查子智能体 (./task-reviewer-prompt.md)" -> "任务审查者报告规格 ✅ 且质量通过?"; + "任务审查者报告规格 ✅ 且质量通过?" -> "针对 关键/重要 问题分派修复子智能体" [label="否"]; + "针对 关键/重要 问题分派修复子智能体" -> "写出 diff 文件,分派任务审查子智能体 (./task-reviewer-prompt.md)" [label="重新审查"]; + "任务审查者报告规格 ✅ 且质量通过?" -> "在待办列表和进度账本中标记任务完成" [label="是"]; + "在待办列表和进度账本中标记任务完成" -> "还有剩余任务?"; "还有剩余任务?" -> "分派实现子智能体 (./implementer-prompt.md)" [label="是"]; - "还有剩余任务?" -> "分派最终代码审查子智能体审查整体实现" [label="否"]; - "分派最终代码审查子智能体审查整体实现" -> "使用 superpowers:finishing-a-development-branch"; + "还有剩余任务?" -> "分派最终代码审查子智能体 (../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:** 进入规格合规性审查。 +**DONE:** 生成审查包(在本技能目录下运行 `scripts/review-package BASE HEAD`——它会打印出自己写入的那个唯一文件路径;BASE 是你在分派实现者之前记录下来的那个提交——**绝不用** `HEAD~1`,那会悄悄丢掉多提交任务里除最后一个之外的所有提交),然后把打印出的路径交给任务审查者去分派。 -**DONE_WITH_CONCERNS:** 实现者完成了工作但标记了疑虑。在继续之前阅读这些疑虑。如果疑虑涉及正确性或范围,在审查前解决。如果只是观察性说明(如"这个文件越来越大了"),记录下来并继续审查。 +**DONE_WITH_CONCERNS:** 实现者完成了工作但标记了疑虑。在继续之前先读这些疑虑。如果疑虑涉及正确性或范围,在审查前先解决。如果只是观察性说明(例如"这个文件越来越大了"),记录下来并继续进入审查。 -**NEEDS_CONTEXT:** 实现者需要未提供的信息。提供缺失的上下文并重新分派。 +**NEEDS_CONTEXT:** 实现者需要未提供的信息。补上缺失的上下文并重新分派。 **BLOCKED:** 实现者无法完成任务。评估阻塞原因: 1. 如果是上下文问题,提供更多上下文并用同一模型重新分派 @@ -120,13 +132,53 @@ digraph process { 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`),并写进分派提示词。实现者把完整报告写在那里,只返回状态、提交、一行测试小结和疑虑。 +- **审查者输入:** 任务审查者拿到三个路径——同一份简报文件、报告文件、以及审查包——外加约束该任务的全局约束。 +- 修复分派把它们的修复报告(连同测试结果)追加到同一个报告文件,并返回一句简短小结;重新审查读取更新后的文件。 + +## 持久化进度 + +会话记忆无法在上下文压缩(compaction)中存活。在真实会话里,丢失了位置的控制者曾重新分派整段已经完成的任务序列——这是观察到的最昂贵的失败。把进度记在一个账本文件里,而不只是记在待办里。 + +- 技能启动时,检查是否有账本: + `cat "$(git rev-parse --show-toplevel)/.superpowers/sdd/progress.md"`。在那里被列为完成的任务就是完成了——不要重新分派它们;从第一个未标记完成的任务处继续。 +- 当某个任务的审查干净地返回时,在你做其他记账的同一条消息里,往账本追加一行: + `Task N: complete (commits .., review clean)`。 +- 这个账本是你的恢复地图:它点名的那些提交,即使你的上下文已经不记得创建过它们,也确实存在于 git 中。压缩之后,相信账本和 `git log`,而不是你自己的记忆。 +- `git clean -fdx` 会毁掉这个账本(它是被 git 忽略的临时文件);万一发生了,就从 `git log` 恢复。 ## 提示词模板 -- `./implementer-prompt.md` - 分派实现子智能体 -- `./spec-reviewer-prompt.md` - 分派规格合规审查子智能体 -- `./code-quality-reviewer-prompt.md` - 分派代码质量审查子智能体 +- [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) ## 示例工作流 @@ -134,13 +186,11 @@ digraph process { 你:我正在使用子智能体驱动开发来执行这个计划。 [一次性读取计划文件:docs/superpowers/plans/feature-plan.md] -[提取全部 5 个任务的完整文本和上下文] -[用所有任务创建 TodoWrite] +[为所有任务创建待办] 任务 1:Hook 安装脚本 -[获取任务 1 的文本和上下文(已提取)] -[分派实现子智能体,附带完整任务文本 + 上下文] +[对任务 1 运行 task-brief;分派实现者,附带简报 + 报告路径 + 上下文] 实现者:"在我开始之前——hook 应该安装在用户级别还是系统级别?" @@ -153,18 +203,15 @@ digraph process { - 自审:发现遗漏了 --force 参数,已添加 - 已提交 -[分派规格合规审查] -规格审查者:✅ 符合规格 - 所有需求已满足,无多余内容 - -[获取 git SHA,分派代码质量审查] -代码审查者:优点:测试覆盖好,代码整洁。问题:无。通过。 +[运行 review-package,把打印出的路径交给任务审查者去分派] +任务审查者:规格 ✅ - 所有需求已满足,无多余内容。 + 优点:测试覆盖好,代码整洁。问题:无。任务质量:通过。 [标记任务 1 完成] 任务 2:恢复模式 -[获取任务 2 的文本和上下文(已提取)] -[分派实现子智能体,附带完整任务文本 + 上下文] +[对任务 2 运行 task-brief;分派实现者,附带简报 + 报告路径 + 上下文] 实现者:[无疑问,直接开始] 实现者: @@ -173,32 +220,24 @@ digraph process { - 自审:一切正常 - 已提交 -[分派规格合规审查] -规格审查者:❌ 问题: +[运行 review-package,把打印出的路径交给任务审查者去分派] +任务审查者:规格 ❌: - 缺失:进度报告(规格要求"每 100 项报告一次") - 多余:添加了 --json 参数(未被要求) + 问题(重要):魔法数字(100) -[实现者修复问题] -实现者:移除了 --json 参数,添加了进度报告 - -[规格审查者再次审查] -规格审查者:✅ 现在符合规格 - -[分派代码质量审查] -代码审查者:优点:扎实。问题(重要):魔法数字(100) - -[实现者修复] -实现者:提取了 PROGRESS_INTERVAL 常量 +[分派修复子智能体,带上所有发现] +修复者:移除了 --json 参数,添加了进度报告,提取了 PROGRESS_INTERVAL 常量 -[代码审查者再次审查] -代码审查者:✅ 通过 +[任务审查者再次审查] +任务审查者:规格 ✅。任务质量:通过。 [标记任务 2 完成] ... [所有任务完成后] -[分派最终代码审查] +[分派最终代码审查者] 最终审查者:所有需求已满足,可以合并 完成! @@ -218,21 +257,20 @@ digraph process { - 审查检查点自动化 **效率提升:** -- 无文件读取开销(控制者提供完整文本) -- 控制者精确策划所需上下文 +- 控制者精确策划所需的确切上下文;大块产物以文件而非粘贴文本的方式流动 - 子智能体预先获得完整信息 - 问题在工作开始前就被提出(而非工作结束后) **质量关卡:** - 自审在交接前发现问题 -- 两阶段审查:规格合规性,然后代码质量 +- 任务审查给出两个结论:规格合规性和代码质量 - 审查循环确保修复确实有效 - 规格合规防止过度/不足构建 -- 代码质量确保实现良好 +- 代码质量确保实现构建良好 **成本:** -- 更多子智能体调用(每个任务需要实现者 + 2 个审查者) -- 控制者需要更多准备工作(预先提取所有任务) +- 更多子智能体调用(每个任务需要实现者 + 审查者) +- 控制者需要更多准备工作(预先抽取所有任务) - 审查循环增加迭代次数 - 但能及早发现问题(比后期调试更省成本) @@ -240,17 +278,19 @@ digraph process { **绝不:** - 未经用户明确同意就在 main/master 分支上开始实现 -- 跳过审查(规格合规性或代码质量) +- 跳过任务审查,或接受一份缺少任一结论的报告(规格合规性 **和** 任务质量两者都必须有) - 带着未修复的问题继续 - 并行分派多个实现子智能体(会冲突) -- 让子智能体读取计划文件(应提供完整文本) +- 让子智能体去读整个计划文件(改为给它任务简报——`scripts/task-brief`) - 跳过场景铺设上下文(子智能体需要理解任务在哪个环节) - 忽视子智能体的问题(在让它们继续之前先回答) -- 在规格合规性上接受"差不多就行"(规格审查者发现问题 = 未完成) +- 在规格合规性上接受"差不多就行"(审查者发现了规格问题 = 未完成) - 跳过审查循环(审查者发现问题 = 实现者修复 = 再次审查) - 让实现者的自审替代正式审查(两者都需要) -- **在规格合规性审查通过之前开始代码质量审查**(顺序错误) -- 在任一审查有未解决问题时就进入下一个任务 +- 告诉审查者不要标记什么,或在分派提示词里预先给某个发现定级严重度("顶多按 Minor 处理")——计划里的示例代码是起点,不是它的弱点是被有意选择的证据 +- 在没有 diff 文件的情况下分派任务审查者——先生成它(`scripts/review-package BASE HEAD`),并在提示词里点名打印出的路径 +- 在审查还有未解决的 关键/重要 问题时就进入下一个任务 +- 重新分派一个进度账本已标记完成的任务——在任何压缩或恢复之后,都要查账本(和 `git log`) **如果子智能体提问:** - 清晰完整地回答 @@ -263,16 +303,16 @@ digraph process { - 重复直到通过 - 不要跳过重新审查 -**如果子智能体失败:** +**如果子智能体任务失败:** - 分派修复子智能体并提供具体指令 - 不要尝试手动修复(上下文污染) ## 集成 **必需的工作流技能:** -- **superpowers:using-git-worktrees** - 必需:在开始前建立隔离工作区 -- **superpowers:writing-plans** - 创建本技能执行的计划 -- **superpowers:requesting-code-review** - 审查子智能体的代码审查模板 +- **superpowers:using-git-worktrees** - 确保隔离的工作区(创建一个,或核实已有的) +- **superpowers:writing-plans** - 创建本技能所执行的计划 +- **superpowers:requesting-code-review** - 用于最终整分支审查的代码审查模板 - **superpowers:finishing-a-development-branch** - 所有任务完成后收尾 **子智能体应使用:** @@ -280,3 +320,5 @@ digraph process { **替代工作流:** - **superpowers:executing-plans** - 用于并行会话而非同会话执行 + + diff --git a/skills/subagent-driven-development/code-quality-reviewer-prompt.md b/skills/subagent-driven-development/code-quality-reviewer-prompt.md deleted file mode 100644 index d7e876e5..00000000 --- a/skills/subagent-driven-development/code-quality-reviewer-prompt.md +++ /dev/null @@ -1,26 +0,0 @@ -# 代码质量审查者提示词模板 - -分派代码质量审查子智能体时使用此模板。 - -**目的:** 验证实现是否构建良好(整洁、有测试、可维护) - -**仅在规格合规性审查通过后才分派。** - -``` -Task tool (superpowers:code-reviewer): - 使用模板 requesting-code-review/code-reviewer.md - - WHAT_WAS_IMPLEMENTED: [来自实现者的报告] - PLAN_OR_REQUIREMENTS: [plan-file] 中的任务 N - BASE_SHA: [任务开始前的提交] - HEAD_SHA: [当前提交] - DESCRIPTION: [任务摘要] -``` - -**除标准代码质量关注点外,审查者还应检查:** -- 每个文件是否有单一明确的职责和定义清晰的接口? -- 各单元是否拆分得足以独立理解和测试? -- 实现是否遵循了计划中的文件结构? -- 本次实现是否创建了已经很大的新文件,或显著增大了现有文件?(不要标记已有的文件大小问题——聚焦于本次变更带来的影响。) - -**代码审查者返回:** 优点、问题(关键/重要/次要)、评估结论 diff --git a/skills/subagent-driven-development/implementer-prompt.md b/skills/subagent-driven-development/implementer-prompt.md index eed1ced1..ed600add 100644 --- a/skills/subagent-driven-development/implementer-prompt.md +++ b/skills/subagent-driven-development/implementer-prompt.md @@ -3,14 +3,17 @@ 分派实现子智能体时使用此模板。 ``` -Task tool (general-purpose): +Subagent (general-purpose): description: "实现任务 N:[任务名称]" + model: [模型 —— 必填:按 SKILL.md 的"模型选择"来选;省略模型会默默 + 继承会话里最贵的那个] prompt: | 你正在实现任务 N:[任务名称] ## 任务描述 - [计划中任务的完整文本 - 粘贴到这里,不要让子智能体去读文件] + 先读你的任务简报:[BRIEF_FILE] + 它包含计划中该任务的完整文本。 ## 上下文 @@ -41,33 +44,36 @@ Task tool (general-purpose): **工作过程中:** 如果遇到意料之外或不清楚的情况,**提问**。 随时可以暂停并澄清。不要猜测或做假设。 + 迭代过程中,只跑你正在改动的那部分的聚焦测试;在提交前跑一次 + 完整测试套件,而不是每次编辑后都跑。 + ## 代码组织 - 你在能一次性放入上下文的代码上推理效果最好,文件聚焦时编辑也更可靠。 + 你在能一次性放入上下文的代码上推理效果最好,文件聚焦时你的编辑也更可靠。 请牢记: - 遵循计划中定义的文件结构 - 每个文件应有单一明确的职责和定义清晰的接口 - - 如果你正在创建的文件超出了计划预期的规模,停下来并以 + - 如果你正在创建的文件超出了计划的意图规模,停下来并以 DONE_WITH_CONCERNS 状态报告——不要在没有计划指导的情况下自行拆分文件 - - 如果你正在修改的现有文件已经很大或很混乱,小心操作 + - 如果你正在修改的现有文件已经很大或很混乱,小心操作, 并在报告中将其标注为疑虑 - 在已有代码库中,遵循已建立的模式。像一个好的开发者那样 - 改善你接触的代码,但不要重构你任务范围之外的东西。 + 改善你接触到的代码,但不要重构你任务范围之外的东西。 ## 当你力不从心时 - 说"这对我来说太难了"完全没问题。劣质的工作比不做更糟。 + 随时可以停下来说"这对我来说太难了"。劣质的工作比不做更糟。 上报不会受到惩罚。 **遇到以下情况时停下来上报:** - 任务需要在多个有效方案之间做架构决策 - - 你需要理解提供内容之外的代码但找不到答案 + - 你需要理解提供内容之外的代码但找不到清晰答案 - 你对自己的方案是否正确感到不确定 - 任务涉及计划未预期的现有代码重构 - 你一直在逐个读文件试图理解系统但没有进展 **如何上报:** 以 BLOCKED 或 NEEDS_CONTEXT 状态汇报。具体描述 - 你卡在哪里、尝试了什么、需要什么帮助。 + 你卡在哪里、尝试了什么、需要什么样的帮助。 控制者可以提供更多上下文、用更强的模型重新分派, 或将任务拆分为更小的部分。 @@ -94,20 +100,40 @@ Task tool (general-purpose): - 测试是否真正验证了行为(而非只是 mock 行为)? - 如果要求了 TDD,我是否遵循了? - 测试是否全面? + - 测试输出是否干净(没有零散的告警或噪声)? 如果在自审中发现问题,在汇报前就修复。 - ## 汇报格式 + ## 审查发现之后 - 完成后汇报: - - **状态:** DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT - - 你实现了什么(或尝试了什么,如果被阻塞) + 如果审查者发现了问题、你也修复了,就重跑覆盖被改动代码的测试, + 并把结果追加到你的报告文件里。审查者不会替你重跑测试—— + 你的报告就是测试证据。 + + ## 报告格式 + + 把你的完整报告写到 [REPORT_FILE]: + - 你实现了什么(如果被阻塞,则是你尝试了什么) - 你测试了什么以及测试结果 + - **TDD 证据**(如果本任务要求了 TDD): + - RED:跑的命令、实现前相关的失败输出、以及为什么这个失败是预期的 + - GREEN:跑的命令、以及实现后相关的通过输出 - 修改了哪些文件 - 自审发现(如果有) - 任何问题或疑虑 + 然后只汇报以下内容(不超过 15 行——细节都在报告文件里): + - **状态:** DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT + - 创建的提交(短 SHA + 标题) + - 一行测试小结(例如"14/14 通过,输出干净") + - 你的疑虑,如果有 + - 报告文件路径 + + 如果是 BLOCKED 或 NEEDS_CONTEXT,把具体细节放进最终消息本身—— + 控制者会直接据此行动。 + 如果你完成了工作但对正确性有疑虑,使用 DONE_WITH_CONCERNS。 - 如果你无法完成任务,使用 BLOCKED。如果你需要 - 未提供的信息,使用 NEEDS_CONTEXT。绝不默默产出你不确定的工作。 + 如果你无法完成任务,使用 BLOCKED。如果你需要未提供的信息, + 使用 NEEDS_CONTEXT。绝不默默产出你不确定的工作。 ``` + diff --git a/skills/subagent-driven-development/scripts/review-package b/skills/subagent-driven-development/scripts/review-package new file mode 100755 index 00000000..33bb20f7 --- /dev/null +++ b/skills/subagent-driven-development/scripts/review-package @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Generate a review package: commit list, stat summary, and the net +# diff with extended context, written to a file the reviewer reads in one +# 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 +# (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 + exit 2 +fi + +base=$1 +head=$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 +else + dir=$("$(cd "$(dirname "$0")" && pwd)/sdd-workspace") + out="$dir/review-$(git rev-parse --short "$base")..$(git rev-parse --short "$head").diff" +fi + +{ + echo "# Review package: ${base}..${head}" + echo + echo "## Commits" + git log --oneline "${base}..${head}" + echo + echo "## Files changed" + git diff --stat "${base}..${head}" + echo + echo "## Diff" + git diff -U10 "${base}..${head}" +} > "$out" + +commits=$(git rev-list --count "${base}..${head}") +echo "wrote ${out}: ${commits} commit(s), $(wc -c < "$out" | tr -d ' ') bytes" diff --git a/skills/subagent-driven-development/scripts/sdd-workspace b/skills/subagent-driven-development/scripts/sdd-workspace new file mode 100755 index 00000000..ea9bb08f --- /dev/null +++ b/skills/subagent-driven-development/scripts/sdd-workspace @@ -0,0 +1,22 @@ +#!/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. +# +# 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. +# +# Single source of truth for the workspace location, so task-brief and +# review-package cannot drift to different directories. +# +# Usage: sdd-workspace +set -euo pipefail + +root=$(git rev-parse --show-toplevel) +dir="$root/.superpowers/sdd" +mkdir -p "$dir" +printf '*\n' > "$dir/.gitignore" +cd "$dir" && pwd diff --git a/skills/subagent-driven-development/scripts/task-brief b/skills/subagent-driven-development/scripts/task-brief new file mode 100755 index 00000000..879ba356 --- /dev/null +++ b/skills/subagent-driven-development/scripts/task-brief @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Extract one task's full text from an implementation plan into a file the +# implementer reads in one call, so the task text never has to be pasted +# 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). +# +# 中文 fork 适配:上游只识别英文任务标题 "## Task N",而 superpowers-zh +# 的 writing-plans 产出的是 "### 任务 N:..."。下方 awk 同时匹配 +# "Task" 与 "任务",两种计划都能抽取。 +set -euo pipefail + +if [ $# -lt 2 ] || [ $# -gt 3 ]; then + echo "usage: task-brief PLAN_FILE TASK_NUMBER [OUTFILE]" >&2 + exit 2 +fi + +plan=$1 +n=$2 +[ -f "$plan" ] || { echo "no such plan file: $plan" >&2; exit 2; } + +if [ $# -eq 3 ]; then + out=$3 +else + dir=$("$(cd "$(dirname "$0")" && pwd)/sdd-workspace") + out="$dir/task-${n}-brief.md" +fi + +awk -v n="$n" ' + /^```/ { infence = !infence } + !infence && /^#+[ \t]+(Task|任务)[ \t]*[0-9]+/ { + intask = ($0 ~ ("^#+[ \t]+(Task|任务)[ \t]*" n "([^0-9]|$)")) + } + intask { print } +' "$plan" > "$out" + +if [ ! -s "$out" ]; then + echo "task ${n} not found in ${plan} (no heading matching 'Task ${n}' / '任务 ${n}')" >&2 + exit 3 +fi + +echo "wrote ${out}: $(wc -l < "$out" | tr -d ' ') lines" diff --git a/skills/subagent-driven-development/spec-reviewer-prompt.md b/skills/subagent-driven-development/spec-reviewer-prompt.md deleted file mode 100644 index fc684b46..00000000 --- a/skills/subagent-driven-development/spec-reviewer-prompt.md +++ /dev/null @@ -1,61 +0,0 @@ -# 规格合规审查者提示词模板 - -分派规格合规审查子智能体时使用此模板。 - -**目的:** 验证实现者是否构建了所要求的内容(不多不少) - -``` -Task tool (general-purpose): - description: "审查任务 N 的规格合规性" - prompt: | - 你正在审查一个实现是否与其规格匹配。 - - ## 要求的内容 - - [任务需求的完整文本] - - ## 实现者声称构建了什么 - - [来自实现者的报告] - - ## 关键:不要信任报告 - - 实现者完成得疑似过快。他们的报告可能不完整、 - 不准确或过于乐观。你必须独立验证所有内容。 - - **不要:** - - 相信他们关于实现内容的说法 - - 信任他们关于完整性的声明 - - 接受他们对需求的解读 - - **要做的:** - - 阅读他们写的实际代码 - - 逐行对比实际实现和需求 - - 检查他们声称已实现但实际遗漏的部分 - - 寻找他们未提及的多余功能 - - ## 你的工作 - - 阅读实现代码并验证: - - **缺失的需求:** - - 他们是否实现了所有被要求的内容? - - 是否有他们跳过或遗漏的需求? - - 是否有他们声称可用但实际未实现的功能? - - **多余/不需要的工作:** - - 他们是否构建了未被要求的内容? - - 他们是否过度工程化或添加了不必要的功能? - - 他们是否添加了规格中没有的"锦上添花"功能? - - **理解偏差:** - - 他们是否以不同于预期的方式解读了需求? - - 他们是否解决了错误的问题? - - 他们是否实现了正确的功能但方式不对? - - **通过阅读代码来验证,而非信任报告。** - - 报告: - - ✅ 符合规格(如果经过代码检查后一切匹配) - - ❌ 发现问题:[具体列出缺失或多余的内容,附带 file:line 引用] -``` diff --git a/skills/subagent-driven-development/task-reviewer-prompt.md b/skills/subagent-driven-development/task-reviewer-prompt.md new file mode 100644 index 00000000..02d51c0a --- /dev/null +++ b/skills/subagent-driven-development/task-reviewer-prompt.md @@ -0,0 +1,169 @@ +# 任务审查者提示词模板 + +分派任务审查子智能体时使用此模板。审查者一次性读取该任务的 diff, +返回两个结论:规格合规性和代码质量。 + +**目的:** 核实一个任务的实现与其需求匹配(不多不少)且构建良好(整洁、有测试、可维护) + +``` +Subagent (general-purpose): + description: "审查任务 N(规格 + 质量)" + model: [模型 —— 必填:按 SKILL.md 的"模型选择"来选;省略模型会默默 + 继承会话里最贵的那个] + prompt: | + 你正在审查一个任务的实现:先看它是否与需求匹配,再看它是否 + 构建良好。这是一个任务范围内的关卡,不是合并审查——覆盖整个 + 分支的宽范围审查会在所有任务完成后另行进行。 + + ## 要求的内容 + + 读取任务简报:[BRIEF_FILE] + + 来自规格/设计、约束本任务的全局约束: + [GLOBAL_CONSTRAINTS] + + ## 实现者声称构建了什么 + + 读取实现者的报告:[REPORT_FILE] + + ## 待审查的 Diff + + **Base:** [BASE_SHA] + **Head:** [HEAD_SHA] + **Diff 文件:** [DIFF_FILE] + + 一次性读取这个 diff 文件——它包含提交列表、stat 摘要,以及 + 带上下文的完整 diff,它就是你对本次改动的视图。diff 的上下文行 + **就是**那些被改动的文件:不要单独去 Read 某个被改动的文件,除非 + 你必须判断的某个 hunk 在函数中途被截断——并在报告中说明这一点。 + 不要重跑 git 命令。如果 diff 文件缺失,就自己取 diff: + `git diff --stat [BASE_SHA]..[HEAD_SHA]` 和 `git diff [BASE_SHA]..[HEAD_SHA]`。 + 不要爬取更广的代码库。只有为了评估一个你能点名的具体风险,才去 + 查看 diff 之外的代码——每个点名的风险做一次聚焦检查,并在报告中 + 同时点名这个风险和你检查了什么。横切改动是正当的、可点名的风险: + 如果 diff 改动了锁顺序、某个函数或 API 契约、或共享的可变状态, + 检查其调用点就是正确的方法。 + + 你的审查在这个 checkout 上是只读的。不要以任何方式改动工作树、 + 索引、HEAD 或分支状态。 + + ## 不要信任报告 + + 把实现者的报告当作关于代码的、未经核实的说法。它可能不完整、 + 不准确或过于乐观。对照 diff 去核实这些说法。报告里的设计理由 + 同样是说法:"出于 YAGNI 留着没做""特意保持简单"或任何其他辩解, + 都是实现者在给自己的工作打分。就代码本身评判它的优劣——一句 + 陈述出来的理由永远不会降低一个发现的严重度。 + + ## 测试 + + 实现者已经跑过测试,并为正是这份代码报告了带 TDD 证据的结果。 + 不要为了确认他们的报告而重跑测试套件。只有当阅读代码引出一个 + 现有任何运行都无法回答的具体疑问时,才去跑测试——而且是聚焦 + 测试,绝不是包级套件、竞态检测运行、或反复的/高次数的循环。 + 如果看起来确实需要重度验证,就在报告里建议它,而不是自己去跑。 + 如果你在这个环境里无法运行命令,就点名你会跑的那个测试。 + + 实现者报告的测试输出里的告警或其他噪声都是发现——测试输出 + 应当是干净的。 + + ## 第一部分:规格合规性 + + 把 diff 对照"要求的内容"来看: + + - **缺失:** 他们跳过、遗漏、或声称却未实现的需求 + - **多余:** 未被要求的功能、过度工程、不需要的"锦上添花" + - **理解偏差:** 正确的功能却用错了方式来构建,解决了错误的问题 + + 如果某个需求无法仅从这份 diff 中核实(它藏在未改动的代码里、 + 或横跨多个任务),就把它作为一个 ⚠️ 事项报告出来,而不是 + 扩大你的搜索范围。 + + ## 第二部分:代码质量 + + **代码质量:** + - 关注点分离是否干净? + - 错误处理是否恰当? + - 是否做到 DRY 而没有过早抽象? + - 边界情况是否处理了? + + **测试:** + - 新增和改动的测试是否验证了真实行为,而非 mock? + - 本任务的边界情况是否被覆盖? + + **结构:** + - 每个文件是否有单一明确的职责和定义清晰的接口? + - 各单元是否拆分得足以独立理解和测试? + - 实现是否遵循了计划中的文件结构? + - 本次改动是否创建了已经很大的新文件,或显著增大了现有文件? + (不要标记已有的文件大小问题——聚焦于本次改动带来的贡献。) + + 你的报告应指向证据:每一个发现、以及任何你本来会用一句干巴巴的 + "是"来回答的检查,都要给出 file:line 引用。一份引用了行号的 + 紧凑报告,就把控制者需要的一切都给它了。 + + 你的最终消息就是报告本身:直接从规格合规性结论开始。每一行 + 要么是一个结论、要么是一个带 file:line 的发现、要么是你跑过的 + 一个检查——没有开场白、没有流程叙述、没有结尾小结。 + + ## 校准 + + 按实际严重度给问题分类。不是所有东西都是 关键。 + 重要 意味着这个任务在修好之前不可信:不正确或脆弱的行为、 + 一个漏掉的需求、或你会为之拦下合并的可维护性损害——逻辑块的 + 逐字重复、被吞掉的错误、什么都不断言的测试。"覆盖面可以更广" + 和打磨类建议是 次要。 + 如果计划或简报明确强制了某个本评分标准称之为缺陷的东西(一个 + 什么都不断言的测试、逻辑块的逐字重复),那**就是**一个发现—— + 把它报告为 重要,并标注为"计划强制"。计划的作者身份不能给它 + 自己的工作打分;由人类来决定。 + 在列出问题之前,先承认做得好的地方——准确的赞扬能帮实现者 + 信任其余的反馈。 + + ## 输出格式 + + ### 规格合规性 + + - ✅ 符合规格 | ❌ 发现问题:[缺失/多余/理解偏差的内容, + 附带 file:line 引用] + - ⚠️ 无法从 diff 中核实:[你无法仅凭 diff 核实的需求,以及 + 控制者应当检查什么——与你能核实的一切的 ✅/❌ 结论一起报告] + + ### 优点 + [哪些做得好?要具体。] + + ### 问题 + + #### 关键(必须修复) + #### 重要(应当修复) + #### 次要(锦上添花) + + 每个问题:file:line、哪里错了、为什么重要、如何修复(如果不明显)。 + + ### 评估 + + **任务质量:** [通过 | 需要修复] + + **理由:** [1-2 句技术性评估] +``` + +**占位符:** +- `[模型]` —— 必填:按 SKILL.md 的"模型选择"选审查者模型 +- `[BRIEF_FILE]` —— 必填:任务简报文件(`scripts/task-brief PLAN N` + 会打印路径;与实现者所用的是同一个文件) +- `[GLOBAL_CONSTRAINTS]` —— 从计划的"全局约束"一节或规格里逐字抄下的、 + 有约束力的需求:精确的取值、格式、以及组件之间被明确规定的关系 + (不是流程规则——那些已经在本模板里了) +- `[REPORT_FILE]` —— 必填:实现者写入其详细报告的那个文件 +- `[BASE_SHA]` —— 本任务之前的提交 +- `[HEAD_SHA]` —— 当前提交 +- `[DIFF_FILE]` —— 必填:控制者写入审查包的那个路径 + (`scripts/review-package BASE HEAD` 会打印它写入的唯一路径; + 审查包永远不会进入控制者的上下文) + +**审查者返回:** 规格合规性结论(✅/❌/⚠️)、优点、问题 +(关键/重要/次要)、任务质量结论 + +一次修复分派可以同时处理规格差距和质量发现;修复后的重新审查 +覆盖两个结论。 +