Skip to content

fix(pr-review): default ordinary queues to open PRs - #4878

Merged
huangruiteng merged 1 commit into
mainfrom
codex/pr-review-default-open
Sep 22, 2026
Merged

huangruiteng merged 1 commit into
mainfrom
codex/pr-review-default-open

Conversation

@huangruiteng

Copy link
Copy Markdown
Collaborator

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.

  • Default omitted lifecycle state to open across CLI and internal APIs.
  • Require explicit --state merged or --state all for historical audits.
  • Preserve lifecycle-neutral exact-target reads when --state is omitted, so a named merged exact head remains reviewable.
  • Update doctor skill-freshness phrases and document the durable self-repair pattern.
  • Add regression coverage for live open-only scanning, explicit all-state grouping, and merged exact-target behavior.

Validation

  • examples/pr-review-command-smoke.py: passed
  • examples/bootstrap-command-pack-smoke.py: passed
  • examples/install-local-smoke.py: passed standalone
  • pytest tests/test_pr_review_github_scan.py tests/test_doctor_install_freshness.py: 58 passed
  • Ruff: passed
  • semantic vocabulary smoke: passed after installing the repositories declared TypeScript dependencies
  • public/private boundary scan: passed
  • risk-profile canaries: 8/8 passed
  • premerge catalog: 9/10 passed; the same standalone install smoke exceeded the shared 120-second canary budget on one rerun after passing standalone, with no assertion failure

Future-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.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 默认。

具体改动

关键代码讲解

  1. 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。

  2. loopx/pr_review.py::normalize_pr_state_filter

    None 与 internal unknown 现在安全归一为 open;fetch_github_pull_requests、scan_github_pull_requests、build_pr_review_packet 的默认也一致改成 open。普通 live scan 因此只发出一次 gh pr list --state open。

  3. 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 重新带回普通队列。

  4. 安装与文档面

    capability README、loopx-pr-review skill、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.

@huangruiteng
huangruiteng merged commit 8f56751 into main Sep 22, 2026
24 of 27 checks passed
@huangruiteng
huangruiteng deleted the codex/pr-review-default-open branch September 22, 2026 02:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant