mcpField
T
the-judge

the-judge

github.com/tech-leads-club测试与质量7.1k70 次安装3 天前更新
代码仓库

关于 the-judge

the-judge 是用于审查 GitHub 拉取请求的技能,强调证据充分、评论精简且聚焦重要问题。它涵盖检查、研究、验证、门禁校验,并将结果整合为一条审查。

主要功能

  1. 01基于证据的审查发现
  2. 02运行仓库检查与绕过扫描
  3. 03六个专项审查环节
  4. 04按严重程度确定结论
  5. 05门禁校验并整合发布

适用场景

  1. 01合并前审查拉取请求
  2. 02核实依赖或 API 相关主张
  3. 03减少低价值审查评论
  4. 04复查尚未解决的问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/tech-leads-club/agent-skills --skill the-judge

安装后在 Claude Code 中输入/the-judge确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
comment-voice.md
review-standards.md
scripts/
post_review.py
review_gate.py
scan_bypasses.py

详细介绍

The Judge

像资深工程师一样审查拉取请求,并坚持高置信度标准:评论要少,每条都必须有证据,并通过一条汇总的 GitHub 审查一次性发布。The Judge 宁可提出 3 条重要发现,也不愿列出 15 条浪费作者时间的观察。

不可妥协的原则

这些规则优先于本技能中的其他所有内容。开始前请先阅读。

  1. 有证据,否则保持沉默。 对内部内容(关于此代码库的代码)的判断,必须附上经阅读文件确认的 file:line 引用。对外部内容(关于库、API、框架、版本、弃用、安全漏洞或最佳实践)的判断,必须附上本次审查期间从官方来源获取的 URL。没有证据的发现不得发布。就是这样。
  2. 绝不凭记忆断言外部行为。 在声称依赖项、API 或框架的行为之前,先搜索当前的官方文档、变更日志或安全公告。如果研究结论不明确,就把发现降级为问题,或删除。训练数据只是传闻;变更日志才是来源。
  3. 噪声预算。 行内 nit 评论最多 5 条;超出的数量记入摘要。存在结构性问题时,不要用低价值备注刷屏。优先选择少量高置信度评论。
  4. 绝不评论代码库自身工具能发现的问题。 先运行代码库的代码检查工具、类型检查器和针对性测试(步骤 1)。这些工具报告的问题不属于审查评论的范围。
  5. 每条评论都必须通过关卡。 所有评论正文和摘要在发布前都必须通过 scripts/review_gate.py,退出码为 0。没有例外,不得手动绕过。
  6. 语言:由用户选择;默认使用英语。 如果调用中指定了语言(“用葡萄牙语审查这个 PR”、“revise em português”),就用该语言撰写完整审查,语言要地道、正确,并保留完整变音符号;绝不要使用退化的纯 ASCII 文本。未明确指定时,使用英语。无论使用何种语言,Verdict 标记(APPROVE、COMMENT、REQUEST_CHANGES)、代码标识符、引述字符串和工具输出都必须保持原样。
  7. 把 token 花在判断上。 只阅读差异、它涉及的文件,以及追踪某项发现所需的直接调用方或被调用方;切勿读取整个代码库。正则表达式能检测的问题应由 scripts/scan_bypasses.py 处理,而不是写进评论。具有确定性的发现应交给 lint 规则迭代流程,以便下一次审查耗时更少。
  8. 首次审查就是完整审查。 第 1 轮看到的所有内容都必须在第 1 轮提出,并通过一条汇总审查批量发布。禁止将发现留到后续轮次;零散发布评论会让审查陷入无休止的拉锯。重新审查用于确认问题已解决,而不是开启新战线(见 Convergence Contract)。

严重程度与结论

严重程度表情符号定义对结论的影响
blocker🔴会改变 PR 是否应当合并:数据丢失、可利用的安全问题、金额错误、身份验证失效、不可逆迁移、日志中包含 PIIREQUEST_CHANGES
should-fix🟠确实存在缺陷,但不会造成合并风险COMMENT
nit🟡轻微问题。行内评论最多 5 条;超出数量记入摘要无影响
pre-existing🟣PR 未引入的错误。仅写入摘要,绝不写成行内评论无影响

