fix(pr-review): default ordinary queues to open PRs - #4878
Conversation
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Exact head reviewed: c5a017408551cdb344d06abb4a2992638f8d50ac
动机
这个 PR 直接修复了当前 PR-review 工作流里反复出现的摩擦:普通 review queue 的意图是找可行动的 open PR,但旧默认是 all,所以每次都同时扫描 merged/closed 历史。结果不仅多做 GitHub 读取,还会让 packet 因历史量被截断,迫使 agent 为审一两个 PR 重新抓更大的全量包,进而挤占真正的 open queue。
目标边界清晰:普通 discovery 默认只看 open;只有显式 --state merged|all 才进入历史/after-merge audit;指定 NUMBER@HEAD 的直接复审仍然不受 lifecycle 限制。
改动思路
实现把“普通队列默认”和“精确目标意图”分开处理:
- CLI 解析层保留
state=None,因此能识别用户是否真的省略了 state。 - 无 exact target 时,省略 state 统一归一为
open。 - 有 exact target 且省略 state 时,仅在 packet filter 层解析成 lifecycle-neutral;底层仍走现有 direct
gh pr view,不扫描历史队列。 - 用户显式写
--state open|merged|all时严格尊重该值,不做暗中放宽。 - 内部 fetch/scan/build API 的默认也同步改为
open,避免只修 argparse、却让程序化 caller 继续扫全历史。
这个 ownership 划分是合适的:只有 CLI boundary 知道“省略 state + 显式 exact target”这组意图;共享 API 则采用更安全的 open 默认。
具体改动
关键代码讲解
-
loopx/cli_commands/pr_review.py::_resolve_pr_review_state_filter这个小 resolver 是唯一的意图区分点:
raw_state is None and target_exact_heads才返回all;其它情况交给 shared normalizer。它不会覆盖用户显式--state open,因此“指定 merged PR 但显式只允许 open”仍会 fail closed。 -
loopx/pr_review.py::normalize_pr_state_filterNone与 internal unknown 现在安全归一为open;fetch_github_pull_requests、scan_github_pull_requests、build_pr_review_packet的默认也一致改成 open。普通 live scan 因此只发出一次gh pr list --state open。 -
loopx/capabilities/pr_review_queue/github_source.py::scan_github_pull_request_targets这个现有 direct-target reader 被正确复用:逐个
gh pr view、校验 remote head 与期望 SHA 一致、补齐 details,然后返回 complete exact-target scan。它让 named merged PR 可复审,但不会把 merged history 重新带回普通队列。 -
安装与文档面
capability README、
loopx-pr-reviewskill、doctor freshness phrase、bootstrap/install smoke 同步更新,避免本机安装后的 instruction surface 仍告诉 agent 默认跑--state all。
精确 diff 为 10 个文件,+117/-26,主要新增量集中在状态组合与 regression coverage;没有引入新 scheduler、queue abstraction 或 durable state。
对主干的风险
最强风险是兼容性:某个 caller 可能把“省略 state”当成“我要历史全量”。这个 PR 的处理是合理的,因为历史能力没有删除,仍可显式 --state merged 或 --state all;CLI help、capability docs 和 installed skill 都披露了新默认。
我重点验证了四个容易出错的分支:
- 普通省略 state:只查询 open,packet 中
state_filter=open、merged_pr_count=0; - 显式
--state all:仍分别读取 open/closed 并保留 lifecycle groups; - 省略 state 的 named merged exact head:走 direct target,能够读取;
- named merged target + 显式
--state open:显式 filter 保持权威,目标被 packet missing-target gate 拒绝,不会暗中放宽。
本地结果:examples/pr-review-command-smoke.py 通过;tests/test_pr_review_github_scan.py 与 tests/test_doctor_install_freshness.py 共 58 项通过;Ruff、git diff --check、当前 origin/main merge-tree 均通过。远端现有失败是 refresh-state sidecar fixture 缺 progress 字段,与本 PR 的 PR-review lifecycle 路径无关;本轮 packet 的 policy 也明确 wait_for_ci=false,因此我没有把无关聚合红灯冒充本 PR 的语义缺口。
语义与 CI 对齐
这个 change 重用既有 open|merged|all lifecycle vocabulary 和 direct exact-head contract,没有创建新语义。默认行为改变已经在 help、docs、skill 与 smoke 中双向披露;没有 substring classification,也没有把 guidance 伪装成 obligation。
我的整体评价
这个修复关闭了“审一两个 PR 却必须全量扫 merged history”的根因,而不是简单提高 limit。它同时保住了两个重要兼容边界:显式历史审计仍可用,named exact head 仍 lifecycle-neutral。实现小、owner 清晰、回滚直接,相关负向路径也有覆盖。
我对 exact head c5a017408551cdb344d06abb4a2992638f8d50ac 给出批准结论。该结论只覆盖代码审阅;GitHub 当前仍是 review-required/blocked,且本轮没有执行 merge-readiness 或合并。
English verdict: APPROVE - Ordinary PR-review discovery now defaults to open PRs, historical scans require explicit merged|all, and direct exact-head review remains lifecycle-neutral without expanding into merged history. Focused CLI, regression, static, and current-main integration checks passed.
Goal
Keep ordinary PR-review discovery focused on actionable open PRs. Historical merged PRs should enter only when the caller explicitly requests a lifecycle or post-merge audit.
Root cause and change
The CLI parser, internal scan/packet APIs, and installed PR-review skill all shared or reinforced a default of
all. That coupled ordinary queue discovery to historical audit and could saturate the packet with merged PRs.openacross CLI and internal APIs.--state mergedor--state allfor historical audits.--stateis omitted, so a named merged exact head remains reviewable.Validation
examples/pr-review-command-smoke.py: passedexamples/bootstrap-command-pack-smoke.py: passedexamples/install-local-smoke.py: passed standalonepytest tests/test_pr_review_github_scan.py tests/test_doctor_install_freshness.py: 58 passedFuture-facing pass
The state decision is centralized at the CLI boundary only where explicit exact-target intent is available; internal APIs keep the safer open default. No new scheduler, queue, or compatibility framework is introduced.