跳到正文
coograph 17

深度评审

/coograph-review 是一个评审者读一遍工作树:对大多数改动来说,这个尺寸正好。/coograph-ultra-review 面向的是那种大到、或者危险到一个人读不全的改动。多个对抗式评审者,每人只问一个问题;每条发现在进入报告前都要被独立的反驳者攻击一遍;一个结论;一条停止规则。

它是刻意做成可选的。一次运行大约 100 万 token、二十分钟。改动符合条件时代理会指出它的存在,但从不擅自运行。

仅限 Claude Code:它作为保存好的工作流通过 Workflow 工具运行。在其他工具里,skill 描述的是同一套手动流程——每个维度一个 @Reviewer,然后再过一遍去反驳每条发现。

什么时候运行

小而局部的改动不需要。日常评审就够了。

在它诞生的那叠代码上——21 个 pull request,大约 176 次提交——它在常规评审已经通过之后找到了:一把被释放了两次的锁,一个去掉修复也能通过的测试,以及一个可能覆盖客户文件的队列任务。故事在博客文章里。

一次运行做什么

阶段发生什么
Scope一个侦察代理(Haiku)把 PR 或提交解析成文件和改动的行范围,并向代码图查询被改符号的调用方和导入方
Review每个维度一个评审者,在被评审的提交上读代码,返回发现:每条都带原文引用、文件:行号和一个具体的失败场景——一边是输入和状态,另一边是错误结果。没有引用,就不算发现。
Verify每条 Critical 和 Warning 都交给视角各异的反驳者:引用的那行存在吗、真的做了声明里说的事吗;场景真的会发生吗,还是有守卫拦住了它;有没有现成测试与这个解读矛盾。只有没人能反驳,发现才算成立。
Report一份 Markdown 报告:每个提交的 Critical / Warning / Nit、后续项、已验证无误的部分、缺失的测试、被反驳的发现及理由,以及一个结论。页脚写着模式、代理数和 token 数。

默认维度是通用的:状态、生命周期与并发;数据丢失与破坏性路径;契约与兼容性;怎么都能通过的测试。项目可以用 dimensions 传自己的。

落在提交改动行内的发现是阻塞项。落在相邻的、原有代码里的发现是后续项:报告、记录,但从不作为阻塞理由,也从不循环。只有阻塞项才会让结论变成 REQUEST_CHANGES。

模式

模式什么时候评审者视角成本(实测)
full对一个 PR 或一批提交的第一次评审,以及所有修复到位后对整个 PR 的那一次(pr: N)4 个,用会话模型,代码图提供影响范围2(Opus,高强度)120 万–160 万 token,17–22 分钟;33 个提交的 PR:310 万,39 分钟
deltafull 之后的一批修复:上次的发现修好了吗,改动的行又弄坏了什么2 个,用 Sonnet,不查影响范围1约 50 万,约 17 分钟
plan在写会碰生命周期或并发的代码之前2 个,用会话模型,读方案文本以及它点名的代码和调用方1100 万–140 万,约 20 分钟——和一次完整运行一样贵;值,因为它在代码存在之前运行

mode 会自动推断:给了 plan 就是 plan,给了 previous 就是 delta,否则是 full。

怎么运行

skill 先在对话里确定范围,为这次运行提出模型方案——项目的 openspec/config.yaml 里有 models 块就读它,否则用该模式的默认值——然后先问你再开始。接着:

Workflow scriptPath: "<absolute path to the project>/.github/skills/coograph-ultra-review/workflow.js"
args: {"repo": "<absolute path to the project>", "pr": 364}
args: {"repo": "...", "commits": ["c78bdd7", "f04a228"]}
args: {"repo": "...", "commits": ["3d6046a8"], "previous": [{"severity": "critical", "file": "app/Jobs/X.php", "line": 105, "claim": "...", "fix": "..."}]}
args: {"repo": "...", "plan": "<the plan text>", "files": ["app/Jobs/X.php"]}
参数含义
repo仓库的绝对路径——必填
pr / commits评审什么:一个 pull request 编号,或提交哈希(最新的放最后)。堆叠的 PR:只看它自己的提交,不看基底的
previousdelta 模式:上次运行的 findings(file、line、claim、fix、severity)
plan、filesplan 模式:方案文本(或评审者能读到的路径)和它点名的文件
models{scout, reviewer, verifier, report, post},别名 haiku、sonnet、opus、inherit(会话模型)
dimensions替换该模式的默认维度:字符串,或 {key, title, questions}
votes3 表示加第三个验证视角(现有测试覆盖);full 默认 2,其他默认 1
allowCommands允许评审者运行的项目只读检查(go vet ./...、linter)。测试套件、构建、格式化和服务器一律不许
post配合 pr,把报告作为 PR 评审评论发出——只在用户明确要求时

结果包含 verdict、report(Markdown)、findings(阻塞项——也是下一次 delta 运行要喂回去的 previous)、followups、previous_status(delta)、dropped(被反驳的,带理由)、nits、agents、tokens。

每个评审者都在同一份约束下工作:git 只读;代码图优先,grep 兜底;项目约定,以及使用 OpenSpec 时当前变更的 proposal、spec 和 tasks;每条引用背后都是在被评审提交上的一次新读取;除 allowCommands 外什么都不运行。

停止规则

用它的第一周,一个修复跑了四次完整运行,大约 500 万 token,每一轮都在上一轮的代码边缘找到真问题——大多落在改动根本没碰的行里。工具每次都对;错的是循环。于是:

  1. 运行之后 git status 不能出现任何新东西。出现了就是某个评审者违反了约束:撤销它。
  2. 在拥有那段代码的分支上修阻塞项(delta 模式下还包括任何未确认修好的上次发现),发现点名了测试的就补测试。
  3. 后续项不循环。记进变更的笔记和 PR 描述。只有当它是这次改动才让它可达的 Critical 时才顺手修,并且说明。
  4. 带着上次的 findings 以 delta 模式重跑。结论是 APPROVE 就停。最多两轮 delta,到了也停,把 PR 交给人:同样几行上出现第三轮机器发现,说明需要看的是设计而不是代码——下次先跑 plan。
  5. 所有修复到位后,用 pr: N 对整个 PR 跑一次 full,然后交给人评审。
  6. 记录每一轮——模式、代理数、token 数、发现 → 修复 → 提交——并把报告表格贴进 PR 描述。

被反驳的发现留在报告里,附反驳者的理由。要读;反驳者也会错,人不同意就重新打开它。

它在哪

.github/skills/coograph-ultra-review/——SKILL.md 和 workflow.js,基于 Workflow 工具 API 的普通 JavaScript。初始化器把它复制进每个项目;同步脚本保持它最新;插件以 /coograph:coograph-ultra-review 的形式提供。Retro 的 defect 规则把一次深度评审算作一次评审。它在 Plan → Propose → Apply → Review → Archive 中的位置见工作流。