结论映射:只要存在任何 🔴,就用 REQUEST_CHANGES。没有 🔴,也没有 🟠,就用 APPROVE。其他情况用 COMMENT。

审查自己的 PR 时的回退处理: 如果你对自己的 PR 执行 APPROVE 或 REQUEST_CHANGES,GitHub 会返回 422。scripts/post_review.py 会检测 PR 作者是否与已认证的 gh 用户一致;如果一致,就以 COMMENT 发布,并在摘要末尾添加一行脚注,说明预期结论。TL;DR 已包含结论标记,因此脚注只需解释这一机制。不要试图绕过;这是 API 的行为。

工作流程

步骤 0:确定上下文
gh pr view --json number,title,body,author,url,baseRefName,headRefName,additions,deletions,changedFiles
gh api user --jq .login
gh pr diff <number>
gh pr view <number> --json files --jq '.files[].path'

将每个变更文件归类为核心或机械性(生成的代码、锁文件、快照、供应商依赖、构建产物、迁移输出)。跳过机械性文件,并在摘要中列出。检测移动的代码:如果某处删除了 3 行或更多连续代码,并在别处以相同内容添加,则这是代码移动,而非新代码;不要将其作为新代码重新审查。

确定轮次。获取此 PR 上你自己之前的审查:

gh api repos/{owner}/{repo}/pulls/{number}/reviews --jq '[.[] | select(.user.login=="<gh-login>") | {id, submitted_at, body}]'

没有之前的审查:这是第 1 轮,运行完整工作流。存在之前的审查:这是第 N 轮,从最新的之前审查摘要中加载发现记录表(ID 表),并遵循收敛契约,而不是重新完整运行。

如果核心文件中的变更行数大约超过 400 行,且运行环境支持子 Agent,则将步骤 3 的各轮审查作为并行子 Agent 运行。否则按顺序运行。绝不要将子 Agent 支持设为必需条件。

步骤 1:确定性检查

检测并运行仓库自身的检查:lint、类型检查,以及针对变更文件的测试(查看 package.json 脚本、Makefile、pyproject.toml、CI 配置)。如果仓库已在 CI 中接入安全扫描工具(依赖项、IaC 或 SAST 工具),也运行这些工具,或读取其当前输出作为确定性输入。记录结果。这些工具发现的问题不属于你的审查范围;你只判断它们无法检测的问题。如果仓库没有此类工具,请在摘要中说明,然后继续;不要安装任何工具。

然后运行确定性绕过扫描:

gh pr diff <number> | python3 scripts/scan_bypasses.py

它会输出 diff 中新增的每个绕过标记,格式为 path:line category content(抑制指令、规避测试、TLS 和类型检查绕过、吞掉错误、以休眠代替同步)。扫描命中项是第 F 轮审查的候选项,而非发现:带有理由和问题链接的抑制可以接受;没有说明的则不行。此扫描的目的,是避免消耗 LLM 令牌去检测正则表达式就能发现的问题。

步骤 2:强制调研

列出 diff 涉及的所有外部接口:新增或升级的依赖项(查看清单/锁文件 diff)、调用的 API、使用的框架特性、对版本敏感的语言特性。针对每个接口,搜索当前的官方文档、发行说明和安全公告。记录每个查阅过的 URL;摘要必须包含调研日志。这一步不可省略,也不能跳过,即使你自认为很有把握也不行。依赖记忆产生的信心,正是此步骤要消除的失败模式。如果 diff 未涉及任何外部接口,请在调研日志中说明。

步骤 3:审查轮次

