让 Codex 当反方:把重试风险问到可验证
给一个写入接口补上超时重试,代码可能只多出一个循环。假设单元测试已经覆盖“第一次请求超时,第二次成功”,普通审查也没有留下待处理问题。上线前还有一个值得追问的问题:第一次请求,究竟是没有执行,还是执行成功后响应丢了?
这不是某次线上事故的复盘,而是一个教学情境。它用来说明 /codex:adversarial-review 应该追问到哪里:从“这里可能重复写入”,追到具体请求如何穿过失败路径、哪个业务约束会被破坏,以及怎样验证这条怀疑。
反方角色可以帮助组织这样的审查,但命令名本身不能证明它比普通审查更准确。普通审查也能发现设计和并发问题。我们需要的是可辩护的发现,而不是让第二个模型努力说出更多反对话。
超时之后,重试的可能是一件已经完成的事
先把情境限定清楚:一个 Agent 的工具函数向业务服务提交“创建工单”请求;调用方超时后重新发送。假定当前实现每次发送都生成新的请求标识,服务端按这个标识识别重复请求。这里不讨论真实厂商接口,也不宣称已运行实验。
在这个假定实现中,下列时间线足以暴露问题:
| 时刻 | 业务服务 | 调用方看到的状态 |
|---|---|---|
| 第一次发送 | 按标识 A 创建工单 | 正在等待响应 |
| 响应丢失 | 工单已经存在 | 超时,结果未知 |
| 第二次发送 | 收到新的标识 B,按新请求创建 | 返回成功 |
错误不是重试次数不够保守,而是把“没有收到成功响应”当成了“没有产生业务效果”。如果服务端确实把 A、B 当成两个不同请求,第二次发送就可能创建第二张工单。
这个反例还有一个反方向的用途:如果真实代码在重试循环外生成稳定的业务操作标识,并且服务端会原子地复用已完成结果,以上路径可能已经被阻断。不能只看见一个重试循环,就给它贴上“缺少幂等性”的标签。需要检查标识的生命周期、服务端判重条件以及效果与结果记录的提交方式。
这也解释了为什么只补一个“超时后成功”的测试不够。若测试替身把第一次超时实现成“什么都没做就抛异常”,它没有覆盖“效果已完成但响应丢失”。两种情况对调用方都表现为超时,对业务却不同。
真正有用的反方意见,应指出这两个状态被哪段实现合并了;如果尚未看到服务端逻辑,就应把缺失证据说出来。
官方提示词同时要求怀疑与举证
在本次核对的 codex-plugin-cc v1.0.6 源码中,反方审查要求模型主动寻找足以阻止变更交付的实质问题,同时约束发现必须能由仓库上下文或工具输出支持。它禁止编造文件、行号、事故和无法支持的运行行为;依赖推断时,要明确指出。提示词还有一句很实用的校准要求:Prefer one strong finding over several weak ones.。官方提示词
把这两部分连起来看,才能正确理解“让 Codex 当反方”。它可以先尝试推翻你的信心,但最后留下来的必须是有根据的问题。不存在可支撑的实质发现时,官方模板允许直接给出无发现的结果,而不是为了扮演反方凑够几条意见。
对于前面的工单例子,一句“分布式系统会失败,建议增加消息队列”还不能成为发现。它没有证明当前失败路径,也没有解释引入队列怎样消除重复创建。
较有用的审查内容应该说明:重试路径重新生成标识;服务端按该标识区分操作;首次效果提交但响应丢失后,第二个标识会被当成新操作。若其中一环尚无证据,就将结论限制在已看到的代码,不把假设写成系统事实。
这里的价值来自因果链,而不是语气更强硬。把“必须重构”改成“高置信度风险”,也不会自动补齐缺失的依据。
它仍然返回 findings,不是另一套泛化意见
实现层面,这条命令收集选定范围的仓库上下文,将目标和用户 focus 填入专用提示词,再通过 App Server 发起使用 read-only 沙箱和输出 schema 的调用。这是对该版本运行路径的静态核对,不是本文实际运行插件的证明。运行时实现
官方 schema 的核心字段如下。这里只摘录字段和允许值,不是一份模型实测输出:
verdict: approve | needs-attention
summary
findings[]:
severity, title, body
file, line_start, line_end
confidence, recommendation
next_steps[]
每条发现仍要绑定文件、行号、置信度和具体建议;结论的枚举是 approve 与 needs-attention,并不是 Ship / Hold / Redesign。团队可以另设人工决策用语,但不应把自定义用语说成插件协议。官方输出 schema
结构化字段只保证一种表达约束,不能保证行号正确、推理成立或置信度经过统计校准。面对工单重复创建的发现,仍需打开对应代码,核对它指向的是操作标识生成处、重试入口,还是与问题无关的一行。
同样,approve 的含义是这次上下文中没有支撑得住的实质反方发现。它不是“所有失败状态已验证”,也不会替人批准合并。命令文件明确把这条命令限定为审查,不修复或应用补丁。命令约束
把 focus 写成要查证的失败路径
如果准备审当前工作区中这次工单重试的实现,可以这样指定范围和关注点:
/codex:adversarial-review --wait --scope working-tree 检查创建工单在服务端已完成但响应丢失后的重试路径。追踪同一业务操作的标识是否跨重试保持一致、服务端如何识别重复请求。只报告有代码依据的实质风险;缺少服务端上下文时明确指出。
这段 focus 是作者建议,不是官方提示词的逐字引用,也不是已执行成功的记录。它同时给出了事件顺序、要保持的业务约束和证据不足时的处理方式。读者应替换成自己仓库真实的接口与语义;纯查询接口和产生业务效果的写入接口,不必承担相同的判断。
该版本支持 auto、working-tree、branch 范围和 --base <ref>,但不支持 --scope staged 或 --scope unstaged。因此,上面的例子不能读成“只审暂存内容”。--wait 指定前台等待,--background 指定后台执行;切换执行方式不会自动改变要核对的业务问题。普通 /codex:review 在该版本不接受附加 focus,针对性的焦点文字应交给反方命令。命令参数 · 普通审查命令
scope 决定模型从哪里找依据,focus 决定优先追问什么。两者不能互相替代。如果服务端代码在另一个仓库,只加一句“检查服务端幂等性”不会凭空补出证据。应补充可核对的接口约定和实现,或者明确保留这个证据缺口。
对于尚未落成代码的设计讨论,可以沿用这种提问方式;但不要把它冒充为已经完成的代码审查。该命令的发现格式绑定代码位置,空范围也不是设计材料自动送达的证明。
收到发现后,先验证它要推翻的那一个假设
对工单例子,可以把一条发现整理为下面这份人工验证记录。它是本文的主要交付物,属于待填写的实验设计,没有预填任何“通过”结果:
要检验的假设:同一业务操作重试不会再创建一张工单。
代码依据:填写实际文件、行号、操作标识生成位置与服务端判重依据。
故障注入:第一次业务效果提交后,让响应丢失;随后触发调用方重试。
观察结果:该业务操作对应的工单数量、每次请求标识、两次返回或异常。
验收条件:最终只存在一张工单,重试返回可关联到同一操作的结果。
反证条件:若现有实现已满足上述条件,撤销或缩小“重复创建”发现。
未覆盖范围:并发请求、进程重启、判重记录过期需另列用例。
应在隔离测试环境里模拟这条路径。先保证测试替身确实保留了“工单已创建”的效果,再令响应失败;否则会再次退化成原来那个“什么都没发生”的超时测试。没有服务端控制权时,可以用保留状态的替身检验调用方行为,但结果只能说明替身约定下的行为,不能证明真实服务也满足该约定。
如果测试确认重复创建,修复要回到失败原因。例如让重试复用稳定操作标识,并让服务端按同一业务语义原子地判重和记录结果;只复用标识但服务端不识别它,问题仍在。若还需考虑并发或记录过期,就把它们作为明确新增的路径验证,别把一次串行重试通过写成“已经实现恰好一次”。
如果现有保护已经阻断反例,应当接受这个反证,撤销不成立的意见。不能因为用了“对抗式”命令,就不断移动标准,直到找到一个看起来足够严重的问题。
这也是我会采用的结束条件:有证据的发现进入具体修复与回归;不成立的发现记录反证后关闭;无法判断的发现保留所缺证据。反方审查的输出在这里变成工程工作,而不是一份让人更焦虑的风险清单。
本文核对的是 2026-09-18 获取的官方固定提交 db52e28f4d9ded852ab3942cea316258ae4ef346,插件 manifest 标注 v1.0.6。依据限于命令、提示词、schema 与运行时源码;工单时间线和验证记录为作者教学设计。本文没有调用该插件做模型审查,也没有故障注入实测或准确率对比。