From 3bca33ba75e166d9ac7855d63f217678a637c6c4 Mon Sep 17 00:00:00 2001 From: MauroFab Date: Tue, 23 Jun 2026 18:14:20 -0300 Subject: [PATCH 1/2] =?UTF-8?q?fix(ci):=20AI=20review=20=E2=80=94=20accept?= =?UTF-8?q?=20/review-ai=20alias,=20raise=20turn=20cap,=20scope=20agent=20?= =?UTF-8?q?commands?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Accept both /ai-review and /review-ai as the trigger command (in the prepare gate, the concurrency cancel gate, and is_review_command), so a misremembered command no longer silently skips every job. - Raise claude-review max_turns 30 -> 50. Reviews die at 30 not because the work needs it (clean reviews finish in ~18-24 turns) but it leaves no headroom; 50 is a safety ceiling, not a budget. - Tell the native Codex/Claude agents (via general.md custom_prompt) which commands they may run and that they must not build/test/fetch or retry sandbox-denied commands. On PR #703 ~46% of Claude's tool calls were denied fetch/cargo/redirect attempts, exhausting the turn budget. --- .github/ai-review/prompts/general.md | 14 ++++++++++++++ .github/scripts/ai_review.py | 6 ++++-- .github/workflows/pr_ai_review.yaml | 7 ++++--- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.github/ai-review/prompts/general.md b/.github/ai-review/prompts/general.md index 1564caac0..343f8fea8 100644 --- a/.github/ai-review/prompts/general.md +++ b/.github/ai-review/prompts/general.md @@ -21,3 +21,17 @@ Guidelines: - Always prefer simplicity over complexity when performance gains are marginal - Focus on real issues, not hypothetical improvements - Be concise and actionable + +Environment — review statically with the tools you have: +- This is a static code review in a sandbox. The PR branch is ALREADY checked out in the + working directory and the diff is provided to you — read the changed files and their + dependencies directly. You do not need to (and cannot) fetch anything. +- You MAY use only: reading files, grep, glob, `gh pr view`, `gh pr diff`, `gh pr comment`, + `cargo tree`, `cargo metadata`, `npm list`/`npm ls`, and `forge inspect`. Inline comments + go through the provided inline-comment tool. +- You may NOT build, test, or reach the network: no `cargo build`/`cargo check`/`cargo test`/ + `cargo clippy`, no `git fetch`/`git clone`/`git checkout` of other refs. These are blocked + and CI already builds and tests the PR — do not attempt them. +- If a command is denied or fails, do NOT retry it, do NOT try variations to work around the + sandbox, and do NOT report the failure as a review finding. Skip it and continue with the + tools above. Never block or end the review because a command could not run. diff --git a/.github/scripts/ai_review.py b/.github/scripts/ai_review.py index e4d816d61..82a6ea808 100644 --- a/.github/scripts/ai_review.py +++ b/.github/scripts/ai_review.py @@ -748,8 +748,10 @@ def cmd_report(args: argparse.Namespace) -> int: def is_review_command(body: str) -> bool: - # Any /ai-review comment (with or without a legacy standard|critical argument). - return bool(re.search(r"(?im)^\s*/ai-review\b", body)) + # Any /ai-review (or its easy-to-misremember alias /review-ai) comment, with or + # without a legacy standard|critical argument. Keep this in sync with the + # `contains(...)` gates in pr_ai_review.yaml (prepare `if:` and concurrency). + return bool(re.search(r"(?im)^\s*/(ai-review|review-ai)\b", body)) def is_review_label(name: str) -> bool: diff --git a/.github/workflows/pr_ai_review.yaml b/.github/workflows/pr_ai_review.yaml index 4741ce592..6d6e65b0a 100644 --- a/.github/workflows/pr_ai_review.yaml +++ b/.github/workflows/pr_ai_review.yaml @@ -8,6 +8,7 @@ on: # One review at a time per PR; a genuine re-request cancels the in-flight run so # rapid re-labels/`/ai-review` comments can't race and post duplicate reports. +# Both `/ai-review` and `/review-ai` are accepted (the name is easy to misremember). # # cancel-in-progress is gated on the trigger being a REAL request. The native # claude-review job posts its report as a GitHub App comment (claude[bot]), and @@ -19,7 +20,7 @@ on: # Gating the cancel means such non-command comments queue-and-skip instead. concurrency: group: ai-review-${{ github.event.pull_request.number || github.event.issue.number }} - cancel-in-progress: ${{ github.event_name == 'pull_request' || (github.event_name == 'issue_comment' && contains(github.event.comment.body, '/ai-review')) }} + cancel-in-progress: ${{ github.event_name == 'pull_request' || (github.event_name == 'issue_comment' && (contains(github.event.comment.body, '/ai-review') || contains(github.event.comment.body, '/review-ai'))) }} # Default least-privilege: read-only. Only the jobs that need to write (final-report # posts the comment; the native reviews) request write/id-token at the job level. @@ -33,7 +34,7 @@ jobs: ( github.event_name == 'issue_comment' && github.event.issue.pull_request && - contains(github.event.comment.body, '/ai-review') && + (contains(github.event.comment.body, '/ai-review') || contains(github.event.comment.body, '/review-ai')) && contains(fromJson('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association) ) || ( @@ -515,7 +516,7 @@ jobs: uses: yetanotherco/actions/.github/workflows/pr_review_claude.yml@v1.0.0 with: model: opus - max_turns: 30 + max_turns: 50 custom_prompt: ${{ needs.prepare.outputs.custom_prompt }} secrets: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} From 6e89110c4399ed348af7cdea755b9ca285704c26 Mon Sep 17 00:00:00 2001 From: MauroFab Date: Tue, 23 Jun 2026 18:16:47 -0300 Subject: [PATCH 2/2] docs(ci): drop stale references to removed ai-review-standard/-critical labels --- .github/scripts/ai_review.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/scripts/ai_review.py b/.github/scripts/ai_review.py index 82a6ea808..24e5a5f6c 100644 --- a/.github/scripts/ai_review.py +++ b/.github/scripts/ai_review.py @@ -748,14 +748,15 @@ def cmd_report(args: argparse.Namespace) -> int: def is_review_command(body: str) -> bool: - # Any /ai-review (or its easy-to-misremember alias /review-ai) comment, with or - # without a legacy standard|critical argument. Keep this in sync with the - # `contains(...)` gates in pr_ai_review.yaml (prepare `if:` and concurrency). + # Any /ai-review (or its easy-to-misremember alias /review-ai) comment. A trailing + # word (e.g. an old `standard`/`critical` argument) is tolerated and ignored. Keep + # this in sync with the `contains(...)` gates in pr_ai_review.yaml (prepare `if:` + # and concurrency). return bool(re.search(r"(?im)^\s*/(ai-review|review-ai)\b", body)) def is_review_label(name: str) -> bool: - # Any ai-review* label (including the legacy ai-review-standard/-critical labels). + # The `ai-review` label. `startswith` also matches any leftover `ai-review-*` label. return name.strip().lower().startswith("ai-review")