# Code Review

> 从固定点（commit、branch、tag 或 merge-base）开始，沿两条轴线审查变更——规范（代码是否遵循仓库文档化的编码规范？）和规格（代码是否与原始 issue/PRD 的要求一致？）。两条审查线在并行子 agent 中运行，并以并排方式报告结果。当用户想审查一个分支、PR、进行中的变更，或要求"从 X 开始审查"时使用。

- Skill: `devcxl/code-review` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add devcxl/code-review`
- Raw SKILL.md: https://api.skillmd.com/api/skills/devcxl/code-review/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Product & Planning
- Author: devcxl (https://skillmd.com/u/devcxl)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/devcxl/code-review

---


# 审查

对 `HEAD` 与用户指定的固定点之间的 diff 进行双轴审查：

- **规范**——代码是否符合本仓库文档化的编码规范？
- **规格**——代码是否忠实地实现了原始 issue / PRD / 规格？

两条轴线作为**并行子 agent** 运行，互不污染彼此的上下文，然后由本技能汇总双方的发现。

Issue 跟踪器应该已经提供给你了。如果 `docs/agents/issue-tracker.md` 缺失，请告诉用户运行 `/setup-matt-pocock-skills`。

## 流程

### 1. 确定固定点

用户说的任何东西都可以作为固定点——commit SHA、分支名、tag、`main`、`HEAD~5` 等等。不要随意发挥，直接传入即可。如果用户没有指定，则询问："以什么为基准进行审查——一个分支、一个 commit、还是 `main`？" 没有得到答案之前不要继续。

捕获 diff 命令：`git diff <fixed-point>...HEAD`（三个点，这样比较的是 merge-base）。同时通过 `git log <fixed-point>..HEAD --oneline` 记录 commit 列表。

在继续之前，确认固定点能解析（`git rev-parse <fixed-point>`）且 diff 非空。错误的引用或空的 diff 应该在此处失败——不应该让两个并行子 agent 来处理。

### 2. 确定规格来源

按以下顺序查找原始规格：

1. commit 消息中的 issue 引用（`#123`、`Closes #45`、GitLab `!67` 等）——按照 `docs/agents/issue-tracker.md` 中的工作流来获取。
2. 用户作为参数传入的路径。
3. `docs/`、`specs/` 或 `.scratch/` 下与分支名或功能名匹配的 PRD/规格文件。
4. 如果什么都没找到，询问用户规格在哪里。如果用户说没有，**规格**子 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 prompt**——包含：

- 完整的 diff 命令和 commit 列表。
- 你在步骤 3 中找到的规范来源文件列表，**加上步骤 3 中的气味基线**（完整粘贴——子 agent 没有其他途径获取它）。
- 任务简述："报告——按文件/hunk 列出——(a) diff 中每一处违反文档化规范的地方：引用规范（文件 + 规则）；以及 (b) 你发现的任何基线气味：命名并引用 hunk。区分硬性违规和判断性差异——文档化规范的违规可以是硬性的，但基线气味始终是判断性问题，且已文档化的仓库标准覆盖基线。跳过工具已强制执行的内容。400 字以内。"

**规格子 agent prompt**——包含：

- diff 命令和 commit 列表。
- 规格文件的路径或获取到的内容。
- 任务简述："报告：(a) 规格要求但缺失或不完整的需求；(b) diff 中存在但规格未要求的行为（范围蔓延）；(c) 看起来已实现但实现可能错误的需求。每一项都引用规格原文。400 字以内。"

如果规格缺失，跳过规格子 agent，并在最终报告中注明。

### 5. 汇总

在 `## 规范` 和 `## 规格` 标题下呈现两份报告，可以原文呈现或稍作整理。**不要**合并或重新排序发现项——两条轴线刻意分开（参见《为什么要分两条轴线》）。

结尾附一行总结：每条轴线上发现项的总数，以及每条轴线内最严重的单项问题（如果有的话）。不要跨轴线选一个最终获胜者——那正是拆分要防止的重新排序。

## 为什么要分两条轴线

一项变更可能通过一条轴线的审查而不通过另一条：

- 代码遵循了所有规范但实现了错误的功能 → **规范通过，规格失败。**
- 代码完全按 issue 要求实现但违反了项目约定 → **规格通过，规范失败。**

分别报告可以防止一条轴线掩盖另一条轴线。

