| name | review-loop |
| description | 提交前的自动 review 迭代环:委派子 agent 跑 CC 自带 /code-review(默认 sonnet × medium,并发/难复现等硬 diff 升 opus × high),发现高置信正确性问题就修、跑测试+happy-path 验证、复审,迭代到「运行验证通过 + 无高置信 correctness 问题」才放行。收敛靠运行验证+置信过滤,非 reviewer 挑不出为止。三条硬规则:永远显式传档位、永远委派子 agent、只用两个合法的模型×档位组合。由 /commit 在生成 commit 前自动调用,也可手动跑 |
| disable-model-invocation | false |
用户(或 /commit)调用此 skill 表示要对当前工作树的改动跑一轮自动 review 迭代,直到「运行验证通过 + 无高置信 correctness 问题」(clean)才放行提交。
为什么存在
/code-review 只出一次 finding,且要人记得跑。本 skill 把「review → 修 → 验证 → 复审 → 迭代到干净」固化成 commit 前的自动环,让每个提交都经过 review 把关。
它要同时治三个实战病根:
- 无运行验证 → 基础功能审废无人知:reviewer 只读代码、不跑代码。若收敛只看「reviewer 说没问题」,那每轮修 corner case 时基础功能被某次「外科手术式修复」改废也没人发现。故收敛闸把**「受影响测试全绿 + happy-path 主流程跑通」列为硬前置**(呼应
/verify、rules/python.md §3.7、宪法 TDD 章),且排在 reviewer 意见之前:先确认基础功能没被上一轮修废,再谈还有没有新问题。
- 无置信过滤 → 无限挑刺、开发变慢:reviewer(尤其对规则类文档)问题空间近乎无穷,任何编得出的 corner case 都能算「可能出错」。故对齐 anthropic 官方 code-review plugin 的做法——只认「附
file:line 源码证据 + 高置信真会在生产触发」的 correctness finding,pre-existing / pedantic / linter 能抓的 / 推测式 corner case 一律不阻断。收敛看「有没有高置信 correctness finding」,不是「reviewer 还能不能再挑一个」。
- 成本与 diff 规模脱钩 → 一次 review 烧光 session 预算:
/code-review 的 review angle 是 inline 的(跑在调用方 context 里),且不传档位就继承 session 的 effort。于是在 xhigh session 下,一个 5 行的 diff 也按 10 个 angle + sweep 审,那十轮文件阅读还全部沉进主对话历史、之后每轮重发。故有 Step 3 的三条硬规则。
收敛靠「运行验证 + 高置信过滤」,不是靠 reviewer 挑不出为止。
已知局限(诚实声明):本 skill 用的 /code-review 与写这段 diff 的是同一个模型家族,属同模型自审,对并发 / 多线程 / 难复现改动存在已知盲区。硬实证:一处 grpc.aio 消费迁专用线程的重构,CC 自审只发现 2 个并发隐患,换独立模型(codex)review 又补出 3 个 P1,其中「优雅停不可达」CC 完全漏判。本 skill 不再自动引入跨模型第二意见(判定链长、触发率近零、维护面外溢);需要时由人工手动引入。重档改用 opus × high 加深思考,只是缓解、不等于消除这层盲区。
loop 是什么
review → 修 → 验证 → 再 review → 再修 → 直到 clean。必须是循环而非单次:修复本身可能引入新问题,首轮 review 也未必看全——只有「修完再验证 + 复审、直到验证通过且 reviewer 报没有该修的问题」才收敛。
收敛判据 = 三要素并闸(一轮收敛当且仅当三者同时成立):
- (A) 运行验证通过:受影响测试全绿 + happy-path 主流程跑通(被改的编排器 / facade 无 happy-path test 则先补一条)。这是硬前置,排在 (B) 之前——先确认基础功能没被上一轮修废。无运行时面的文件(纯文档 / 指令规则)该闸 N/A,跳过(见 6.3)。
- (B) 无高置信 correctness finding:reviewer 按置信闸过滤后,无「附
file:line 证据 + 高置信真会在生产触发」的正确性 / 逻辑 / 安全问题(无论标注 P0 / P1 / P2——被标 P2 的高置信正确性 bug 同样阻断)。低置信 / 无证据 / pre-existing / pedantic / linter 域一律不阻断(顺手能改可改,不强制、不计入迭代)。
- (C) 已定前提未被重复质疑:若 reviewer 报的「问题」实质是质疑一个已由人类明确拍板的设计决策,那不是 bug、不阻断收敛——它只是不知道该决策已定。把该前提补进下轮委派 prompt,继续;不要为了让它闭嘴而推翻人类已定的决策。分诊规则见 6.1。
判据是「基础功能没坏 + 有没有高置信真会出错的问题」,不是 P 级数字、更不是「reviewer 还能不能再挑一个」。
Step 1:确认有变更
git status 看工作树有没有改动。干净无变更 → 打印「无待 review 变更」退出(clean);有变更 → 继续。
review 的对象就是整个工作树的全部改动——/commit 提交前调本 skill,此刻工作树就是一堆待提交改动、没有谁提前分批 git add,故不区分、不合并 staged / unstaged。
Step 2:琐碎改动跳过判定
避免每个小 commit 都烧 review。只有真正的用户文档 / 纯机械改动才自动跳过——仅命中以下之一 → 打印「琐碎改动,跳过 review」返回 clean:
- 仅改
docs/ 下文件、或 README 的非流程说明段;
- 仅改代码注释 / docstring;
- 单行或极小的机械 fix(笔误、格式、排版)。
这些绝不自动跳过(哪怕它们是 Markdown / 纯文字):
- 指令 / 规则文件:
skills/*.md、GLOBAL_AGENTS.md(宪法)、rules/*.md、.claude/ 下的 agent 配置等——它们就是开发流程与安全边界本身,改它们等于改门禁自己的规则,跳过 review 会让门禁在「修改自身」时失效。
- 配置变更:CI 权限、部署目标、认证 / CORS、依赖版本、构建 / 运行时开关等,一行就可能改变安全态或线上行为。
有疑则不跳——涉及业务逻辑 / 并发 / 算法 / 接口契约 / 配置 / 指令规则 / 多文件改动,一律走 review。
Step 3:选档
三条硬规则
一、调 /code-review 必须显式带档位。 裸调会让它继承当前 session 的 effort——ultracode / xhigh session 下,一个 5 行的 diff 也按 xhigh(10 个 angle + sweep)审,成本与 diff 规模完全脱钩。显式传档把 review 成本钉死在本 skill 手里。
二、review 永远在子 agent 里跑,主会话不直接跑——重档也不例外(唯一例外是 Step 5 的降级链:委派本身失败时才退回主会话直跑)。/code-review 的各个 review angle 是 inline 的,跑在调用方的 context 里:主会话直调会把 8–10 轮文件阅读永久写进主对话历史,之后每一轮都要重发。委派后主会话只收一份 finding 列表。代价是子 agent 一份固定的 standing context(约 5 万 token 量级,绝大部分是可缓存 input),远小于主 context 被撑大的复利。
三、只有两个合法的「模型 × 档位」组合。
| 档 | 委派模型 | 命令 | 触发 |
|---|
| 默认 | sonnet | /code-review medium | 一切需要 review 的改动 |
| 重 | opus | /code-review high | 命中下列任一复杂特征 |
禁止组合(别顺手「升档」踩进去)
sonnet + high / max → 打开 finder 扇出(按 diff 行数扇 2–8 个 finder 子 agent),比 Opus 还贵。finder 扇出只在 Sonnet 的 high 及以上开启,Opus 全档位关闭。
opus + medium → 与 opus + high 同为 8 个 angle、成本几乎相同,findings 上限却更低,被严格支配,没有使用理由。
- 任何档位 +
xhigh → 10 个 angle + sweep,正是「一次 review 烧光 session」的规格;且它根本不是 /code-review 的合法入参,只能靠继承 session effort 拿到——硬规则一已封死这条路。
升重档的复杂特征
这些正是「审浅了会漏真 bug」的场景,也正是同模型自审盲区最大的地方:
- 并发 / 多线程 / 异步生命周期:线程、
asyncio、锁、跨线程队列、join / cancel / 优雅停、事件循环迁移;
- 跨进程 / 网络 / 容错:重试 / 幂等 / 部分失败 / 回滚 / 超时 / 降级路径;
- 状态机 / 竞态:排序假设 / 陈旧状态 / 重入 / 资源生命周期(文件 / socket / channel 的开关配对);
- 难以用测试复现,或改动横跨 3+ 模块的编排装配。
拿不准时偏向升重档——漏判一个并发 diff 的代价,大于多花一次 opus × high。
没有第三档
不设 low 档:它只省「与 diff 规模成正比」的那部分推理(小 diff 上本就小),却丢掉 Sonnet medium 自带的 1-vote verify 步骤。而本 loop 真正的成本大头是误报引发的无效修复轮(写测试 → 改代码 → 跑验证 → 复审),不是 review 本身。真正琐碎的改动已在 Step 2 跳过;没跳过的(配置、指令规则文件)每行都重,不该降规格。
顺带澄清一个常见误解:/code-review 的 verification step 只有 Sonnet 档有(3+5 angles × 6 candidates → 1-vote verify),Opus 各档是 8–10 个 inline angle 去重后直接出、无 verify。这也是默认档选 Sonnet 的理由之一——不只是便宜,误报还更少。
Step 4:委派子 agent 跑 review
Agent(
subagent_type: "general-purpose",
model: "sonnet" | "opus", // 按 Step 3 选档
description: "Review working tree diff", // 必填字段,别漏
run_in_background: false, // 必须同步:拿到 finding 才能往下走
prompt: """
对当前工作树的 diff 跑 `/code-review medium`(重档写 high),不带 --fix / --comment。
原样返回它输出的 finding 列表(含每条的 file:line 与严重度),不要自行修改任何文件。
本轮已定的设计前提,不要把对这些的质疑当作 finding:
- <逐条列出人类已拍板的决策>
"""
)
四条要点:
description 与 prompt 都是 Agent 工具的必填字段,漏掉 description 会直接校验失败。
run_in_background: false:Agent 默认后台跑,而本 loop 要拿到 finding 才能继续,必须同步。
- 不带
--fix:本 skill 要自己走 Step 6 的分诊 + TDD 正序修复 + 运行验证闸;--fix 会绕过验证闸直接改代码。只取它的 finding 列表。
- 不带
--comment:本地迭代,不发 PR 评论。
「已定设计前提」摘要怎么来:子 agent 没有本轮对话的上下文,不告诉它哪些是人类已拍板的决策,它就会去质疑,产出一堆假 finding、白烧闸口额度。故:
- 首轮委派前先收集一份清单——来源是本轮对话里人类明确拍板过的决策,以及
docs/<N>-*/PLAN.md 的「关键设计决策」段与 PROMPT.md 的「已决」段(/start 轮通常已写好,直接摘)。清单为空就省略 prompt 里那一段。
- 迭代中追加:reviewer 若又质疑了某个已定决策,先跟用户确认这条确属已定(除非本轮对话里人类已拍板过),确认后追加进下轮的 prompt。不要自己替用户否决 reviewer 的意见。
拿到 finding 后进 Step 6 分诊。
Step 5:降级链
优先级:委派子 agent 跑 /code-review > 主会话直跑 /code-review <档位> > 本会话自审 > 不 review(禁止)。
-
委派失败(子 agent 起不来 / 跑不起 /code-review / 返回的不是 finding 列表)→ 退回主会话直跑同档位 /code-review,并告知用户「本次 review 未走委派,主 context 会因此增大」。硬规则一(显式传档位)在任何降级下都不放松。
-
/code-review 本身不可用(命令缺失 / 报错)→ 停下告知用户一声「/code-review 不可用,本次降级为本会话自审(未经把关,盲区大)」,然后在当前会话内对整树 diff 做一遍自审——逐处改动核对正确性 / 逻辑 / 边界 / 并发 / 资源管理,需要时翻阅相关未改文件,列出问题。结果顶部显著标注:
⚠ 本次为本会话自审(未经任何 review 把关),盲区大——同一个脑子审自己写的代码,难复现问题极易漏判。
-
绝不静默跳过。
然后进 Step 6。
Step 6:分诊 + 运行验证 + 迭代收敛
收敛 = 三要素并闸(见「loop 是什么」段):(A) 运行验证通过 + (B) 无高置信 correctness finding + (C) 已定前提未被重复质疑。分诊时先跑 (A) 再看 (B)——先确认基础功能没被上一轮修废。
6.1 分诊 reviewer finding(闸 B / 闸 C)
按置信 + 是否真会出错分诊,不看 P 级数字。三条出口:
- 高置信 correctness finding(附
file:line 证据 + 高置信真会在生产触发的正确性 / 逻辑 / 安全问题,含被标 P2 的)→ 未收敛,进 6.2 修复。
- 命中「已定设计前提」(实质在质疑一个人类已拍板的决策)→ 不算 bug、不阻断、不计入迭代轮数(闸 C)。把该前提补进下轮委派 prompt。如前所述,拿不准是否真属「已定」时问用户,不要自己替用户否决 reviewer。
- 低置信 / 无证据 / pre-existing / pedantic / 纯风格 / 可选优化 → 闸 B 通过,不阻断(顺手能改的轻量项可改,不强制、不计入迭代)。
这一层是防「无限挑刺」的最后一道闸:reviewer 若报了无 file:line 证据、或明显推测式的项,本 skill 直接判为「不阻断」丢弃,不修、不因它继续迭代。
6.2 自动修复(不停下逐条等用户确认——人工把关前移到 /finish)
修复按问题性质分流(呼应宪法 TDD 章「适用范围 + 例外」):
- 有清晰输入输出契约的代码类问题(业务逻辑 / 纯函数 / 算法 / 并发)→ 走 TDD 正序,不许先改实现再补测试:① 先写一个能复现该 bug 的最小测试、跑它、确认它在当前未修实现下失败(红)——写不出会红的测试,说明还没真正理解这个 bug,先别动实现;② 只改相关代码让红变绿;③ 跑该测试确认绿。⚠ 防假绿硬规则:补写的测试必须先在旧(未修)实现上验证为红——旧实现上就绿的测试是假绿,证明不了它抓得住 bug(宪法「避免先画靶子后射箭」)。
- 纯风格 / 机械修复,或 bug 本质无法用测试复现(纯 UI / 视觉,或改的就是指令 / 文档本身——如本 skill、宪法、README)→ 无红测试可写,直接改。
- 修复纪律:只改与本次改动相关的代码,绝不顺手动无关文件。
6.3 运行验证子步(闸 A)——每轮修完必跑
修完后、复审前,必须真正运行代码确认基础功能没坏(reviewer 只读不跑、发现不了这层):
- 有对应测试 → 必跑、失败阻断:探测项目类型跑受影响测试(沿用
/commit 的探测:Python+uv uv run pytest、Node npm test、Rust cargo test、Go go test ./...;跑受影响子集即可,无法精准定位则跑全量)。失败 → 未收敛,回 6.2 修(失败本身就是一条高置信 correctness 问题)。
- 被改代码是编排器 / facade 却无 happy-path integration test → 先补一条再放行:判据见
rules/python.md §3.7(__init__ 收外部资源 + 有 run / execute / process 主入口 + 调 3+ 模块)。补一条最小 fixture 端到端跑主入口、只验「跑通不报错」(抓 missing import / 参数顺序 / self.X 没初始化等装配错误——正是「审废基础功能」的典型形态)。
- 无运行时面 → 闸 A 判 N/A 跳过:纯文档 / 指令规则文件(本 skill、宪法、
rules/*、README)没有可运行的代码单元,运行验证不适用,跳过本子步(但这类仍走闸 B 的置信 review)。项目无任何测试框架且改动非编排器时同样 N/A,但若改动含业务逻辑,应按 TDD 章补最小测试而非直接跳过。
闸 A 与 lint 的分工:lint(/commit 第 5 步)只证明静态无错、证明不了行为未回归;闸 A 真正跑起来验证基础功能。二者不可互替,尤其复杂 / 并发改动。
6.4 复审收敛
修复 + 运行验证通过后回到 Step 1 重跑(以修复后最新工作树复审,档位沿用本轮 Step 3 的选择,不降档;只把委派 prompt 的任务收窄为「核对这几处 finding 是否已消除、修复是否引入新问题」)——抓出修复引入的新问题、确认旧问题已消。迭代直到三要素并闸全过:(A) 运行验证通过 + (B) 无高置信 correctness finding + (C) 无新的已定前提被质疑。全过 → 打印「review clean ✅」放行。
终止保护 —— 每 2 轮一个强制人工闸口(硬规则,防无限迭代烧 token):自动修复每跑满 2 轮就必须停下、交回用户,绝不自作主张跑第 3 轮。停下时把「已迭代 2 轮、每轮修了什么、当前剩余问题、当前 diff」摆给用户,由用户拍板下一步:
- 继续 → 再获授权跑至多 2 轮,满 2 轮再次强制停下问(如此每 2 轮一闸,永不自动突破);
- 就此放行 → 带标注提交(剩余项归 TODO);
- 降级自审后放行 / 人工接手 / 放弃本次 review → 按用户选择。
为什么是硬闸而非软提示:review 对象若是「策略 / 规则类文档」(如 skill、宪法),问题空间近乎无穷、reviewer 总能再挖一个更极端的边缘场景,极易在边际收益递减处无限迭代烧光预算(本 skill 自举时就踩过——纯文档跑了近 20 轮)。置信闸(6.1)已大幅压低这类噪音——无 file:line 证据的推测式 corner case 直接判「不阻断」丢弃、不触发迭代;但硬闸仍不可省,因为「哪些边际问题值得修」终究是人的判断,而且人不该为了等 loop 收敛干坐着。故「每 2 轮必停问人」是不可绕过的硬规则:是否值得继续,只有人能判断。此外,reviewer 反复质疑已定前提的不算未收敛、不计入轮数;同类问题反复出现(振荡)或每轮全返新问题(发散)时应提前停、不必等满 2 轮。
留痕:每轮结论追加到 docs/<N>-*/REVIEW.md(报了什么 → 怎么修 → 复审结果)。非 /start 轮(无 docs 目录,如 /quick)跳过留痕。供 /finish 时用户追溯本分支的 review 迭代。
明确不做
- 不做提交动作:本 skill 只把 diff review 到 clean,
git commit 由 /commit 完成。
- 不自动引入跨模型第二意见:判定链长、触发率近零、维护面外溢到四个文件。需要时人工手动引入(见「已知局限」)。
- 不做敏感文件隔离:委派的子 agent 与主会话处在同一信任边界——同为本机 CC 进程、能读的文件完全一样、受同一套权限设置约束,故不额外加「禁读
.env*」之类的指令(那只在把 diff 交给外部模型进程时才有意义)。真正的保证仍是「绝密内容不落工作树明文」。
- 不做「每次 stop 都触发」:loop 由「commit 前触发」界定边界,收敛即停。