pr-ai-review-loop
GitHub无人值守驱动 PR 的 review-修复-push 循环,直到所有 AI reviewer 通过。监控审查状态、收集评论、自动修复代码并重新推送,实现代码审查的自动化闭环。
Trigger Scenarios
Install
npx skills add ArcReel/ArcReel --skill pr-ai-review-loop -g -y
SKILL.md
Frontmatter
{
"name": "pr-ai-review-loop",
"description": "无人值守驱动 PR 的 review → 修复 → push → 再 review 循环,直到全部 AI reviewer 通过或触发收敛退出。仅当用户明确要求运行或继续该编排循环,或本地会话刚完成 PR push 后要求继续收敛时调用;作为 GitHub reviewer 审查代码、仅阅读 PR 或处理单条 review 意见时不调用。"
}
AI Review 自动循环
本 skill 监控 reviewer 状态、必要时触发 review、收集评论并按 receiving-code-review 的纪律处置。进入循环前:确认当前分支已有非 draft 的 PR(draft 时 CodeRabbit 默认不审;无 PR 时交用户决定是否创建,不代为提交),并通读 references/reviewers.md——每轮判定(已审 / actionable / 通过)全部依赖其中的 per-reviewer 规则。
目标状态
循环的唯一正常出口。宣布通过前逐项核对:
- 本 PR 参审的每家 AI reviewer(CodeRabbit / Gemini / Codex)通过。CodeRabbit 与 Codex 审过当前 HEAD;Gemini 由 cold-start fallback 保证参审,可按 fix-up 顺延沿用上一已审 HEAD 的通过结论(口径见 reviewers.md「通用约定」)
- CodeQL 退出门槛:分析完成且成功、security 无 PR 引入的 open 告警、quality 全量评论逐条已处置——三条细则与"仓库未接入"的跳过口径见 reviewers.md「GitHub code scanning bots」节
- 循环期间的所有 actionable 评论均已实施修复或记录 pushback。终核时对三家 AI reviewer 各跑一次
query.sh unacked <bot[bot]>核对历史 inline;再跑query.sh history,从三家的 review / 顶层评论中取本循环尚未核对的 id,用query.sh details <id>...批量读全文。两处发现的每条 actionable 均须已修复或有在案 pushback
运行模式:无人值守
自动执行整个循环,无需每轮征求授权:触发命令、push 修复、回应 inline、修复 CI、下一轮 poll 的延迟均自行决定。只有两类场景暂停询问用户——故障类见「故障处理」节,调度类如下:
- 根本性分歧无定论——同一主题反复重提的判定与动作见「收敛兜底」#3
- reviewer 之间冲突:同一议题,A 家主张 X、B 家反对 X。暂停并交用户裁决,不自行选边
- 业务取舍:修复方案在前向兼容、性能、用户体验上存在显著差异,可能影响业务意图。暂停并确认
每轮 poll 流程
每轮三步:拉数据 → 对照目标找缺口 → 动作。
步骤 1:拉取当前状态
以下命令的 <repo-root> 均取目标 PR checkout 根目录:
bash scripts/poll.sh --repo-root <repo-root> <PR_NUMBER>
stdout 是最小索引:本轮新评论带索引行(id / 判定 flags / 120 字符预览),旧评论折叠为 per-bot 计数,正文一律不内联;字段语义见 poll.sh header。索引与上一轮无差异时,stdout 折叠为单行 no_change(unchanged_since 即上次全量打印时刻)——决策沿用上下文中已有的索引,上下文已丢失(如压缩后)时用 index 子命令重印。完整快照(含全文)落盘在 snapshot_file,正文详情按需查询:
bash scripts/query.sh --repo-root <repo-root> <PR_NUMBER> <子命令>
子命令:details <id>...(按 id 批量取全文)/ gemini-latest-body / quality-all(终核)/ history(主题重复及终核枚举 review / 顶层评论)/ unacked <bot[bot]>(终核或 fix-up 顺延时核对历史 inline;bot 名带 [bot] 后缀,如 chatgpt-codex-connector[bot])/ index(重印上轮全量索引)。查询异常一律以 QUERY_ERROR 响亮失败——空结果因此可以放心当作确无数据。
步骤 2:对照目标找缺口
按「目标状态」逐项核对,对每个缺口执行对应动作(同一轮可并行处理多家):
| 缺口 | 动作 |
|---|---|
checks_failing 非空(CI 红) |
就地修复并 push——CI 红会阻塞 reviewer 触发。若根因是 main 上的问题且修复已合入,rebase 到最新 main 后 git push --force-with-lease 即可拿到修复——gh run rerun 只在原 merge-ref 上重跑,不包含 main 的新提交,而 rebase 改写了 commit,普通 push 会被拒;已 rebase 到最新 main 仍红即属修不动,暂停询问 |
| 某家参审 reviewer 未审当前 HEAD | 按 reviewers.md 该家「触发」规则决定等待或发触发命令 |
| 至少一家有本轮新 actionable 评论(判定见 reviewers.md) | 进入步骤 3 |
security_alerts.open_introduced 与已认定误报在案清单(核对方式见 reviewers.md「已知误报」)的差集非空,且该差集无对应新评论 |
上一轮没修干净(bot 不重复提醒)——只把差集里的 alert 数据(number / rule / path / url)带入步骤 3,按数据修而非按评论修;已在案的部分不重复处理。前提:CodeQL 分析完成且成功(门槛 1 口径)——分析未完成时差集基于过期数据,归入下行等待 |
CodeQL 分析未完成(codeql_checks.all_ok == false 且 failing 为空) |
等待(不阻塞其它缺口的处理,但阻塞终核——分析完成前不得宣布"缺口均消失") |
| 以上缺口均消失 | 做目标状态终核(含 CodeQL 门槛与 unacked 兜底逐条);全过则按「收敛兜底」#4 正常退出;发现遗留则按对应缺口处理 |
| 未全部达成且无可执行动作(reviewer 响应中) | 按「轮询节奏」表等待下一轮 |
fix-up 顺延:仅在决定是否重触发 Gemini 前,对最近的 push 批次跑 bash scripts/classify_commits.sh --repo-root <repo-root> <PR_NUMBER> [SINCE_SHA](SINCE_SHA 取上一批次末 commit 的 oid;批次边界从索引 commits_since_pr_created 的间隔看,首批次以 base_oid 为界),按 reviewers.md「通用约定」判定是否沿用 Gemini 结论。
脚本在 stderr 报 WARNING: SINCE_SHA ... is not on PR(典型成因 rebase 改写了全部 SHA)时锚点已失效,拿到的是全量提交而非最近一批,不得按该输出判形状——rebase 同时刷新了 committedDate,批次边界也无从重建。此时保守处置:不顺延,按 reviewers.md 的触发规则重审 Gemini,并把锚点重设为索引 commits_since_pr_created 末条 oid 供下轮使用。「收敛兜底」#2 用本脚本取证时同样适用该告警的处置。
执行完触发动作后,按「轮询节奏」进入主动等待。
步骤 3:收集评论并实施修复
按索引挑出本轮新 actionable 条目(判定见 reviewers.md),用 query.sh details <id>... 一次批量取全文;Gemini 最新 summary 的 has_pass_marker == false 时再取 gemini-latest-body 整段——某些建议仅出现在 summary 中,inline 部分为空。运行 /receiving-code-review 取得评估与回复的纪律,把本轮所有 reviewer 的新评论合并为一批处理,处置完这一批后一次 push——分批处理意味着多次 push,而每次 push 都会让全部 reviewer 重审一轮。
GitHub code scanning 两家(quality / security)的评论并入同一批,处置口径(全部 actionable、修复与 pushback 落点)见 reviewers.md「GitHub code scanning bots」节。
修复形状:下面两条与 receiving-code-review 逐条实施的要求冲突时以本节为准——逐条实施会把一批意见变成一批分散的小补丁,累积下来持续降低代码的可修改性(ETC);修复取「回到合理形态」的最小改动,不在现状上叠补丁。
- YAGNI:对防御性意见(新增检查、兜底、try-except、默认值、空值分支),先确认它要防的失败路径是否真实存在,即能否指出一个具体的调用方或输入触发它。能指出就实施;不能指出就回复评论说明理由,不修改代码。两种处置都要用一句话记录这条路径:驳回的写在回复评论里,实施的写在 commit 说明里。
receiving-code-review的YAGNI Check一节检查的是静态未被调用的代码,这里检查的是运行时不可达的分支 - Duplicated Code:先确认这批意见中有几条指向同一处逻辑或同一个根因。有两条以上时,在已有抽象内合并为一处改动
gh 读命令遇 API 瞬断会输出截断内容且退出码仍为 0——写回远端(如 pr edit --body)前先确认读到的是完整原文。
这一批处置完并 push 后回到步骤 1。
轮询节奏
每轮 poll 与决策后运行 bash scripts/wait.sh --repo-root <repo-root> <PR_NUMBER>并等待返回,命令执行上限设为 1800 秒;返回后回到步骤 1。WAIT_TIMEOUT 后仍无可执行动作时,按「故障处理」的 30 分钟无响应条目暂停。
收敛兜底
下列任一条件触发退出:
round_estimate≥ 3 → 暂停询问"已 3 轮,merge / 继续 / 放弃?"- 连续 2 轮 push 都没有产生实质收益 → 暂停询问"边际收益已降低,是否结束?"。实质收益有两种,占一种即算:用户可感知的行为改善(修掉一条真实可达的崩溃或错误路径算,哪怕形式上是一处防御),或后续改动成本的下降(消除重复、拆掉错误抽象、去掉不可达的防御分支)。按改动实际做了什么判断,不按它的标签——架构与 DRY 上的改善是要争取的收益,不因为用户看不见就算没收益。真正不算的是往复:风格与命名的口味调整、reviewer 之间的偏好差异、已驳回又换个说法重提的意见。证据跑
classify_commits.sh看最近两批;它只给 commit 说明与文件行数统计,说明笼统或同一文件里内部逻辑与用户路径混在一起时,按输出的sha跑git show看改动本身。本条判断的是收益,fix-up 顺延的五类形状判断的是重审风险,两处口径不通用 - 同一主题(reviewer + 关键词,例如 "Pydantic
extra=ignorevsforbid")被同一家 reviewer 在 ≥ 3 个 HEAD 上反复提出,且无 ADR / 项目决策记录兜底 → 暂停询问是否升级 ADR。新评论似曾相识时跑query.sh <PR> history通读评论历史,按语义归并主题,数同一主题出现在几个 HEAD 上 - 目标状态全部达成 → 正常退出,按 references/retrospective.md 产出复盘随汇报交出(何种出口产复盘以该文件开篇为准)
故障处理
条件与处置一一对应,除能力证伪外均暂停询问用户(无人值守的例外面):
能力证伪自裁决(唯一不暂停的故障):reviewer 的回复或官方通知确证其无法参审——App 未接入、要求创建/连接账号、服务已停止——该家本 PR 按不参审处理、不再触发,记入退出汇报;沉默或一般报错不算证伪,仍按下列条目暂停询问。
- 某家 reviewer(含 CodeQL 分析)超过 30 分钟未响应:bot 可能服务异常或配额已满,暂停说明现状。Gemini fix-up 顺延导致的"未审"不算无响应——那是设计内跳过
- bot 报错(如 "Internal error"、"Token limit exceeded"):贴出错误内容,按 reviewers.md 该家的触发约束询问是否重跑
quota_alerts非空:alert 之后该家已有成功审查(更晚的 review 或 walkthrough 更新)的视为已恢复,忽略残留 banner;真实受阻时,reviewers.md 该家有专项配额处置段的(如 CodeRabbit)按其规则自行处置,不暂停;其余家贴出body_head,询问停用该家继续其他家,还是等 quota 恢复后再 pushcodeql_checks.failing非空(失败态集合见 poll.sh headerchecks_failing条):分析失败,alerts 数据停留在上次成功分析,不能做终核;询问是否重跑失败的 workflowsecurity_alerts.available == false:贴出unavailable_hint,按 reviewers.md「仓库未接入」段判别权限问题与未接入——两种情形都需用户确认,不得自动跳过 security 门槛wait.sh返回WAIT_ERROR:401/403 按下条处理;其余贴出 stderr 暂停gh401/403:请用户运行gh auth refresh -s repo- review 评论语义模糊,按
receiving-code-review的纪律仍无法判定是否 pushback:贴出原文请用户定夺
Version History
-
feafcb4
Current 2026-08-20 00:24
优化轮询与 push 间隙的评论判定逻辑,防止漏判;改进 Gemini 审查状态的 HEAD 锚定机制,解决并行审查导致的假通过问题;增强 seen 台账的数据校验与写入可靠性。
- 24a1f5c 2026-07-25 06:25


