Skip to content

feat(review-gate): PR 自动审查闸门组件 + mcp-server --call 模式 - #15

Merged
tizerluo merged 5 commits into
mainfrom
feat/review-gate
Aug 9, 2026
Merged

feat(review-gate): PR 自动审查闸门组件 + mcp-server --call 模式#15
tizerluo merged 5 commits into
mainfrom
feat/review-gate

Conversation

@tizerluo

@tizerluo tizerluo commented Aug 9, 2026

Copy link
Copy Markdown
Owner

概要

第 4 个组件 packages/review-gate:常驻轮询 GitHub 仓库 open PR,对新 head sha 调 zcode_pr_review 完成审查(git diff + mimosa 深扫 + zcode 只读复核),带 verdict(pass/concerns + P0/P1/P2 分布)回贴 PR 评论。state 文件按 head sha 去重,失败指数退避。systemd --user 单元随包提供。

变更

  • packages/review-gate/:gate 脚本 + zcode-review-gate.service + README(安装/卸载/配置/运维/限制)
  • packages/mcp-server/zcode-mcp-server:新增 --call <tool> '<json>' 一次性调用模式(+43 行零侵入,exit 0/1/2;锁/限流/只读护栏全走 TOOL_HANDLERS 路径)
  • tests/test_review_gate.py + tests/test_mcp_call.py(+34 用例,全 fake 不碰网络/真实 git)
  • CI ruff/perms 登记第 4 组件;顶层 README 加组件行

验证

  • unittest 387 全绿(含既有 353 零回归);ruff CI 同口径全绿;组件 100755
  • 独立 subagent code review 两轮:无 P0、2P1+9P2 清零,冗余红线通过(无重复实现)
  • GC-8G 实测 openagentemail PR#5 全链路:检测→deep 审查→verdict=pass→评论发布(issuecomment-5228132228);同 sha 去重、退避重试、评论禁用、fail-safe 路径均实测;systemd --user 常驻 active+enabled
  • 实测抓出并修复:git 认证 Basic header(OAuth token 拒 Bearer)、超时余量、mcp_server PATH 回退

6tizer added 5 commits August 8, 2026 16:17
Add the 4th component: zcode-review-gate, a polling daemon that watches
open PRs on configured GitHub repos, reviews each new head sha via the
bridge's zcode_pr_review (git diff + mimosa deep scan + read-only ZCode
recheck), and posts the pass/concerns verdict back as a PR comment.
Same head sha is never reviewed twice (state-file dedup); failures retry
with exponential backoff. Tokens never touch disk (injected per-command
via git -c http.extraHeader).

Also add a one-shot '--call TOOL <json>' mode to zcode-mcp-server so
scripts/daemons can invoke a single tool without a stdio MCP session;
locks/retries/read-only guardrails all go through the same TOOL_HANDLERS
path. stdio behavior is unchanged.
P1:
- inject git token via GIT_CONFIG_COUNT/KEY/VALUE env (git>=2.31)
  instead of -c argv; env is per-user, argv leaks to ps. GitError
  messages never include env content (pinned by test)
- pass ZCODE_BRIDGE_REVIEW_TIMEOUT=REVIEW_TIMEOUT(3600) to the --call
  subprocess so mcp-server's default 300s zcode timeout can't cut
  deep-tier reviews short

P2:
- verdict regex excludes 'P' in the gap (P0[^\dP]{0,12}) so the
  'P0/P1/P2 各 0/0/2' enumeration format fails parsing to None
  (fail-safe concerns + note) instead of misreading numbers
- cache review result (report/verdict/counts) in state on comment
  failure (status=comment_failed); retry with same head only re-posts
  the comment, never re-runs the expensive zcode review; cache cleared
  once reviewed
- rate-limit detection: also treat bare 429 and Retry-After header as
  RateLimited, preferring Retry-After over X-RateLimit-Reset
- clone: dedicated 600s timeout, cleanup on failure, self-heal
  incomplete clones via rev-parse check (delete + rebuild)
- clamp config lower bounds (poll>=30s, retry base>=1, max>=base,
  attempts>=1) and comment max_body>=2000
- derive git web base from github_api (api.github.com->github.com,
  GHE <host>/api/v3-><host>)
- include subprocess stderr tail (500 chars) in review failure errors
- re-read 'now' per PR instead of once per round
- systemd unit: TimeoutStopSec=120 with rationale; docs updated
  (status enum pending/comment_failed, --call exit 1 wording, timeout
  passthrough, token env wording)

Tests: 27 new cases (380 total) covering all of the above; ruff clean
- ensure_clone: only rc!=0 rev-parse failures trigger delete+rebuild;
  transient faults (OSError/TimeoutExpired) re-raise as repo-level
  round failure so a healthy clone is never deleted on a hiccup
- split review timeouts: ZCODE_REVIEW_TIMEOUT (3600, passed through to
  mcp-server's zcode budget) vs REVIEW_TIMEOUT (= +120s headroom for
  the mimosa scan and process teardown on the gate side)
- README: note gave_up keeps the cached report (<=max_body each) in
  the state file for forensics (watch its size), and that PR comments
  are at-least-once (issue comments have no idempotency key)
…rer)

GitHub's git smart-HTTP endpoints reject the Bearer scheme for OAuth
tokens (gho_*): 'remote: invalid credentials' on clone/fetch, while the
same token works fine as Bearer on the REST API. Switch the env-injected
http.extraHeader to Basic: base64('x-access-token:' + token), the
official placeholder username. REST (urllib) side keeps Bearer unchanged.
Verified live: ls-remote with x-access-token Basic succeeds with the
same token that failed as Bearer.
…t PATH

systemd --user defaults to PATH=/usr/local/bin:/usr/bin:/bin (no
~/.local/bin), while the standard install puts components in
~/.local/bin — so a bare mcp_server name always failed with
FileNotFoundError under the default deployment form (GC-8G live test).

Two-pronged fix:
- gate resolves a bare mcp_server name via PATH first, then falls back
  to ~/.local/bin/<name> when it exists and is executable (DEBUG-logged);
  anything else is passed through to the existing OSError path
- the unit template now ships Environment=PATH=%h/.local/bin:... by
  default instead of mentioning it as optional; README install/config
  wording updated
@tizerluo
tizerluo merged commit 689c10a into main Aug 9, 2026
4 checks passed
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.

2 participants