EIP-8141: per-payer mempool exposure accounting for frame transactions #28488
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
| # Claude Code Review workflow | |
| # | |
| # This workflow has two modes: | |
| # | |
| # 1. Review path — triggered automatically on same-repository PR open / ready-for-review, | |
| # and manually when a trusted maintainer comments a variant of "@claude review". Runs | |
| # Claude with a fixed review prompt, captures a structured `mergeable` verdict via | |
| # --json-schema, and posts a `claude-review/reviewed` commit status (success/failure) | |
| # that branch protection uses to gate merging. | |
| # | |
| # 2. Mention path — triggered by any other `@claude ...` comment/mention (e.g. | |
| # `@claude explain X`, `@claude fix Y`). Runs Claude with the comment body as its prompt, | |
| # does NOT post a commit status, and does NOT force structured output. | |
| # | |
| # PRs marked as WIP (via the `wip` label or a WIP marker in the title) are skipped by the | |
| # auto-trigger; removing the `wip` label is itself a trigger so authors can "release" a WIP | |
| # for review. Manual `@claude review` comments always work, regardless of WIP state. | |
| name: Claude Code Review | |
| on: | |
| issue_comment: | |
| types: [created] | |
| pull_request_review_comment: | |
| types: [created] | |
| issues: | |
| types: [opened] | |
| pull_request_review: | |
| types: [submitted] | |
| # `unlabeled` is included so that removing the `wip` label triggers a review. | |
| pull_request: | |
| types: [opened, ready_for_review, unlabeled] | |
| jobs: | |
| claude: | |
| # Gate the job on either: | |
| # - a same-repository pull_request event that is NOT a WIP PR (label/title filter), OR | |
| # - an unlabeled event where the removed label was specifically `wip`, OR | |
| # - an `@claude` mention on comments/reviews/issues from a trusted author. | |
| # | |
| # The `author_association` guard on mention paths is a security boundary: `issue_comment` | |
| # and related events always run in the base-repo context with full secret access, even | |
| # for comments on fork PRs, so without this guard an external contributor could trigger | |
| # a Claude run (consuming the OAuth token) by commenting `@claude ...` on their own PR. | |
| # Auto-triggered reviews are limited to same-repository PRs. Fork PRs run with a | |
| # read-only token and no secrets, so the Claude action cannot mint an OIDC token or | |
| # post the required `claude-review/reviewed` status. Maintainers can still trigger a | |
| # review manually with `@claude review`, which runs in the base-repo context. | |
| if: | | |
| (github.event_name == 'pull_request' && ( | |
| github.event.pull_request.head.repo.full_name == github.repository && | |
| ( | |
| (github.event.action == 'unlabeled' && github.event.label.name == 'wip') || | |
| ( | |
| (github.event.action == 'opened' || github.event.action == 'ready_for_review') && | |
| !contains(github.event.pull_request.labels.*.name, 'wip') && | |
| !startsWith(github.event.pull_request.title, 'WIP') && | |
| !contains(github.event.pull_request.title, '[WIP]') && | |
| !contains(github.event.pull_request.title, '[wip]') | |
| ) | |
| ) | |
| )) || | |
| (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude') && | |
| contains(fromJSON('["MEMBER","COLLABORATOR","OWNER"]'), github.event.comment.author_association)) || | |
| (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude') && | |
| contains(fromJSON('["MEMBER","COLLABORATOR","OWNER"]'), github.event.comment.author_association)) || | |
| (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude') && | |
| contains(fromJSON('["MEMBER","COLLABORATOR","OWNER"]'), github.event.review.author_association)) || | |
| (github.event_name == 'issues' && | |
| (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) && | |
| contains(fromJSON('["MEMBER","COLLABORATOR","OWNER"]'), github.event.issue.author_association)) | |
| runs-on: ubuntu-latest | |
| env: | |
| RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| issues: write | |
| id-token: write # Required by anthropics/claude-code-action for OIDC auth | |
| actions: read # Required for Claude to read CI results on PRs | |
| statuses: write # Required to post the claude-review/reviewed commit status | |
| steps: | |
| # Classify this invocation as a review (→ review path, posts commit status) or a | |
| # generic @claude mention (→ mention path, no status). The classification is used | |
| # as the `if:` gate on the subsequent steps. | |
| - name: Detect review intent | |
| id: detect | |
| env: | |
| COMMENT_BODY: ${{ github.event.comment.body }} | |
| REVIEW_BODY: ${{ github.event.review.body }} | |
| run: | | |
| # Job-level `if:` already ensures `@claude` is present for comment/review events. | |
| # Here we classify: a comment/review that also mentions "review" (any case) runs | |
| # the review path (structured output + commit status). Anything else — e.g. | |
| # `@claude implement X`, `@claude explain Y` — falls through to the mention path. | |
| IS_REVIEW=false | |
| case "$GITHUB_EVENT_NAME" in | |
| pull_request) | |
| # Auto-triggers (opened, ready_for_review, unlabeled-wip) are always reviews. | |
| IS_REVIEW=true | |
| ;; | |
| issue_comment|pull_request_review_comment) | |
| [[ "${COMMENT_BODY,,}" == *"review"* ]] && IS_REVIEW=true | |
| ;; | |
| pull_request_review) | |
| [[ "${REVIEW_BODY,,}" == *"review"* ]] && IS_REVIEW=true | |
| ;; | |
| esac | |
| echo "is_review=$IS_REVIEW" >> "$GITHUB_OUTPUT" | |
| - name: Checkout repository | |
| uses: actions/checkout@v6 | |
| # Review path: runs for auto-triggers and for @claude comments mentioning "review". | |
| # - `track_progress: true` renders the v0.x-style tracking comment with checkboxes. | |
| # - The prompt is fixed (overrides whatever the user wrote in the comment), so Claude | |
| # always produces a full Nethermind-flavored review with severity-tagged findings. | |
| # - `--json-schema` forces Claude's final result message into a structured JSON we | |
| # parse in the status-posting step below. This JSON is NOT shown to humans — Claude | |
| # still posts rich prose comments via the gh/MCP tools; the JSON is just the verdict. | |
| - name: Run Claude Code (review path) | |
| timeout-minutes: 20 | |
| if: steps.detect.outputs.is_review == 'true' | |
| id: claude_review | |
| uses: anthropics/claude-code-action@v1 | |
| with: | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| track_progress: ${{ github.event.action != 'unlabeled' }} # not supported for unlabeled events | |
| prompt: | | |
| REPO: ${{ github.repository }} | |
| PR NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} | |
| Review this pull request focusing on: | |
| - Correctness, edge cases, and potential regressions | |
| - Security implications | |
| - Performance (this is a hot-path Ethereum execution client) | |
| - Adherence to repo rules in CONTRIBUTING.md and .agents/rules/ | |
| Categorize each finding by severity: | |
| - **Critical**: blocks merge, likely production impact | |
| - **High**: significant issue, should be addressed before merge | |
| - **Medium**: notable issue, should be addressed or explicitly acknowledged with rationale | |
| - **Low**: minor suggestions | |
| Post a top-level summary with `gh pr comment`. Use `mcp__github_inline_comment__create_inline_comment` for specific code issues. | |
| Set `mergeable: false` in the structured output if any Critical, High, or Medium findings exist that have not been explicitly acknowledged with rationale in prior PR comments. Otherwise `mergeable: true`. | |
| claude_args: | | |
| --model opus | |
| --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh:*),WebFetch" | |
| --json-schema '{"type":"object","properties":{"mergeable":{"type":"boolean","description":"False if any Critical, High, or Medium findings remain unresolved and unexplained"},"critical_count":{"type":"integer"},"high_count":{"type":"integer"},"medium_count":{"type":"integer"},"summary":{"type":"string"}},"required":["mergeable","critical_count","high_count","medium_count","summary"]}' | |
| # Mention path: any other `@claude ...` interaction (no "review" keyword). No prompt | |
| # is supplied, so the action parses the comment body and runs Claude against it — | |
| # preserving the original "@claude do this thing" behaviour for implementation help, | |
| # explanations, etc. No commit status is posted in this path. | |
| - name: Run Claude Code (mention path) | |
| timeout-minutes: 20 | |
| if: steps.detect.outputs.is_review != 'true' | |
| id: claude_mention | |
| uses: anthropics/claude-code-action@v1 | |
| with: | |
| claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| claude_args: | | |
| --model opus | |
| --allowedTools "Bash(gh:*),WebFetch" | |
| # After a successful review, read the structured verdict from the previous step and | |
| # post a commit status on the PR head SHA: | |
| # - mergeable == true → state=success, merging is allowed | |
| # - mergeable == false → state=failure, branch protection will block merging | |
| # Statuses are keyed by (sha, context), so a later re-review overwrites the previous | |
| # verdict on the same commit. Pushing new commits changes the SHA and leaves the new | |
| # commit with no status → branch protection blocks until `@claude review` is re-run. | |
| - name: Post claude-review status (success) | |
| if: success() && steps.detect.outputs.is_review == 'true' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| STRUCTURED: ${{ steps.claude_review.outputs.structured_output }} | |
| REPO: ${{ github.repository }} | |
| PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} | |
| run: | | |
| # Resolve the PR head SHA. Works for both pull_request events (where PR_NUMBER | |
| # comes from event.pull_request.number) and comment events (from event.issue.number). | |
| SHA=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json headRefOid --jq .headRefOid) | |
| # `// default` in jq guards against missing/malformed fields — we default to the | |
| # most conservative interpretation (not mergeable, zero counts reported). | |
| MERGEABLE=$(printf '%s' "$STRUCTURED" | jq -r '.mergeable // false') | |
| CRIT=$(printf '%s' "$STRUCTURED" | jq -r '.critical_count // 0') | |
| HIGH=$(printf '%s' "$STRUCTURED" | jq -r '.high_count // 0') | |
| MED=$(printf '%s' "$STRUCTURED" | jq -r '.medium_count // 0') | |
| SUMMARY=$(printf '%s' "$STRUCTURED" | jq -r '.summary // ""' | tr '\n' ' ') | |
| if [[ "$MERGEABLE" == "true" ]]; then | |
| STATE=success | |
| PREFIX="Claude reviewed: no blockers" | |
| else | |
| STATE=failure | |
| PREFIX="Claude blockers: $CRIT critical, $HIGH high, $MED medium" | |
| fi | |
| # GitHub truncates commit status descriptions at 140 chars in the UI; build | |
| # "<prefix> — <summary>" and clip so the summary surfaces directly in the PR checks. | |
| if [[ -n "$SUMMARY" ]]; then | |
| DESC="$PREFIX — $SUMMARY" | |
| else | |
| DESC="$PREFIX" | |
| fi | |
| DESC="${DESC:0:140}" | |
| gh api "repos/$REPO/statuses/$SHA" \ | |
| -f state="$STATE" \ | |
| -f context=claude-review/reviewed \ | |
| -f description="$DESC" \ | |
| -f target_url="$RUN_URL" | |
| # If the action itself errored out (API timeout, rate limit, schema violation, etc.) | |
| # we still need to record a non-success status so branch protection keeps the PR | |
| # blocked. `state=error` is distinct from `failure` so reviewers can tell the workflow | |
| # broke vs. Claude flagged blockers. | |
| - name: Post claude-review status (error) | |
| if: failure() && steps.detect.outputs.is_review == 'true' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| REPO: ${{ github.repository }} | |
| PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} | |
| run: | | |
| SHA=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json headRefOid --jq .headRefOid) | |
| gh api "repos/$REPO/statuses/$SHA" \ | |
| -f state=error \ | |
| -f context=claude-review/reviewed \ | |
| -f description="Claude review workflow failed; please re-run with @claude review" \ | |
| -f target_url="$RUN_URL" |