babysit-pr

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Babysit PR

看护 PR

Bots review, you decide, you act, and the PR keeps the record.
AI review bots are useful and often wrong. They miss context outside the diff, assume other library versions, invent APIs and pad reviews with taste. You are the engineer who owns the PR: verify each finding against the code, fix what is real, and answer every bot comment with a short verdict and its evidence. A later reader of the PR should be able to see what each finding was, whether it held up and which commit fixed it, without re-investigating.
All GitHub reads and writes go through
scripts/pr-ops.sh
in this skill's directory. Call it by absolute path through bash (
bash <skill-dir>/scripts/pr-ops.sh <command> ...
). It implements references/github-operations.md, and every write asserts what GitHub stored, so exit 0 means it happened.
--repo owner/name --pr N
default to the current checkout and branch; pass them explicitly when you are anywhere else. Exit 3 means the script refused to post a duplicate because your answer is already there. Don't force it; finish whatever that answer still lacks (
react
and
resolve
are safe to repeat).
机器人负责审查,你负责判断和行动,而 PR 会完整保留过程记录。
AI 审查机器人很有用,却经常出错。它们会遗漏 diff 之外的上下文、假定其他库版本、臆造 API,还会用主观偏好填充审查内容。你是 PR 的负责人:必须根据代码核实每条发现,修复确实存在的问题,并用简短判定和证据回应每条机器人评论。PR 的后续读者应能看清每条发现是什么、是否成立,以及哪个提交修复了它,而无需重新调查。
所有 GitHub 读取和写入操作都通过本 skill 目录中的
scripts/pr-ops.sh
完成。通过 bash 使用绝对路径调用(
bash <skill-dir>/scripts/pr-ops.sh <command> ...
)。它实现了 references/github-operations.md 中的操作,每次写入都会核验 GitHub 中实际保存的内容,因此 exit 0 表示操作已完成。
--repo owner/name --pr N
默认使用当前检出目录和分支;如果处于其他位置,应显式传入这些参数。Exit 3 表示脚本拒绝发布重复回复,因为对应回答已经存在。不要强制绕过;应先完成该回答仍缺少的步骤(
react
和
resolve
可以安全地重复执行)。

0. Set up