**完整性约定:**第 1 轮要一次性深入审查所有轮次中的全部核心文件。不把任何内容留到“以后再看”。如果某个问题现在就能提出,却被留到之后才提出,就是违背了对作者的约定。关于评论数量有一个例外:对于结构性问题将重写的代码,不要堆叠评论;如果某条 🔴 或 🟠 评论要求重构某个代码块,就暂缓提出该代码块中的小问题,并在摘要中注明“结构性修复将改写相关代码行,因此暂缓指出小问题”。

**现在阅读 references/review-standards.md。**对核心文件进行六轮审查:

  • A 轮:正确性与逻辑:被破坏的不变量、未处理且会丢失数据的故障路径、部分状态、具体的并发隐患。
  • B 轮:安全性:仅指出高度可信、由此 PR 引入的可利用问题,并应用严格排除项和先例列表。
  • C 轮:结构与可维护性:深入审查结构。代码改造、文件大小限制、代码混乱度增长、边界、规范层。
  • D 轮:AI 生成的冗余内容与无用代码注释:复述代码的注释、变更日志式注释、冗长的文档字符串、已注释掉的代码、在可信路径上的防御性 try/catch、推测性的抽象。
  • E 轮:PR 描述中的声明:每一项“修复了 X”或“改进了 Y”的声明都需要证据(测试、复现或测量),否则应改为疑问。
  • F 轮:绕过、重复与权宜之计:抑制指令、规避测试、类型与 TLS 绕过、复制粘贴式重复、魔法值、用 sleep 同步、未标注的变通方案。以步骤 1 的绕过扫描结果为起点;此处要逐一评估每个扫描命中项。

每一轮都会产出候选问题:问题陈述、暂定严重性、证据位置。如果运行框架支持为每个子 Agent 选择模型,则机械性任务(文件分类、去重、扫描结果初筛)使用轻量快速模型,把最强的模型留给判断和验证环节;用重型模型做廉价初筛是浪费,用轻量模型做判断则会产生误报。

步骤 4:验证轮次

对于每个候选问题:重新阅读引用位置的实际代码,并确认问题确实存在。重新应用排除列表。无法举证的内容一律删除。合并不同轮次中的重复问题。保守地确定最终严重性:对尚不确定的阻断性问题,应降为“应该修复”,并以疑问句表述。之所以设置这一轮,是因为候选问题生成侧重召回率,而发布问题侧重精确率。

两条证据依据:

  • **可行时进行复现。**对于 A 轮或 B 轮中能够在本地演示的 🔴 问题,应提供最有力的证据类别:在仓库自身的测试框架中运行失败的测试或简短脚本(绝不进行网络攻击,也绝不离开检出目录的沙盒)。将命令及其输出记录为 repro 证据。反过来也同样成立:如果能够复现却未能复现所述问题,则无论代码阅读结果如何,都必须删除该问题。
  • **低风险不等于误报。**严重性与有效性是两个彼此独立的维度。真实但轻微的问题应标为 🟡,而不是直接丢弃;因为问题较小就删除,筛选器就会悄悄停止检测真实问题。证据不足时删除,影响较小时降级,绝不要混淆两者。
步骤 5:撰写评论

现在阅读 references/comment-voice.md。 按照该规范撰写摘要和每条评论正文。生成 findings.json:

{
  "language": "en",
  "round": 1,
  "carryover": {"blocker": 0, "should-fix": 0},
  "verdict": "REQUEST_CHANGES",
  "summary": "## TL;DR\n...\n## Findings\n...\n## Promote to lint rule\n...\n## Research log\n...\n## Checks run\n...\n## Skipped files\n...",
  "findings": [
    {
      "id": "F1",
      "path": "src/billing/invoice.ts",
      "line": 142,
      "severity": "blocker",
      "body": "🔴 `applyDiscount` divides by `items.length` with no empty-list guard (src/billing/invoice.ts:142)...",
      "evidence": [
        {"type": "internal", "ref": "src/billing/invoice.ts:142"},
        {"type": "external", "ref": "https://official-docs.example/api#behavior"}
      ]
    }
  ]
}

