教程概述
系列索引: gstack 教程系列
/review 发现能通过 CI 但在生产环境中爆炸的 bug。/codex 从 OpenAI 模型添加独立的第二意见。
你将学到
- ✅
/review哲学和自动修复机制 - ✅ 审查就绪仪表板
- ✅
/codex第二意见的三种模式 - ✅ 两者运行时的跨模型分析
- ✅ 用 ASK vs AUTO-FIX 发现竞态条件
为什么需要工程师级别的审查?
CI 不够用
测试通过。Lint 通过。类型检查通过。但:
flowchart LR
A[CI 通过] --> B[部署]
B --> C[生产 Bug]
C --> D[用户影响]
style C fill:#ffcccc
style D fill:#ffcccc
/review 捕获 CI 遗漏的
flowchart TD
A[/review] --> B[逻辑分析]
B --> C[边界情况]
C --> D[竞态条件]
D --> E[错误路径]
E --> F[完整性检查]
F --> G[修复或标记]
style A fill:#e1f5ff
style G fill:#e8f5e9
它发现什么:
- 异步操作之间的竞态条件
- Promise 链中缺失的错误处理
- 不完整的重构(旧代码仍然存在)
- 状态突变 bug
- 不可达的代码路径
- 业务规则中的逻辑错误
/review — 工程师级别分析
工作原理
- 读取所有更改的文件 — 全上下文,不只是 diff
- 分析逻辑流 — 跟随代码路径,不是语法
- 检查完整性 — 实现完整吗?
- 发现 bug — 实际的 bug,不是风格挑剔
- 自动修复明显问题 — 或标记给人类决策
使用
/review
输出:
正在审查 5 个更改的文件...
┌─────────────────────────────────────────────────────────────┐
│ 审查发现 │
├─────────────────────────────────────────────────────────────┤
│ 🔴 高: src/auth/login.ts:42 中的竞态条件 │
│ - Promise 链未 await,状态可能突变 │
│ - AUTO-FIX: 已添加 await 并重新排序操作 │
│ │
│ 🟡 中: src/api/users.ts:78 中的不完整重构 │
│ - 旧的 getUserById() 仍被调用,新的 getUser() 未使用 │
│ - ASK: 我应该删除已废弃的函数吗? │
│ │
│ 🟢 低: src/utils/format.ts:15 中的不可达代码 │
│ - 早期 return 跳过验证块 │
│ - AUTO-FIX: 已删除不可达块 │
└─────────────────────────────────────────────────────────────┘
3 个发现: 1 AUTO-FIXED, 1 ASK, 1 AUTO-FIXED
审查完成。已应用 2 个修复。
AUTO-FIX vs ASK
| 类别 | 操作 | 示例 |
|---|---|---|
| 简单 bug | AUTO-FIX | 缺失 await,不可达代码 |
| 缺失验证 | AUTO-FIX | 添加空检查,类型守卫 |
| 已废弃代码 | ASK | 删除旧函数? |
| 业务逻辑 | ASK | 这应该抛出还是返回 null? |
| 架构变更 | ASK | 重构为新模式? |
审查就绪仪表板
显示已运行的审查:
┌────────────────────────────────────────────┐
│ 审查就绪状态 │
├────────────────────────────────────────────┤
│ ✅ /review: 通过 (3 个发现,全部修复) │
│ ⏳ /codex: 未运行 │
│ ⏳ /qa: 未运行 │
│ ⏳ /cso: 未运行 │
├────────────────────────────────────────────┤
│ 准备好 /ship? 否 │
│ 缺失: /qa │
└────────────────────────────────────────────┘
/codex — 跨模型第二意见
为什么用另一个模型?
不同模型有不同的盲点:
flowchart TD
A[代码变更] --> B[/review Claude]
A --> C[/codex OpenAI]
B --> D[Claude 发现]
C --> E[OpenAI 发现]
D --> F[跨模型综合]
E --> F
F --> G[组合信心]
style F fill:#e1f5ff
style G fill:#e8f5e9
三种模式
| 模式 | 用途 | 输出 |
|---|---|---|
review |
通过/失败门 | APPROVED 或 CHANGES_REQUIRED |
adversarial |
挑战代码 | 具体攻击场景 |
consultation |
询问具体问题 | 针对性分析 |
使用
# 审查模式(默认)
/codex
# 对抗性挑战
/codex --mode adversarial
# 带具体问题的咨询
/codex --mode consultation --questions "这个认证流程安全吗?"
审查模式输出:
正在 Codex 上审查 5 个文件...
┌─────────────────────────────────────────────────────────────┐
│ CODEX 审查 │
├─────────────────────────────────────────────────────────────┤
│ ✅ APPROVED │
│ │
│ 备注: │
│ - 认证流程稳健,无计时攻击 │
│ - API 错误处理完整 │
│ - 一个小建议:给登录添加速率限制 │
│ │
│ 信心度: 8/10 │
└─────────────────────────────────────────────────────────────┘
对抗性模式输出:
正在运行 Codex 对抗性挑战...
┌─────────────────────────────────────────────────────────────┐
│ 对抗性挑战 │
├─────────────────────────────────────────────────────────────┤
│ 🎯 攻击 1: 并发登录中的竞态条件 │
│ - 两个使用相同邮箱的请求可能创建重复 │
│ - 修复: 添加互斥锁或数据库唯一约束 │
│ │
│ 🎯 攻击 2: Token 重放攻击 │
│ - 密码更改时旧 token 未失效 │
│ - 修复: 密码重置时使所有会话失效 │
│ │
│ 🎯 攻击 3: 通过分布式 IP 的暴力破解 │
│ - 无用户级别速率限制,只有 IP 级别 │
│ - 修复: 添加用户级别速率限制 │
└─────────────────────────────────────────────────────────────┘
发现 3 个攻击向量。审查安全态势。
跨模型分析
当两者都运行时
如果 /review 和 /codex 都已运行,gstack 会综合:
┌─────────────────────────────────────────────────────────────┐
│ 跨模型综合 │
├─────────────────────────────────────────────────────────────┤
│ Claude (/review) 发现: │
│ - login.ts:42 中的竞态条件 │
│ - users.ts:78 中的不完整重构 │
│ │
│ OpenAI (/codex) 发现: │
│ - Token 重放漏洞 │
│ - 缺失速率限制 │
│ │
│ 重叠: │
│ - 两者都标记了 login.ts 竞态条件 │
│ → 高信心:这是真实的 bug │
│ │
│ 独特: │
│ - Claude: 不完整重构(内部质量) │
│ - Codex: Token 重放(安全) │
│ │
│ 建议: │
│ 修复所有发现。跨模型重叠表明 │
│ 高严重性问题。 │
└─────────────────────────────────────────────────────────────┘
信心评分
| 场景 | 信心 | 操作 |
|---|---|---|
| 两者都发现 | 9/10 | 立即修复 |
| 一个发现,另一个批准 | 6/10 | 手动审查 |
| 两者都批准 | 9/10 | 继续发布 |
| 两者发现不同问题 | 7/10 | 修复两者,重新审查 |
示例:发现竞态条件
场景
异步登录流程的代码变更:
// src/auth/login.ts
async function login(email: string) {
const user = await getUser(email);
setSession(user); // 没有 await!
return generateToken(user);
}
/review 分析
正在分析 login.ts...
┌─────────────────────────────────────────────────────────────┐
│ 检测到竞态条件 │
├─────────────────────────────────────────────────────────────┤
│ 位置: login.ts:24 │
│ │
│ 问题: │
│ setSession(user) 未被 await,但依赖于 │
│ getUser(email) 完成。如果 generateToken() 在 │
│ session 设置完成前被调用,认证状态不一致。 │
│ │
│ 利用方式: │
│ 1. 用户登录 │
│ 2. generateToken 在 setSession 完成前返回 │
│ 3. 第一次请求认证检查失败 │
│ 4. 第二次请求成功(竞态以不同方式获胜) │
│ │
│ AUTO-FIX: │
│ await setSession(user); │
│ │
│ ✅ 已应用修复 │
└─────────────────────────────────────────────────────────────┘
ASK 处理
当 /review 发现无法自动修复的问题:
┌─────────────────────────────────────────────────────────────┐
│ ASK: 业务逻辑决策 │
├─────────────────────────────────────────────────────────────┤
│ 位置: users.ts:78 │
│ │
│ 旧代码: │
│ export async function getUserById(id: string) { │
│ return db.users.findUnique({ where: { id } }); │
│ } │
│ │
│ 新代码已添加: │
│ export async function getUser(id: string) { │
│ return db.users.findUnique({ where: { id } }); │
│ } │
│ │
│ 问题: │
│ 两个函数都存在。getUserById 被调用 12 次。 │
│ getUser 从未被调用。 │
│ │
│ 我应该: │
│ [A] 删除 getUserById,用 getUser 替换调用 │
│ [B] 保留两者,标记 getUserById 为已废弃 │
│ [C] 只保留 getUserById,删除未使用的 getUser │
│ │
│ 输入你的选择: │
└─────────────────────────────────────────────────────────────┘
你回复 A,/review 应用重构。
审查工作流
典型序列
flowchart TD
A[代码完成] --> B[/review]
B --> C{有发现?}
C -->|是| D[修复/ASK]
D --> B
C -->|否| E[/codex]
E --> F{批准?}
F -->|否| G[处理关注点]
G --> B
F -->|是| H[/qa]
H --> I[/ship]
style B fill:#fff3e0
style E fill:#e8f5e9
style I fill:#e1f5ff
与 /ship 集成
/ship 在继续前检查审查就绪状态:
/ship
正在检查前置条件...
❌ 审查未完成
- /review: 通过
- /codex: 未运行(生产代码必需)
在发布前运行 /codex,或使用 /ship --skip-review
技能快速参考
| 命令 | 用途 | 模式 |
|---|---|---|
/review |
工程师级别分析 | Auto-fix + ASK |
/codex |
跨模型第二意见 | review/adversarial/consultation |
/codex --mode adversarial |
攻击场景 | 挑战代码 |
/codex --mode consultation |
具体问题 | 针对性分析 |
总结
gstack 中的代码审查提供:
- 工程师级别深度 — 逻辑分析,不只是风格
- 自动修复智能 — 修复明显 bug,询问决策
- 跨模型信心 — 两个模型,综合发现
- 审查仪表板 — 跟踪已审查内容
关键要点
- ✅ 代码变更后运行
/review - ✅ 对生产代码运行
/codex - ✅ 修复 AUTO-FIX 项目,决策 ASK 项目
- ✅ 检查跨模型综合中的重叠发现
系列导航:
- ← 上一篇: 教程 6B:多代理浏览器
- → 下一篇: 教程 8:QA 与安全
- 返回: 系列索引