Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions .github/workflows/ai-pr-review-v2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ jobs:

- name: Claude Code review
id: review
# Advisory gate: an infra failure (turn exhaustion, rate limit, action
# outage) must never red-flag or block an otherwise healthy PR. The
# approve step below only runs on an explicit no-blockers verdict, so
# failing soft here degrades to "no automated approval", never to
# "silently approved".
continue-on-error: true
uses: anthropics/claude-code-action@v1
with:
# Subscription OAuth token (Pro/Max). Absent on fork PRs -> action no-ops.
Expand Down Expand Up @@ -98,10 +104,19 @@ jobs:
# steps.review.outputs.structured_output.
claude_args: |
--model claude-opus-4-8
--max-turns 15
--max-turns 40
--allowedTools "Read,Grep,Glob,Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr comment:*),mcp__github_inline_comment__create_inline_comment"
--json-schema '{"type":"object","properties":{"has_blockers":{"type":"boolean"},"p0_count":{"type":"integer"},"summary":{"type":"string"}},"required":["has_blockers","p0_count","summary"],"additionalProperties":false}'

# Make a soft-failed review visible instead of silently green.
- name: Note when the review did not produce a verdict
if: steps.review.outcome != 'success' || steps.review.outputs.structured_output == ''
run: |
echo "AI review did not produce a machine-readable verdict (outcome: ${{ steps.review.outcome }})." \
| tee -a "$GITHUB_STEP_SUMMARY"
echo "This is advisory only and does not block the PR. Human review still applies." \
>> "$GITHUB_STEP_SUMMARY"

# ── Deterministic verdict gate (NOT the model) ──────────────────────────
# Reads the machine-readable verdict. On zero blockers: label + approve.
# Approval uses the dedicated approver PAT and is best-effort: a missing
Expand All @@ -117,7 +132,11 @@ jobs:
FALLBACK_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
SUMMARY: ${{ fromJSON(steps.review.outputs.structured_output).summary }}
# NOTE: `env:` expressions are evaluated even when the step's `if:` is
# false, so this MUST be guarded independently. An unguarded
# fromJSON('') is a workflow *template* parse error ("Error reading
# JToken from JsonReader") that fails the whole run, not a skipped step.
SUMMARY: ${{ steps.review.outputs.structured_output != '' && fromJSON(steps.review.outputs.structured_output).summary || '' }}
run: |
set -uo pipefail
# Label with the Actions token (can write issues). Best-effort.
Expand Down
Loading