round 默认为 1。carryover 统计上一轮仍未解决的发现(第 1 轮为 0);门禁会使用它计算正确的判定结果,避免仅凭新发现列表低估未解决的风险。id 值在各轮之间保持稳定(F1 永远是 F1),以便解决情况记录表能够准确映射。证据条目接受三种类型:internal(已验证的 path:line)、external(本次审查中从官方来源获取的 https URL)和 repro(能够演示该主张的本地命令,以及发现正文中记录的实际结果)。

门禁强制执行的规则(从一开始就遵守):正文以严重性表情符号开头;阻塞项和应修复项至少需要一条证据;外部证据必须是 https URL;先前已有的发现不得包含 line;摘要必须包含 TL;DR 部分和 lint 规则部分。

步骤 6:门禁
python3 scripts/review_gate.py findings.json

修复所有报告的问题并重新运行,直到退出代码为 0。门禁的行为是确定性的;跟它争论,就等于跟正则表达式争论。

步骤 7:发布
python3 scripts/post_review.py findings.json

将所有内容作为一条审查发布(单次 API 调用:摘要正文、判定事件、定位的行内评论),处理本人 PR 的回退方案,并输出审查 URL。行内评论只能锚定在差异中存在的行上;如果 GitHub 拒绝某个锚点,脚本会告知你哪条评论发布失败。

摘要正文模板

## TL;DR
One to three sentences: what the PR does and the verdict with its reason. Must contain the verdict token (APPROVE, COMMENT, or REQUEST_CHANGES) verbatim; the gate checks for it.

## Findings
| ID | Severity | Location | Summary |
|---|---|---|---|

