Add replayable closeout evidence gates #316
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Claude Code Review | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, ready_for_review, reopened] | |
| jobs: | |
| claude-review: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| id-token: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 1 | |
| - name: Run Claude Code Review | |
| id: claude-review | |
| uses: anthropics/claude-code-action@v1 | |
| with: | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| allowed_bots: "dependabot[bot]" | |
| prompt: | | |
| REPO: ${{ github.repository }} | |
| PR NUMBER: ${{ github.event.pull_request.number }} | |
| Please review this pull request with a focus on: | |
| - Code quality and best practices | |
| - Potential bugs or issues | |
| - Security implications | |
| - Performance considerations | |
| - Portability: shared skills and workflows must stay generic. Flag any | |
| consumer-repo commands, labels, branches, release trackers, or paths | |
| hardcoded in `skills/` or `workflows/` (see AGENTS.md "Editing Rules"). | |
| - Shell and Ruby helper safety in `bin/` and `skills/*/bin/`. | |
| Note: The PR branch is already checked out in the current working directory. | |
| Use `gh pr comment` for top-level feedback. | |
| Use `mcp__github_inline_comment__create_inline_comment` to highlight specific code issues. | |
| Only post GitHub comments - don't submit review text as messages. | |
| claude_args: | | |
| --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)" | |
| # The action exits 0 even when the review never ran: token auth failures, | |
| # expired tokens, or exhausted credits can fail before model work starts, | |
| # yet the result still reports a green "pass" and posts no review. Inspect | |
| # the execution output and fail any Claude-level error. | |
| # | |
| # Scoped to outcome == 'success' on purpose. When the action itself fails | |
| # (missing token on Dependabot PRs, the "workflow validation failed" safety | |
| # skip on PRs that edit this file, a real action error) the job is already | |
| # red and the action prints its own message, so re-failing here would only | |
| # add a misleading one. And a successful run that legitimately skips Claude | |
| # (so emits no execution_file/result) is treated as a pass, not a failure. | |
| - name: Verify review completed (fail on Claude error) | |
| if: steps.claude-review.outcome == 'success' | |
| env: | |
| EXECUTION_FILE: ${{ steps.claude-review.outputs.execution_file }} | |
| run: | | |
| set -euo pipefail | |
| TOKEN_HINT="Check CLAUDE_CODE_OAUTH_TOKEN auth, available credits/quota, and the repo secret. Rotate with 'claude setup-token' if needed." | |
| # No execution output: the action skipped Claude (e.g. the workflow- | |
| # validation safety skip). Nothing was claimed to run, so let it pass. | |
| if [ -z "${EXECUTION_FILE:-}" ] || [ ! -f "$EXECUTION_FILE" ]; then | |
| echo "No execution output found; the action skipped Claude. Nothing to verify." | |
| exit 0 | |
| fi | |
| # The execution file may be a JSON array or newline-delimited JSON; | |
| # slurp + flatten handles both, then grab the final result record. | |
| result=$(jq -s 'flatten | map(select(type == "object" and .type == "result")) | last' "$EXECUTION_FILE" 2>/dev/null || echo null) | |
| if [ "$result" = "null" ] || [ -z "$result" ]; then | |
| echo "No result record in execution output; nothing to verify." | |
| exit 0 | |
| fi | |
| is_error=$(echo "$result" | jq -r '.is_error // false') | |
| cost=$(echo "$result" | jq -r '.total_cost_usd // 0') | |
| turns=$(echo "$result" | jq -r '.num_turns // 0') | |
| echo "Claude review result: is_error=$is_error total_cost_usd=$cost num_turns=$turns" | |
| # is_error=true with $0 cost and a single turn means Claude could not | |
| # start real model work. Nonzero-cost errors mean Claude ran but ended | |
| # in an error state. Either way, no review should be treated as valid. | |
| if [ "$is_error" = "true" ]; then | |
| if [ "$cost" = "0" ] && [ "$turns" -le 1 ]; then | |
| echo "::error::Claude review failed before model work (is_error=true, cost=$cost, turns=$turns). $TOKEN_HINT" | |
| else | |
| echo "::error::Claude review session ended in error (is_error=true, cost=$cost, turns=$turns). Inspect the execution output for details. $TOKEN_HINT" | |
| fi | |
| exit 1 | |
| fi |