0. 初始化

  1. Rules. Read the target repository's agent and contribution rules (
    AGENTS.md
    ,
    CLAUDE.md
    ,
    .agents/rules/*.md
    ,
    CONTRIBUTING.md
    , linter and formatter config). They decide what counts as a convention violation and how commits must look (Conventional Commits, DCO sign-off with
    git commit -s
    , and so on).
  2. The PR. Use the number or URL the user gave, else the current branch's PR. Check out its head branch in a clean working tree. If the user has unrelated uncommitted work, use a separate worktree rather than mixing it in.
  3. The goal. Take the scope from the user's original request, else the PR title and description. This is the fence for every judgement below. Fixes stay inside it, even when a bot suggests otherwise.
  4. Authority. Babysitting includes pushing fixes to the PR branch. Merging needs an explicit request from the user. Closing the PR, force-pushing anything other than a rebase of this branch, opening issues and anything else outward-facing need the user's go-ahead unless they already gave it.
  5. First snapshot. Run
    status
    and learn how each reviewer in
    reviewers
    runs (below).
  1. 规则。 阅读目标仓库的 Agent 和贡献规则(
    AGENTS.md
    、
    CLAUDE.md
    、
    .agents/rules/*.md
    、
    CONTRIBUTING.md
    、linter 和 formatter 配置)。这些规则决定什么属于约定违规,以及提交必须采用什么形式(Conventional Commits、使用
    git commit -s
    进行 DCO sign-off 等)。
  2. PR。 使用用户提供的编号或 URL,否则使用当前分支对应的 PR。在干净的工作树中检出其 head 分支。如果用户存在无关的未提交工作,应使用单独的 worktree,避免将其混入。
  3. 目标。 范围以用户最初的请求为准,否则以 PR 的标题和描述为准。这是后续所有判断的范围边界。即使机器人提出其他建议,修复也必须留在该范围内。
  4. 权限。 看护 PR 包括将修复推送到 PR 分支。合并 PR 必须得到用户明确要求。关闭 PR、强制推送本分支 rebase 之外的任何内容、创建 issue 以及其他对外操作,除非用户已经授权,否则都需要用户同意。
  5. 首次快照。 运行
    status
    ,并了解下文
    reviewers
    中每个审查者的运行方式。

How reviewers run

审查者如何运行

Assume no particular bot. Learn each reviewer's behaviour from this PR and the repository: its earlier reviews, its check runs, its configuration file or workflow.
  • Bots review every push by themselves. Some run as a CI check and post their review only after that check finishes (Pullfrog runs with CI, then posts a review saying whether anything needs action). Treat such a reviewer as pending until its check on
    head_sha
    has finished.
  • A passed check can be the whole review. Bots that review incrementally often stay silent when a push brings nothing new: the check on
    head_sha
    passes, but no review is posted and
    reviewed_head
    stays
    false
    (Pullfrog does this). If the bot's check on
    head_sha
    passed and it posted nothing after the push, it found nothing to say; read the check's log to be sure when it is cheap. Don't wait for a review that won't come.
  • Expected reviewers are the active ones.
    reviewers
    lists everyone who ever reviewed or commented inline, including bots since removed and humans. Wait only for bots that are still active: one that reviewed the previous head, or one whose check runs on this head. A bot that skipped the last pushes is not coming back; mention it in the report instead of waiting for it.
  • Retrigger only as a last resort: when a reviewer has clearly not reviewed the latest push long after its usual delay, and the repository documents an exact trigger comment or this PR's history shows one that worked. Then use
    pr-ops.sh retrigger --trigger '<exact text>'
    , which reuses a trigger that is still active. Never post a trigger from memory; bot commands change and old ones go stale.
  • Don't @-mention a bot in a reply. Many bots treat a mention as a command and answer again. Replying inside a bot's thread can itself start a conversation; its answer shows up as a pending thread or followup, and you judge it like any other comment.
  • Summary-only findings are feedback too (section 3). Pure summaries need no answer: a recap of the change, a walkthrough, "No new issues found".
不要假定任何特定机器人。应从当前 PR 和仓库中了解每个审查者的行为,包括其历史审查、check run、配置文件或 workflow。
  • 机器人会在每次 push 后自行审查。 有些机器人以 CI check 的形式运行,并且仅在该 check 完成后发布审查意见(Pullfrog 会与 CI 一起运行,随后发布审查,说明是否需要采取行动)。在针对
    head_sha
    的 check 完成之前,应将这类审查者视为 pending。
  • 通过的 check 可能就是全部审查结果。 增量式审查机器人在一次 push 没有带来新内容时通常会保持沉默:
    head_sha
    上的 check 通过,但不会发布审查,且
    reviewed_head
    仍为
    false
    (Pullfrog 即是如此)。如果机器人在
    head_sha
    上的 check 已通过,且 push 后没有发布任何内容,就说明它没有需要表达的意见;在成本较低时,可以读取 check 日志以确认。不要等待一条永远不会出现的审查。
  • 只等待仍处于活跃状态的预期审查者。
    reviewers
    列出所有曾经审查或发表过行内评论的人,包括后来移除的机器人和人类。只等待仍然活跃的机器人:审查过上一个 head 的机器人,或其 check 正在当前 head 上运行的机器人。跳过最近几次 push 的机器人不会再来;应在报告中提及它,而不是继续等待。
  • 仅将 retrigger 作为最后手段:当某个审查者在通常延迟之后仍明显没有审查最新 push,并且仓库文档记录了确切的触发评论,或该 PR 的历史记录显示某个触发方式曾经有效时,才执行重触发。然后使用
    pr-ops.sh retrigger --trigger '<exact text>'
    ,它会复用仍然有效的触发方式。绝不要凭记忆发布触发评论;机器人命令会发生变化,旧命令可能已经失效。
  • 不要在回复中 @ 机器人。 许多机器人会将提及视为命令,并再次回复。在机器人的 thread 内回复本身也可能引发对话;它的回答会显示为 pending thread 或 followup,你应像处理其他评论一样进行判断。
  • 仅包含总结的发现也属于反馈(见第 3 节)。纯粹总结的内容无需回答:例如变更回顾、流程说明或“未发现新问题”。

1. The loop

1. 循环

Repeat until a stop condition in section 7 holds.
  1. Snapshot.
    pr-ops.sh status [--since <cursor>]
    prints JSON:
    • pr
      : state,
      isDraft
      ,
      head_sha
      ,
      head_repo
      and
      base_repo
      (they differ for a fork),
      mergeStateStatus
      (
      CLEAN
      ,
      BEHIND
      ,
      DIRTY
      = conflicts,
      BLOCKED
      ,
      UNSTABLE
      , ...).
    • checks
      :
      counts
      ,
      failing
      (with
      required
      ),
      pending
      , for the head commit only.
      required_reported
      lists only required checks that have reported; one that never started shows up as
      mergeStateStatus: BLOCKED
      , not here.
    • reviewers
      : everyone non-self who reviewed or commented inline, with
      bot
      ,
      reviewed_head
      and
      last_review_commit
      .
    • pending_threads
      : unresolved inline threads whose latest comment is not yours.
    • unfinished_threads
      : unresolved bot threads that end with your reply, meaning an earlier round stopped between
      reply
      and
      resolve
      . Finish them with
      react
      and
      resolve
      ; don't reply again.
    • awaiting_humans
      : unresolved human threads that end with your reply. They're the reviewer's to resolve.
    • followups
      : threads you resolved where someone replied after you.
    • feedback
      : review bodies and top-level comments you haven't answered with
      comment --ack
      , plus any edited after your answer. Bodies are complete; read all of one before judging it.
    • cursor
      : GitHub's clock when the snapshot started. Pass it back as
      --since
      next round so feedback and followups you've already seen stay hidden. Threads don't need it; their state lives on GitHub. Checks from older commits are history; only
      head_sha
      counts. A thread on an older commit (
      isOutdated: true
      ) still counts until you check whether it still applies at HEAD.
  2. CI. Handle
    checks.failing
    (section 4).
  3. Judge every pending thread, followup and feedback item (section 2). Investigate first and write nothing yet.
  4. Fix the items you judged
    VALID
    . Run the repository's own checks locally (its test suite, linters, pre-commit/prek hooks), commit following the repository's rules, and push. Give unrelated fixes separate commits so each reply can cite a focused commit, and write real commit messages (
    fix(parser): reject empty --since values
    ), not "address review comments".
  5. Answer (section 3). Replies cite pushed commits, so answer after the push lands:
    git rev-parse HEAD
    must equal
    head_sha
    in a fresh
    status
    .
  6. Reviewers. Let them review the push on their own; retrigger only under the last-resort rule in section 0.
  7. Base branch. Rebase when needed (section 5).
  8. Wait (section 6), then go back to step 1.
重复执行以下步骤,直到第 7 节中的某个停止条件成立。
  1. 快照。
    pr-ops.sh status [--since <cursor>]
    会输出 JSON:
    • pr
      :状态、
      isDraft
      、
      head_sha
      、
      head_repo
      和
      base_repo
      (对于 fork,两者可能不同),以及
      mergeStateStatus
      (
      CLEAN
      、
      BEHIND
      、
      DIRTY
      = 存在冲突、
      BLOCKED
      、
      UNSTABLE
      等)。
    • checks
      :仅针对 head commit 的
      counts
      、
      failing
      (包含
      required
      )和
      pending
      。
      required_reported
      只列出已经报告结果的 required check;从未启动的 check 会显示为
      mergeStateStatus: BLOCKED
      ,不会出现在这里。
    • reviewers
      :所有除自己以外、曾审查或发表过行内评论的人,并包含
      bot
      、
      reviewed_head
      和
      last_review_commit
      。
    • pending_threads
      :最新评论不是由你发布的未解决行内 thread。
    • unfinished_threads
      :以你的回复结尾但仍未解决的机器人 thread,表示上一轮在
      reply
      和
      resolve
      之间中断。使用
      react
      和
      resolve
      完成它们;不要再次回复。
    • awaiting_humans
      :以你的回复结尾但仍未解决的人类 thread。这些 thread 应由审查者自行解决。
    • followups
      :你已解决,但之后又有人回复的 thread。
    • feedback
      :尚未通过
      comment --ack
      回答的审查正文和顶层评论,以及在你回答后被编辑的内容。正文是完整的;判断之前应读完某条反馈的全部内容。
    • cursor
      :快照开始时 GitHub 的时钟。下一轮将其作为
      --since
      传回,从而隐藏已经看过的反馈和 followup。Thread 不需要该参数;其状态保存在 GitHub 上。 较旧提交上的 check 属于历史记录;只有
      head_sha
      上的结果有意义。旧提交上的 thread(
      isOutdated: true
      )仍然需要计数,直到确认该问题在 HEAD 上是否仍然适用。
  2. CI。 处理
    checks.failing
    (见第 4 节)。
  3. 判断每个 pending thread、followup 和 feedback 项(见第 2 节)。先调查,暂不写入任何内容。
  4. 修复判定为
    VALID
    的项目。在本地运行仓库自己的检查(测试套件、linters、pre-commit/prek hooks),按照仓库规则提交并推送。将无关修复放在单独的提交中,使每条回复都能引用一个有明确目标的提交;提交信息应真实具体,例如
    fix(parser): reject empty --since values
    ,而不是“address review comments”。
  5. 回答(见第 3 节)。回复需要引用已经推送的提交,因此应在 push 落地后回答:在一次全新的
    status
    中,
    git rev-parse HEAD
    必须等于
    head_sha
    。
  6. 审查者。 让它们自行审查这次 push;仅在第 0 节所述的最后手段规则下才进行 retrigger。
  7. 基础分支。 必要时执行 rebase(见第 5 节)。
  8. 等待(见第 6 节),然后回到步骤 1。

2. Judge each finding

2. 判断每项发现

A verdict needs evidence either way. Check the claim against the code at HEAD (not the commit the bot saw): read the code and its callers, run the test, or write a quick reproduction. "Looks fine to me" is not a reason, and neither is "the bot said so".
There are three verdicts. Pick one by answering two questions, in this order:
  1. Is the claim real at HEAD? If the evidence disproves it, or nothing real stands behind it (no defect, no documented rule, no requirement), the verdict is
    INVALID
    .
  2. Is fixing it within this PR's goal? If yes, it is
    VALID
    : fix it. If no, it is
    OUT OF SCOPE
    .
VerdictMeansReaction
VALID
Real and in scope. Fixed, as the bot suggested or another way (say how in the reply).👍
INVALID
Wrong, or a preference with nothing behind it.👎
OUT OF SCOPE
Real, but fixing it would widen the PR beyond its goal.😕
The reaction records the outcome: 👍 agreed and fixed, 👎 wrong, 😕 real but not fixed here. Some bots act on reactions (a "fix the 👍 findings" button, for one), so a finding this PR won't fix must never get a 👍.
The reason in the reply must be something a reader can check: a commit for
VALID
, a
path:line
, test, caller or doc for
INVALID
, and the PR's goal for
OUT OF SCOPE
. If you can't name one, you haven't finished judging.
Real means at least one of these holds:
  • You can state a concrete failing scenario (inputs or state, then the wrong result) and you confirmed it by reading the reachable path or running it.
  • It breaks a rule the repository documents (rules files, linter config, contribution guide), or the PR's own stated goal.
  • It is a security, data-loss or concurrency issue on a reachable path. For these the bar to dismiss is higher: if you can't disprove it, treat it as real or ask the user.
Common reasons a bot is wrong (each is an
INVALID
when you can cite the evidence):
  • The guard exists outside the diff: a caller validates, the type rules it out, a test pins it.
  • It assumes a different version of a library, language or API than the lockfile pins, or an API, flag or option that doesn't exist.
  • It misreads the diff (old side for new side), or the code it describes never behaved that way. (If the problem was real when the bot looked and a later commit in this PR fixed it, that is
    VALID
    with that commit.)
  • The scenario isn't reachable: validated input, private function with known callers, impossible state.
  • It contradicts the repository's documented conventions or its formatter.
Scope and nitpicks. A correct nitpick on lines this PR touches is
VALID
: fix it. A suggestion that is only taste (no rule or defect behind it), or that contradicts the repository's conventions, is
INVALID
. Pre-existing problems in code the PR doesn't change, refactors and feature ideas are
OUT OF SCOPE
, however good, because the user decides scope. A real, in-scope problem that is expensive to fix is none of these: it is the user's call, so list it under "Needs your call".
Repeats and rebuttals. If a bot repeats a finding you already answered, or argues back without new evidence, answer once more with the same verdict and a link to your earlier reply, then resolve. Don't argue a third time. If it brings new evidence, judge again; a flipped verdict is fine, so say so plainly. If you still can't decide after investigating, don't guess: list the item under "Needs your call" in the report and leave the thread unresolved.
Acknowledgements need nothing. A bot reply like "Addressed in
<sha>
", "Thanks" or "LGTM" in a followup gets no reply.
Humans are not bots. Comments from human reviewers don't get verdict labels, reactions or resolution from you. Implement clear, in-scope requests and reply in plain prose saying what changed and where. Bring disagreements, questions about intent and anything out of scope to the user rather than disputing a person on the user's behalf. Leave resolving their threads to them.
无论判定结果如何,都必须有证据。将主张与 HEAD 上的代码进行核对,而不是机器人审查时的提交:阅读代码及其调用方、运行测试,或编写快速复现。“看起来没问题”不是理由,“机器人这么说”也不是理由。
共有三种判定。按以下顺序回答两个问题,从而选择一种:
  1. 该主张在 HEAD 上是否属实? 如果证据能否定它,或其背后没有实际问题(没有缺陷、书面规则或需求),则判定为
    INVALID
    。
  2. 修复它是否属于本 PR 的目标范围? 如果是,则判定为
    VALID
    并进行修复;如果不是,则判定为
    OUT OF SCOPE
    。
判定含义Reaction
VALID
问题属实且在范围内。已经按机器人建议或采用其他方式修复(请在回复中说明)。👍
INVALID
判断错误,或只是背后没有依据的主观偏好。👎
OUT OF SCOPE
问题属实,但修复会扩大 PR 的目标范围。😕
Reaction 会记录处理结果:👍 表示认可并已修复,👎 表示判断错误,😕 表示问题属实但未在此处修复。部分机器人会根据 reaction 执行操作,例如提供“修复所有 👍 发现”的按钮,因此本 PR 不准备修复的发现绝不能获得 👍。
回复中的理由必须是后续读者能够核查的内容:
VALID
应引用提交,
INVALID
应引用
path:line
、测试、调用方或文档,
OUT OF SCOPE
应说明 PR 的目标。如果无法指出任何依据,就说明尚未完成判断。
若满足以下至少一项,则问题属实:
  • 你可以说明具体的失败场景(输入或状态,以及随后出现的错误结果),并通过阅读可达路径或实际运行进行了确认。
  • 它违反了仓库记录在案的规则(规则文件、linter 配置、贡献指南),或违反 PR 自身声明的目标。
  • 它在可达路径上构成安全、数据丢失或并发问题。对于这些问题,驳回的门槛更高:如果无法将其否定,就应视为属实或询问用户。
机器人判断错误的常见原因(能够引用证据时,均判定为
INVALID
):
  • 保护逻辑存在于 diff 之外:调用方会进行验证、类型规则排除了该情况,或测试锁定了相关行为。
  • 它假定的库、语言或 API 版本与 lockfile 中固定的版本不同,或者假定了并不存在的 API、flag 或选项。
  • 它误读了 diff(把 old side 当成 new side),或者它描述的代码从未有过那种行为。(如果问题在机器人查看时确实存在,并且本 PR 中后续的提交已修复该问题,则判定为
    VALID
    ,并引用该提交。)
  • 场景不可达:输入已被验证、函数是私有且调用方明确,或状态不可能出现。
  • 它与仓库记录的约定或 formatter 冲突。
范围与 nitpick。 对于本 PR 触及的行,正确的 nitpick 判定为
VALID
,应当修复。仅属于主观偏好、背后没有规则或缺陷的建议,或与仓库约定冲突的建议,判定为
INVALID
。本 PR 未修改的代码中已存在的问题、重构以及功能构想判定为
OUT OF SCOPE
,无论它们看起来多么合理,因为范围由用户决定。真实且在范围内、但修复成本很高的问题不属于上述任何一种:应由用户决定,并将其列在“Needs your call”下。
重复意见与反驳。 如果机器人重复了你已经回答过的发现,或在没有新证据的情况下继续反驳,则再回答一次,使用相同判定并附上之前回复的链接,然后解决 thread。不要进行第三次争论。如果它带来了新证据,则重新判断;改变判定完全没问题,但应明确说明。如果调查后仍无法决定,不要猜测:将该项目列在报告的“Needs your call”下,并保持 thread 未解决。
致谢无需回应。 对于“已在
<sha>
中处理”“谢谢”或“LGTM”之类的机器人后续回复,不需要再回复。
人类不是机器人。 来自人类审查者的评论不应由你添加判定标签、reaction 或进行解决。执行其中明确且在范围内的要求,并以普通文本回复说明改动了什么以及改动位置。对于分歧、意图问题以及任何超出范围的事项,应交给用户,而不是代表用户与审查者争论。人类 thread 应由其审查者自行解决。

3. Answer

3. 回答

Inline threads

行内 thread

For each pending thread or followup that needs an answer, in this order:
bash
bash <skill-dir>/scripts/pr-ops.sh reply --comment <latest_comment_id> <<'EOF'
VALID. <why it is real, one or two sentences>. Fixed in <full sha>.
EOF
bash <skill-dir>/scripts/pr-ops.sh react --comment <latest_comment_id> --verdict VALID
bash <skill-dir>/scripts/pr-ops.sh resolve <latest_comment_id>
--verdict
takes
VALID
,
INVALID
or
'OUT OF SCOPE'
(quoted).
reply
finds the thread's root itself. Quote the heredoc (
<<'EOF'
) so backticks and
$
reach GitHub literally.
resolve
takes several IDs at once, so you can batch the resolves at the end of the round.
Reply template. The first word is the verdict label followed by a full stop. Then come one to three sentences with concrete evidence:
path:line
, the test name, the caller, the doc. Use a full commit SHA (GitHub renders it as a short link) and never a SHA you haven't pushed.
text
VALID. <why it is real>. Fixed in <sha>.
VALID. <why it is real>. Fixed differently in <sha>: <what you did instead and why>.
INVALID. <why the claim is wrong, with checkable evidence>.
OUT OF SCOPE. <why it is real>, but this PR's goal is <goal>. <Tracked in #N.>
Examples:
text
VALID. `since` is compared against the local clock, so a skewed machine skips new comments. Fixed in 4c1e9b0d27a35f8e6b2d1c0a9f8e7d6c5b4a3f21.

INVALID. `limit` can't be 0 here: `parse_args()` rejects values below 1 (`cli.py:88`) and `test_limit_must_be_positive` covers it.

OUT OF SCOPE. `retry()` never caps its backoff, but that predates this PR, whose goal is the token refresh.
No thanks, no praise, no @-mentions of bots (section 0), and no hedging. For
OUT OF SCOPE
, write "Tracked in #N" only when an issue exists; opening one is outward-facing, so it needs the user's go-ahead.
对于每个需要回答的 pending thread 或 followup,按以下顺序执行:
bash
bash <skill-dir>/scripts/pr-ops.sh reply --comment <latest_comment_id> <<'EOF'
VALID. <why it is real, one or two sentences>. Fixed in <full sha>.
EOF
bash <skill-dir>/scripts/pr-ops.sh react --comment <latest_comment_id> --verdict VALID
bash <skill-dir>/scripts/pr-ops.sh resolve <latest_comment_id>
--verdict
可取
VALID
、
INVALID
或
'OUT OF SCOPE'
(需要加引号)。
reply
会自行查找 thread 的根评论。使用 quoted heredoc(
<<'EOF'
),确保反引号和
$
原样发送到 GitHub。
resolve
可以一次接收多个 ID,因此可以在每轮结束时批量解决 thread。
回复模板。 第一个词是判定标签,后面跟一个句点。然后用一到三句话给出具体证据,例如
path:line
、测试名称、调用方或文档。使用完整的 commit SHA(GitHub 会将其渲染为短链接),绝不能引用尚未推送的 SHA。
text
VALID. <why it is real>. Fixed in <sha>.
VALID. <why it is real>. Fixed differently in <sha>: <what you did instead and why>.
INVALID. <why the claim is wrong, with checkable evidence>.
OUT OF SCOPE. <why it is real>, but this PR's goal is <goal>. <Tracked in #N.>
示例:
text
VALID. `since` is compared against the local clock, so a skewed machine skips new comments. Fixed in 4c1e9b0d27a35f8e6b2d1c0a9f8e7d6c5b4a3f21.

INVALID. `limit` can't be 0 here: `parse_args()` rejects values below 1 (`cli.py:88`) and `test_limit_must_be_positive` covers it.

OUT OF SCOPE. `retry()` never caps its backoff, but that predates this PR, whose goal is the token refresh.
不要感谢、不要赞扬,也不要 @ 机器人(第 0 节)。对于
OUT OF SCOPE
,仅在对应 issue 已存在时写“Tracked in #N”;创建 issue 属于对外操作,需要用户同意。

Feedback without an inline thread

没有行内 thread 的反馈

Review bodies and top-level comments sometimes carry findings of their own: nitpick sections, "outside diff range" notes, a bot's whole review when it posts nothing inline. Answer each source with one top-level comment that lists a verdict per finding in the same template, quoting each finding in a few words so readers can match them:
bash
bash <skill-dir>/scripts/pr-ops.sh comment --ack pullrequestreview-<id> <<'EOF'
Re: <url of the review or comment>

1. "Unused import in `sync.py`": VALID. Removed in <sha>.
2. "Prefer a dataclass for `Config`": INVALID. The module deliberately keeps plain dicts for TOML round-tripping (`config.py:12-30`).
EOF
There's no thread to resolve and no reaction (a list can mix verdicts). Inline findings that a review body merely summarises are answered in their threads, not again here. Feedback that has nothing to judge (summaries, walkthroughs, "No new issues found") gets no answer; the cursor retires it.
审查正文和顶层评论有时也会包含各自的发现,例如 nitpick 部分、“超出 diff 范围”的说明,或机器人没有发布任何行内评论时给出的完整审查结果。每个来源只使用一条顶层评论进行回答,按照相同模板为每项发现分别给出判定,并简要引用每项发现,方便读者进行匹配:
bash
bash <skill-dir>/scripts/pr-ops.sh comment --ack pullrequestreview-<id> <<'EOF'
Re: <url of the review or comment>

1. "Unused import in `sync.py`": VALID. Removed in <sha>.
2. "Prefer a dataclass for `Config`": INVALID. The module deliberately keeps plain dicts for TOML round-tripping (`config.py:12-30`).
EOF
此类评论没有需要解决的 thread,也不需要 reaction(一个列表可以包含不同判定)。如果审查正文只是总结了在行内 thread 中已经提出的发现,应在对应 thread 中回答,不要在此重复回答。无需判断的反馈(总结、流程说明或“未发现新问题”)不进行回复;cursor 会将其淘汰,不再重复处理。

Screenshots and recordings

截图和录屏

When a fix changes something visible, a screenshot or short recording in the reply or the PR description is the strongest evidence. The GitHub API can't upload images, so use a file-upload skill or tool if one is installed; otherwise describe what you verified and how.
当修复改变了可见内容时,在回复或 PR 描述中附上截图或短录屏是最有力的证据。GitHub API 无法上传图片,因此如果已安装文件上传 skill 或工具,应使用它;否则描述你验证了什么以及验证方式。

4. CI failures

4. CI 失败

Only checks on
head_sha
matter. For each failing check, read its evidence first. When the check's
link
points to a GitHub Actions run (
/actions/runs/<run-id>/...
), use
gh run view <run-id> --log-failed
. Any other link is an external CI service or GitHub App: read what that link exposes, and if you can't read or rerun it, say so in the report rather than guessing. Then decide:
  • Repository failure: a test, lint, type check, build or policy check fails because of the code, the commits or the PR metadata (title format, sign-off). Reproduce it locally when you can, fix it, and push. Treat it like a
    VALID
    finding without a thread.
  • Infrastructure flake: a runner lost or out of disk, network or registry timeouts, 5xx or rate limits from GitHub or a package registry, a job cancelled by a timeout with no failing step of its own, or a known flaky test that passes locally. Rerun once:
    gh run rerun <run-id> --failed
    for Actions, or the provider's documented retry for anything else. If the same check fails the same way again, it isn't a flake: treat it as a repository failure or, if it truly is outside the repository, report it to the user.
Don't rerun a repository failure hoping it goes green, and don't touch CI config or skip tests to get green unless that is the PR's goal.
只有
head_sha
上的 check 才需要处理。对于每个失败的 check,首先读取其证据。当 check 的
link
指向 GitHub Actions run(
/actions/runs/<run-id>/...
)时,使用
gh run view <run-id> --log-failed
。其他链接指向外部 CI 服务或 GitHub App:读取链接所提供的信息;如果无法读取或重跑,应在报告中说明,不要猜测。然后进行判断:
  • 仓库失败:测试、lint、类型检查、构建或 policy check 因代码、提交或 PR 元数据(标题格式、sign-off 等)而失败。尽可能在本地复现,修复并推送。将其视为没有 thread 的
    VALID
    发现。
  • 基础设施引发的 flake:runner 丢失或磁盘空间不足、网络或 registry 超时、GitHub 或 package registry 返回 5xx 或触发限流、job 因超时被取消且自身没有失败步骤,或者已知 flaky test 在本地能够通过。重跑一次:对于 Actions 使用
    gh run rerun <run-id> --failed
    ,其他服务则使用 provider 文档中规定的重试方式。 如果同一个 check 再次以相同方式失败,它就不是 flake:应将其视为仓库失败;如果问题确实位于仓库之外,则报告给用户。
不要期望重跑仓库失败后它就会变绿。除非这正是本 PR 的目标,否则不要修改 CI 配置或跳过测试来强行变绿。

5. Base branch

5. 基础分支

Rebase onto the base branch when
mergeStateStatus
is
DIRTY
(conflicts), when it is
BEHIND
and branch protection requires an up-to-date branch, or when the base gained changes this PR interacts with (
git log HEAD..<base-remote>/<base> -- <files this PR touches>
). Otherwise leave it: every rebase restarts CI and bot reviews.
Pick remotes by repository, not by name:
<base-remote>
is the remote whose URL is
base_repo
, and
<head-remote>
the one whose URL is
head_repo
(
git remote -v
). In a fork checkout,
origin
is usually the fork. Pin the lease to the exact head you rebased, so a commit someone else pushed in the meantime makes the push fail instead of being overwritten:
bash
git fetch <base-remote> <base> && git fetch <head-remote> <headRefName>
git merge-base --is-ancestor <head_sha> HEAD   # local branch must contain the PR head; stop if not
git rebase <base-remote>/<base>
当
mergeStateStatus
为
DIRTY
(存在冲突)、为
BEHIND
且分支保护要求分支保持最新,或者基础分支新增了会与本 PR 产生交互的变更(
git log HEAD..<base-remote>/<base> -- <files this PR touches>
)时,将本 PR rebase 到基础分支上。否则不要 rebase:每次 rebase 都会重新触发 CI 和机器人审查。
根据仓库而不是 remote 名称选择 remote:
<base-remote>
是 URL 与
base_repo
对应的 remote,
<head-remote>
是 URL 与
head_repo
对应的 remote(可使用
git remote -v
查看)。在 fork 的检出目录中,
origin
通常是 fork。将 lease 固定到 rebase 时的准确 head,这样如果期间有人推送了提交,push 会失败,而不是覆盖他们的提交:
bash
git fetch <base-remote> <base> && git fetch <head-remote> <headRefName>
git merge-base --is-ancestor <head_sha> HEAD   # local branch must contain the PR head; stop if not
git rebase <base-remote>/<base>

resolve conflicts, rerun the local checks

resolve conflicts, rerun the local checks

git push --force-with-lease=refs/heads/<headRefName>:<head_sha> <head-remote> HEAD:refs/heads/<headRefName>

If the lease is rejected, someone pushed: run `status` again and start the round over.

Rebase between rounds, not while bots are mid-review. SHAs quoted in earlier replies stay reachable
through the PR's history, so leave old replies as they are. If the repository merges the base into
branches instead of rebasing (merge commits in history, contribution rules), follow that, for
example with `gh pr update-branch`.

**Overlap.** If another PR or a commit on the base already achieves this PR's goal, stop
babysitting, report it with links and ask before closing anything (unless the user already
authorised closing).
git push --force-with-lease=refs/heads/<headRefName>:<head_sha> <head-remote> HEAD:refs/heads/<headRefName>

如果 lease 被拒绝,说明有人进行了推送:重新运行 `status`,并从头开始本轮。

在两轮之间执行 rebase,不要在机器人正在审查时执行。早期回复中引用的 SHA 仍可通过 PR 历史访问,因此不要修改旧回复。如果仓库选择将基础分支 merge 到分支,而不是执行 rebase(历史中存在 merge commit,贡献规则中也有相关规定),则遵循仓库做法,例如使用 `gh pr update-branch`。

**重叠。** 如果另一个 PR 或基础分支上的提交已经实现了本 PR 的目标,则停止看护,附上相关链接进行报告,并在关闭任何内容前征求用户同意(除非用户已经授权关闭)。

6. Wait without noise

6. 无噪声等待

Between rounds, block on
wait
. It returns when something actually changed:
bash
bash <skill-dir>/scripts/pr-ops.sh wait --since <cursor> --timeout 1800
It prints
{"reason": ...}
for
new-activity
,
checks-finished
,
head-changed
,
pr-MERGED
or
pr-CLOSED
, and exits 124 with
timeout
when nothing happened. Pick the mechanism your harness offers:
  • A harness that notifies you when a background command exits (Claude Code's Bash tool with
    run_in_background: true
    , for instance): run
    wait
    in the background, and go back to step 1 when it finishes.
  • A harness with scheduled wake-ups or a loop command: schedule the next round instead.
  • Otherwise: run
    wait
    in the foreground with
    --timeout
    under your tool's time limit, and loop.
While waiting, post nothing. No status updates, no "still watching" comments, no re-pinging bots. When
wait
times out, run
status
before waiting again, because a check can finish between a snapshot and the start of
wait
. After about two hours without any change, stop and report what you are waiting on.
两轮之间,使用
wait
阻塞等待。只有发生实际变化时它才会返回:
bash
bash <skill-dir>/scripts/pr-ops.sh wait --since <cursor> --timeout 1800
它会针对
new-activity
、
checks-finished
、
head-changed
、
pr-MERGED
或
pr-CLOSED
输出
{"reason": ...}
,没有变化时以 124 退出并返回
timeout
。根据 harness 提供的机制选择等待方式:
  • 如果 harness 会在后台命令退出时通知你,例如 Claude Code 的 Bash tool 使用
    run_in_background: true
    ,则在后台运行
    wait
    ,完成后回到步骤 1。
  • 如果 harness 支持定时唤醒或循环命令,则安排下一轮执行。
  • 否则,在工具时限内以前台方式运行
    wait --timeout
    ,并循环执行。
等待期间不要发布任何内容。不要发送状态更新、“仍在监控”之类的评论,也不要反复 ping 机器人。
wait
超时后,应先运行
status
再等待,因为 check 可能在快照和开始
wait
之间完成。约两小时都没有任何变化时,停止并报告当前正在等待的事项。

7. Stop

7. 停止

Stop and report when one of these holds:
  • Ready: on
    head_sha
    , nothing is failing or pending; every active bot (section 0) has
    reviewed_head: true
    or a passed check on
    head_sha
    with nothing posted since;
    pending_threads
    ,
    unfinished_threads
    and
    followups
    need nothing more; every feedback item has been answered or needs no answer; the PR is not a draft; and
    mergeStateStatus
    is
    CLEAN
    (or
    HAS_HOOKS
    ). Merge only if the user explicitly asked for it, using the merge method the repository allows and pinned to the head you checked:
    gh pr merge <n> --squash|--merge|--rebase --match-head-commit <head_sha>
    , never
    --admin
    . Otherwise report that the PR is ready.
  • Done but blocked: the bots and checks are finished, but GitHub still won't allow the merge (
    BLOCKED
    : a required approval, a required check that never started,
    awaiting_humans
    ; or a draft). Report it as "review and CI done, blocked by <reason>", never as ready.
  • Merged or closed by someone else.
  • Superseded by an overlapping PR or commit (section 5).
  • Not converging: after three rounds the bots only produce new low-value nitpicks, a check fails the same way after your fix, or the same disagreement keeps coming back.
  • Blocked on the user: a decision outside your authority, a human reviewer's question, or an item you couldn't judge.
Report in this shape:
markdown
**Status:** Ready to merge | Merged | Blocked: <why> | Superseded by #N | Stopped: <why>

PR: <url> · head `<short sha>` · rounds: <n> · checks: <pass/fail/pending counts>

| Source | Finding | Verdict | Evidence / commit |
|---|---|---|---|
| <bot> `path:line` | short claim | VALID | `<short sha>` |
| <bot> review body | short claim | OUT OF SCOPE | reason |
| CI `checks` | ruff F401 | fixed | `<short sha>` |
满足以下任一条件时,停止并报告:
  • Ready:在
    head_sha
    上没有任何失败或 pending check;每个活跃机器人(见第 0 节)均满足
    reviewed_head: true
    ,或者其
    head_sha
    上的 check 已通过且此后没有发布任何内容;
    pending_threads
    、
    unfinished_threads
    和
    followups
    均无需进一步处理;每条 feedback 都已回答或无需回答;PR 不是 draft;并且
    mergeStateStatus
    为
    CLEAN
    (或
    HAS_HOOKS
    )。仅当用户明确要求合并时才执行合并,使用仓库允许且锁定到已检查 head 的合并方式:
    gh pr merge <n> --squash|--merge|--rebase --match-head-commit <head_sha>
    ,绝不使用
    --admin
    。否则报告 PR 已准备就绪。
  • Done but blocked:机器人和 check 均已完成,但 GitHub 仍不允许合并(
    BLOCKED
    :需要 required approval、required check 从未启动、存在
    awaiting_humans
    ,或 PR 为 draft)。报告为“review and CI done, blocked by <reason>”,绝不能称为 ready。
  • 已被其他人 Merged or closed。
  • 被重叠的 PR 或提交 Superseded(见第 5 节)。
  • Not converging:经过三轮后,机器人只产生新的低价值 nitpick、某个 check 在修复后仍以相同方式失败,或同一分歧反复出现。
  • Blocked on the user:需要用户决定超出权限范围的事项、处理人类审查者的问题,或某项内容无法判断。
按以下格式报告:
markdown
**Status:** Ready to merge | Merged | Blocked: <why> | Superseded by #N | Stopped: <why>

PR: <url> · head `<short sha>` · rounds: <n> · checks: <pass/fail/pending counts>

| Source | Finding | Verdict | Evidence / commit |
|---|---|---|---|
| <bot> `path:line` | short claim | VALID | `<short sha>` |
| <bot> review body | short claim | OUT OF SCOPE | reason |
| CI `checks` | ruff F401 | fixed | `<short sha>` |

Needs your call

Needs your call

  • <deferred items, undecidable findings, human questions, proposed outward actions; or "nothing">
undefined
  • <deferred items, undecidable findings, human questions, proposed outward actions; or "nothing">
undefined