## Resolution (round 2+)
| ID | Status | Note |
|---|---|---|
Every previous finding appears here with status resolved (with the commit), open, or declined-accepted (author's reason held). Omit this section in round 1.

## Promote to lint rule
Findings in this review that are deterministic by nature (banned pattern, naming convention, style rule). For each: the rule, and a one-line sketch of how to lint it. Reviews should get cheaper every cycle; this section is the flywheel. Write "none" if empty.

## Research log
URLs consulted in Step 2, one per line, with the claim each one supports or refutes. Sources that refuted a candidate finding belong here too: a documented non-finding is evidence of diligence and saves a future round. Write "no external surfaces touched" if that is the case.

## Checks run
Deterministic ladder results from Step 1, verbatim numbers with no interpretation: test counts (passed/failed/skipped), linter and typechecker outcome, bypass scan candidate count.

## Skipped files
Mechanical/generated files excluded from review.

## Nit overflow
"N additional nits not posted individually" when the cap was hit. Omit otherwise.

收敛约定

Judge 会作出明确判断:让审查收敛,而不是无限拖延。第 1 轮进行全面检查;之后每一轮的范围都会缩小。此约定旨在杜绝一种失败模式:每一轮都发现新的问题,导致无休止地来回审查。

第 N 轮(N >= 2)的范围仅限以下两项:

  1. 检查解决情况。 针对上一轮记录表中的每项发现,根据新提交确认其状态:已解决(注明修复该问题的提交)、仍未解决,或作者不予采纳。所有发现都要列入解决情况表。这是重新审查的重点;它是按清单核实,而不是重新全面搜查。
  2. 仅检查新的阻塞项。 仅检查自上次审查的提交以来的差异,找出由修复本身引入的 🔴 问题。绝不报告新的 🟠、🟡 或 🟣 问题。第 1 轮已可见但当时未标出的问题,视为审查者放弃追究:漏掉了就由审查者承担。唯一例外是后来发现了确实的 🔴 问题(可被利用的安全漏洞、数据丢失、资金损失),这种问题必须始终提出,并如实标注为第 1 轮漏报。

作者不予采纳的发现。 作者说明理由并拒绝采纳时,先考虑作者可能更了解代码且判断正确;如果从代码健康角度看理由成立,就记录为 declined-accepted 并永久移除该项。如果理由不成立,最多基于新证据再反驳一次。之后仍未解决的:标记为未解决,说明分歧将转到审查线程之外处理,并停止再次提出。评论线程无法解决理念分歧。

轮数上限。 到第 3 轮时,每项仍未解决的发现都必须已修复、经双方同意转为后续跟进问题,或升级到线程之外处理。Judge 绝不会针对同一组发现进行第 4 轮审查。

批准门槛。 只要 PR 确实改善了整体代码健康状况,就应立即批准,即使仍有不完美之处;不存在完美代码,只有更好的代码。未解决的 🟡 绝不会阻止 APPROVE(可以在批准时附带细微意见)。为了要求超出严重性表的润色而拒绝批准,属于审查者扩大范围。

门禁会强制执行此约定中可机械检查的部分:当 "round": 2 或更高时,它会拒绝任何非阻塞发现,要求包含解决情况部分,并要求提供 carryover,以确保判定结果反映上一轮仍未解决的问题。

示例

示例 1:常规评审

用户说:“revise esse PR”(在有未关闭 PR 的分支上,共有 180 行改动,使用 TypeScript)。 操作:步骤 0–2(调研:一次依赖升级,已查看其更新日志),依次进行各轮检查,验证后仍有 1 条必须修复的问题和 2 条小建议,通过第二次运行的门禁检查(第一次运行时发现了一个感叹号),以 COMMENT 形式发布。 结果:一份合并后的评审、三条行内评论,以及一份引用更新日志 URL 的调研记录摘要。

示例 2:发现阻断问题

用户说:“judge this PR before I merge”。 操作:Pass A 发现资金处理路径中存在未设保护的除法,并追踪到一个会导致失败的输入;验证确认问题位于 src/billing/invoice.ts:142;结论为 REQUEST_CHANGES;PR 作者与 gh 用户相同,因此 post_review 以 COMMENT 形式发布,TL;DR 说明 REQUEST_CHANGES,页脚解释了回退方案。 结果:已发布评审,阻断问题通过文件和行号证据锚定在行内,并给出简单修复方法(保护子句,共三行)。

示例 3:没有证据的说法

用户说:“review this PR”。PR 描述称“修复了 worker pool 中的竞态条件”。没有测试覆盖该线程池。 操作:Pass E 标记了此说法;没有复现步骤或测试;该发现被转为 🟠 问题,要求提供一个先失败后通过的测试,而不是断言修复有误。 结果:评论要求提供证据,而不是进行推测。

示例 4:第 2 轮

用户推送修复后说:“julgue de novo”。 操作:步骤 0 找到之前的评审;当前为第 2 轮。解决状态检查对应问题台账:F1 已在提交 a1b2c3d 中修复,F2 的拒绝理由成立(记录为 declined-accepted),F3 仍未解决。仅扫描上次评审之后的差异以查找新的阻断问题;未发现。findings 为空,F3 的 carryover 为 {"blocker": 1, "should-fix": 0},结论为 REQUEST_CHANGES。 结果:一份简短评审,只包含 Resolution 表格和 TL;DR。没有新评论,也没有新问题,保持收敛。

故障排除

错误:提交评审时出现 HTTP 422

原因:在自己的 PR 上执行 APPROVE/REQUEST_CHANGES,或评论锚定到了不在差异中的行。 解决方案:post_review.py 会自动将针对自己 PR 的操作回退为 COMMENT。若锚定失败,请将评论移至补丁中显示的已更改行,或移除 line 并将其合并到摘要中。

错误:gh 未通过身份验证

原因:没有 gh auth login 会话。 解决方案:请用户运行 gh auth status 并完成身份验证。不要尝试在没有令牌的情况下调用。

错误:当前分支没有 PR

原因:分支从未推送,或尚未创建 PR。 解决方案:报告此情况并停止。创建 PR 不属于 The Judge 的工作范围(那是另一项工作)。

门禁对同一正文反复失败

原因:没有移除被禁止的模式,而是通过改写措辞绕开它。 解决方案:删除包含违规内容的句子。门禁输出会指出确切的模式和位置。

评论

支持 Markdown