对 HEAD 与用户提供的固定点之间的 diff 进行双维度审查:
- 规范(Standards):代码是否符合此仓库记录的编码规范?
- 规格(Spec):代码是否忠实地实现了源 Issue / 规格的要求?
两个维度作为并行子 Agent运行,以避免相互污染上下文,然后此 Skill 会汇总它们的审查发现。
Issue 跟踪器应该已提供给您。如果缺失 docs/agents/issue-tracker.md,请提示用户运行 /setup-matt-pocock-skills。
流程
1. 确定固定点
用户指定的任何固定点(提交 SHA、分支名、标签、main、HEAD~5 等)。如果他们没有指定,请主动询问。
获取一次 diff 命令:git diff <fixed-point>...HEAD(三点语法,用于与 merge-base 进行比较)。同时通过 git log <fixed-point>..HEAD --oneline 记录提交列表。
在继续之前,请确认固定点可以解析(git rev-parse <fixed-point>)且 diff 不为空。无效的引用或空的 diff 应该在此处直接失败,而不是在两个并行子 Agent 内部失败。
2. 确定规格来源
按以下顺序查找源规格:
- 提交信息中的 Issue 引用(
#123、Closes #45、GitLab!67等),通过docs/agents/issue-tracker.md中的工作流获取。 - 用户作为参数传入的路径。
docs/、specs/或.scratch/下与分支名或功能匹配的规格文件。- 如果未找到任何内容,请询问用户规格在哪里。如果他们表示没有规格,**规格(Spec)**子 Agent 将跳过并报告“无可用规格”。
3. 确定规范来源
仓库中记录了代码应如何编写的任何内容,例如 CODING_STANDARDS.md 或 CONTRIBUTING.md。
除了仓库记录的任何内容外,“规范”维度始终包含以下异味基准(smell baseline):一组固定的 Fowler 代码异味(《重构》第 3 章),即使仓库没有任何文档记录也同样适用。它受两条规则约束:
- 仓库规范优先。 仓库中记录的规范始终具有最高优先级;如果它认可了基准会标记的内容,请抑制该异味。
- 始终基于主观判断。 每种异味都是带有标签的启发式规则(例如“可能的特性依恋”),绝不是硬性违规。与此处的任何规范一样,请跳过工具已经强制执行的任何检查。
每种异味的解读方式为:它是什么 → 如何修复;将其与 diff 进行匹配:
- 神秘命名(Mysterious Name):名称无法揭示其用途或包含内容的函数、变量或类型。→ 重命名它;如果想不出坦诚贴切的名字,说明设计存在模糊之处。
- 重复代码(Duplicated Code):相同的逻辑形态出现在变更中的多个代码块(hunk)或文件中。→ 提炼共享形态,并在两处都调用它。
- 特性依恋(Feature Envy):某个方法访问另一个对象的数据多于访问自身的数据。→ 将该方法移动到它所依恋的数据所在的对象中。
- 数据泥团(Data Clumps):相同的几个字段或参数总是一起出现(渴望诞生为一个新类型)。→ 将它们绑定为一个类型并传递该类型。
- 基本类型偏执(Primitive Obsession):使用基本类型或字符串来替代本应拥有独立类型的领域概念。→ 为该概念赋予自己的小型类型。
- 重复的 switch(Repeated Switches):在整个变更中,针对相同类型反复出现相同的
switch/if级联。→ 替换为多态,或两处共享的单一映射表。 - 霰弹式修改(Shotgun Surgery):一个逻辑变更迫使在 diff 中的许多文件里进行分散的编辑。→ 将一起变化的内容整合到一个模块中。
- 发散式变化(Divergent Change):一个文件或模块因为多个不相关的原因而被编辑。→ 进行拆分,使每个模块仅因单一原因发生变化。
- 夸夸其谈未来性(Speculative Generality):为规格中不存在的需求添加了抽象、参数或钩子。→ 删除它;内联回去,直到出现真正的需求。
- 消息链(Message Chains):调用方不应依赖的过长
a.b().c().d()导航链。→ 将遍历过程隐藏在第一个对象的方法之后。 - 中间人(Middle Man):大部分工作仅是向下委托的类或函数。→ 移除它,直接调用真正的目标。
- 被拒绝的遗赠(Refused Bequest):忽略或覆盖了其继承的大部分内容的子类或实现者。→ 放弃继承,改用组合。
4. 并行生成两个子 Agent
规范子 Agent 提示词应包含:
- 完整的 diff 命令和提交列表。
- 您在步骤 3 中找到的规范来源文件列表,加上步骤 3 中的异味基准完整粘贴(子 Agent 没有其他途径获取它)。
- 任务说明:“请按文件/代码块(如适用)报告:(a) diff 中违反已记录规范的每个位置:引用该规范(文件 + 规则);以及 (b) 您发现的任何基准异味:命名它并引用相关代码块。区分硬性违规与主观判断:违反记录的规范可以是硬性的,但基准异味始终是主观判断,且仓库记录的规范优先于基准。跳过工具强制执行的任何内容。字数控制在 400 字以内。”
规格子 Agent 提示词应包含:
- diff 命令和提交列表。
- 规格的路径或获取到的内容。
- 任务说明:“请报告:(a) 规格要求但缺失或部分缺失的需求;(b) diff 中未被要求的行为(范围蔓延);(c) 看起来已实现但实现看起来有误的需求。针对每个发现引用规格行。字数控制在 400 字以内。”
如果规格缺失,跳过规格子 Agent 并在最终报告中注明。
5. 汇总
在 ## Standards 和 ## Spec 标题下展示两份报告,保持逐字展示或进行轻度润色。不要合并或重新排列审查发现的优先级,因为这两个维度是有意分开的(参见为什么采用双维度)。
以单行总结结尾:每个维度的审查发现总数,以及每个维度内最严重的问题(如果有)。不要跨维度评选出单一的“最主要问题”:这种重新排序正是我们要通过分离来避免的。
为什么采用双维度
一项变更可能在一个维度上通过,而在另一个维度上失败:
- 代码遵循了每项规范,但实现的内容完全错误 → 规范通过,规格失败。
- 代码完全符合 Issue 的要求,但破坏了项目的约定 → 规格通过,规范失败。
分别报告可以防止一个维度掩盖另一个维度。