名称: phx:challenge 描述: 挑战模式审查 - 在批准更改之前进行严格质疑,确保 Ecto 更改、LiveView 事件或 PR 准备就绪。当您想要对 Ecto 更改、LiveView 事件或 PR 准备情况进行彻底审查时使用。 参数提示: ecto | liveview | pr
挑战模式审查
受 Boris Cherny 的“拷问我”方法启发的严格、批判性审查模式。超越初始解决方案,确保质量。
铁律 - 绝不违反这些
- 未经验证不批准 - 在所有问题解决之前不要批准
- 假设存在错误 - 查找边缘情况、竞态条件、缺失处理程序
- 质疑一切 - 即使是“明显”的代码也可能隐藏问题
- 要求证据 - 请求测试、展示状态转换、验证行为
对抗性视角(适用于所有模式)
在深入模式特定检查之前,应用这三个视角:
- “什么会破坏这个?” — 描述代码在负载下、部署期间、意外数据情况下失败的现实场景。不是边缘情况——生产故障模式。
- “假设压力测试” — 列出代码依赖的每个假设。哪些最脆弱?(例如,“假设用户始终有电子邮件”、“假设此查询返回 < 1000 行”)
- “矛盾查找器” — 查找测试与实现、文档与行为或更改集不同部分之间的矛盾。
挑战模式
Ecto 挑战 (/phx:challenge ecto)
对开发者的数据库更改进行拷问:
迁移安全
- 此迁移会在生产中锁定表吗?
- 没有新字段的现有记录会发生什么?
- 迁移可逆吗?
- 有任何不安全操作吗(列移除、类型更改)?
查询性能
- 您引入了任何 N+1 查询吗?
- 新的 WHERE 子句缺少索引吗?
- 此查询会随数据增长而扩展吗?
模式完整性
- 所有约束在数据库级别都强制执行了吗?
- 在滚动部署期间会发生什么(旧代码、新架构)?
- 外键级联正确吗?
向后兼容性
- 在部署期间,旧代码会工作吗?
- 上下文 API 有任何破坏性更改吗?
LiveView 挑战 (/phx:challenge liveview)
证明 LiveView 处理所有情况:
事件覆盖
- 列出每个
handle_event子句和预期的套接字状态 - 如果事件触发时套接字分配缺失,会发生什么?
- 用户事件和服务器推送之间存在竞态条件吗?
PubSub 处理
- 列出每个
handle_info子句及其触发时间 - 所有 PubSub 订阅都有相应的处理程序吗?
- 如果消息在挂载完成前到达,会发生什么?
状态转换
- 展示事件 → 处理程序 → 状态转换表
- 所有错误状态都优雅处理了吗?
- 每个错误状态的恢复路径是什么?
内存与性能
- 大列表使用流吗?
- 临时数据使用 temporary_assigns 吗?
- 每个连接用户的内存占用是多少?
PR 挑战 (/phx:challenge pr)
高级工程师审查清单:
必须通过
- [ ] 控制器/LiveViews 中没有直接 Repo 调用
- [ ] 所有 Ecto 查询使用显式预加载
- [ ] 更改集验证所有用户输入
- [ ] 没有从参数创建原子
- [ ] 错误情况已处理(不仅仅是快乐路径)
- [ ] 测试覆盖新功能
性能
- [ ] Enum.map 循环中没有查询
- [ ] 列表 > 100 项的 LiveView 流
- [ ] WHERE 子句列存在索引
OTP
- [ ] GenServers 有监督
- [ ] GenServer.call 设置超时
- [ ] 没有无限进程生成
安全
- [ ] 没有通过原始查询进行 SQL 注入
- [ ] 文件处理中没有路径遍历
- [ ] 存在授权检查
先前发现去重
在运行挑战之前,检查先前审查输出:
- 搜索 在
.claude/plans/*/reviews/和.claude/reviews/中的现有审查 - 如果先前发现存在,先阅读它们
- 在您的挑战输出中,将每个发现分类为:
- 新发现 — 在任何先前审查中未找到
- 持续存在 — 先前发现过且仍然存在(未修复)
- 回归 — 已修复但重新引入
- 不要重新标记已修复问题 — 如果先前审查标记了某些内容,且代码现在已解决,跳过它
- 关注新问题 — 投入大部分精力在先前审查中未找到的发现上
呈现结果时,先显示新发现,然后是持续存在(附注“先前已标记”),最后是回归。这防止了“3 次挑战清理”问题,即相同问题被重新发现。
使用方式
运行 /phx:challenge [模式] 启动严格审查。审查者在所有问题通过证据解决之前不会批准。
示例工作流程:
- 在迁移更改后运行
/phx:challenge ecto - 用代码引用或测试结果回答每个问题
- 在继续到 PR 之前解决所有问题