From 2253451212c8cec53d6d13eb7a05053f85791a0a Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Wed, 6 May 2026 22:49:13 -0400 Subject: [PATCH] ci: upgrade deep review to compound-engineering v3.6.1 - Bump plugin pin from v2.42.0 to compound-engineering-v3.6.1. - Rename "compound review" workflows to "deep review" (deep-review.yml, deep-resolve.yml). - Add deep-resolve.yml -- author can comment /just-fix-it on a PR to have the review findings auto-applied (P0/P1 plus mechanical P2). Same-repo PRs only; collaborator-gated. - Remove the compound-review label gate; deep review now runs on every non-draft PR mirroring claude-code-review.yml. - Drop compound-engineering.local.md. v3.x removed the review_agents: pinning mechanism; reviewer selection is orchestrator-driven from the diff (4 always-on personas + cross-cutting/stack-specific selected by the LLM, ~6-13 reviewers per PR). - Update the JSON envelope marker from to . --- .github/workflows/claude-code-review.yml | 2 +- .github/workflows/deep-resolve.yml | 196 ++++++++++++++++++ .../{compound-review.yml => deep-review.yml} | 72 ++++--- 3 files changed, 238 insertions(+), 32 deletions(-) create mode 100644 .github/workflows/deep-resolve.yml rename .github/workflows/{compound-review.yml => deep-review.yml} (77%) diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 1cb9d39c76..d6137f45c5 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -138,7 +138,7 @@ jobs: # output a second time so the comment body posts as raw JSON. Detect # that case (the inner string parses as an object with a `review` key) # and unwrap once more so we post markdown, not JSON. Mirrors the same - # fix applied to compound-review.yml. + # fix applied to deep-review.yml. - name: Extract review from structured output id: extract-review env: diff --git a/.github/workflows/deep-resolve.yml b/.github/workflows/deep-resolve.yml new file mode 100644 index 0000000000..453b099383 --- /dev/null +++ b/.github/workflows/deep-resolve.yml @@ -0,0 +1,196 @@ +name: Deep Review Resolver + +# Triggered by a collaborator commenting `/just-fix-it` on a PR. Reads the +# latest sticky comment posted by deep-review.yml, +# hands the findings to Claude with edit + git tools, and pushes a single +# fix commit to the PR head branch. +# +# Limitations: +# - Same-repo PRs only. Fork PRs cannot be pushed to from CI with the +# default GITHUB_TOKEN; the workflow exits early on forks. +# - Collaborator-gated. The job `if` requires OWNER/MEMBER/COLLABORATOR +# association on the triggering comment to prevent random drive-by use. +# - Single-shot. Re-trigger by commenting `/just-fix-it` again after the +# follow-up deep-review run posts an updated finding list. + +on: + issue_comment: + types: [created] + +concurrency: + group: deep-resolve-${{ github.event.issue.number }} + cancel-in-progress: true + +jobs: + resolve: + if: | + github.event.issue.pull_request != null && + startsWith(github.event.comment.body, '/just-fix-it') && + (github.event.comment.author_association == 'OWNER' || + github.event.comment.author_association == 'MEMBER' || + github.event.comment.author_association == 'COLLABORATOR') + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + issues: write + id-token: write + actions: read + + steps: + - name: Acknowledge trigger + uses: actions/github-script@v9 + with: + script: | + await github.rest.reactions.createForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id, + content: 'eyes', + }); + + - name: Resolve PR metadata + id: pr + uses: actions/github-script@v9 + with: + script: | + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.issue.number, + }); + const isFork = pr.head.repo.full_name !== pr.base.repo.full_name; + core.setOutput('number', String(pr.number)); + core.setOutput('head_repo', pr.head.repo.full_name); + core.setOutput('head_ref', pr.head.ref); + core.setOutput('is_fork', String(isFork)); + + - name: Reject fork PRs + if: steps.pr.outputs.is_fork == 'true' + uses: actions/github-script@v9 + with: + script: | + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.issue.number, + body: '\n⚠️ `/just-fix-it` is not supported on fork PRs — CI cannot push to a fork branch with the default token. Apply the review findings locally and push.', + }); + core.setFailed('Fork PR — auto-fix unavailable'); + + - name: Fetch latest deep review comment + id: review + uses: actions/github-script@v9 + with: + script: | + const comments = await github.paginate( + github.rest.issues.listComments, + { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.issue.number, + per_page: 100, + } + ); + const review = [...comments].reverse().find(c => + c.body && c.body.includes('')); + if (!review) { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.issue.number, + body: '\n⚠️ No deep review comment found on this PR. Wait for the review to post, then re-trigger with `/just-fix-it`.', + }); + core.setFailed('No deep review comment found'); + return; + } + core.setOutput('body', review.body); + + - name: Checkout PR head + uses: actions/checkout@v6 + with: + repository: ${{ steps.pr.outputs.head_repo }} + ref: ${{ steps.pr.outputs.head_ref }} + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - name: Set git author + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Enable corepack + run: corepack enable + + - name: Run Claude to apply fixes + uses: anthropics/claude-code-action@v1 + with: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + github_token: ${{ secrets.GITHUB_TOKEN }} + prompt: | + REPO: ${{ github.repository }} + PR NUMBER: ${{ steps.pr.outputs.number }} + BRANCH: ${{ steps.pr.outputs.head_ref }} + + The deep multi-agent review posted findings on this PR. Apply + fixes per the rules below. The PR head is already checked out + with push credentials configured. + + Review findings (verbatim): + --- + ${{ steps.review.outputs.body }} + --- + + Rules: + 1. Apply ALL P0 and P1 findings. + 2. Apply P2 findings only if the fix is mechanical (rename, + missing await, obvious typo, dead import). Skip ambiguous P2. + 3. Skip P3 entirely. + 4. If a finding is wrong (false positive) or out of scope for + the PR, skip it and note why in your summary. + 5. Make the smallest change that addresses each finding. Do not + refactor surrounding code, rename unrelated identifiers, or + touch files not cited by a finding. + + After edits: + 6. Run `yarn lint:fix` to auto-fix formatting. If it errors on + files you didn't touch, leave those alone. + 7. Stage and commit in a single commit: + git add -A + git commit -m "fix: address deep review findings" + Use that exact message. No Co-Authored-By trailers + (project convention; see AGENTS.md). + 8. Push: `git push origin HEAD` + 9. Post a summary comment on PR ${{ steps.pr.outputs.number }} + via `gh pr comment`. The comment body MUST start with + `` on its own line so future runs + can locate it. Then a brief markdown list: + - **Fixed:** one line per finding addressed (file:line - what) + - **Skipped:** one line per finding deliberately not fixed, + with reason + Keep the whole comment under 30 lines. + + If you make no edits at all (every finding skipped), do not + create an empty commit and do not push. Still post the summary + comment so the author sees why. + + claude_args: | + --setting-sources user + --allowedTools "Bash(git:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr comment:*),Bash(yarn lint:fix),Bash(yarn:*),Edit,Write,MultiEdit,Read,Grep,Glob" + + - name: React on failure + if: failure() + uses: actions/github-script@v9 + with: + script: | + await github.rest.reactions.createForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id, + content: 'confused', + }); diff --git a/.github/workflows/compound-review.yml b/.github/workflows/deep-review.yml similarity index 77% rename from .github/workflows/compound-review.yml rename to .github/workflows/deep-review.yml index 6b55dd2195..189ba83744 100644 --- a/.github/workflows/compound-review.yml +++ b/.github/workflows/deep-review.yml @@ -1,22 +1,31 @@ -name: Compound Engineering Code Review +name: Deep Code Review -# Opt-in, multi-agent PR review using EveryInc/compound-engineering-plugin's +# Multi-agent PR review using EveryInc/compound-engineering-plugin's # /ce-code-review skill. Runs alongside the default Claude review (which lives -# in claude-code-review.yml). Gated behind the `compound-review` label so it -# does not run on every PR -- the multi-agent fan-out is significantly more -# expensive than the default single-pass review. +# in claude-code-review.yml). # -# To trigger: -# - Add the `compound-review` label to a PR, or -# - Run the workflow manually via the Actions tab and pass a PR number. +# Reviewer selection is orchestrator-driven by the plugin in v3.x. 4 always-on +# personas (correctness, testing, maintainability, project-standards) run on +# every PR; cross-cutting and stack-specific reviewers (security, performance, +# api-contract, reliability, frontend-races, architecture, adversarial, etc.) +# are LLM-selected from the diff. Roster is not pinnable -- the v2.x +# `compound-engineering.local.md` / `review_agents:` mechanism was removed. +# Expect ~6-13 reviewers per PR depending on diff scope. +# +# Triggers automatically on every non-draft PR. The multi-agent fan-out is +# significantly more expensive than the default single-pass review, so expect +# higher Anthropic API spend and longer wall-clock latency than +# claude-code-review.yml. +# +# Author can request automated fixes for the findings by commenting +# `/just-fix-it` on the PR -- see deep-resolve.yml. # # To compare quality vs. the default review, look for the two distinct sticky -# comments (markers: and -# ). +# comments (markers: and ). on: pull_request_target: - types: [labeled] + types: [opened, synchronize, ready_for_review] workflow_dispatch: inputs: pr_number: @@ -25,15 +34,14 @@ on: type: string concurrency: - group: - compound-review-${{ github.event.pull_request.number || inputs.pr_number }} + group: deep-review-${{ github.event.pull_request.number || inputs.pr_number }} cancel-in-progress: true jobs: - compound-review: - if: | - github.event_name == 'workflow_dispatch' || - (github.event.action == 'labeled' && github.event.label.name == 'compound-review') + deep-review: + if: + github.event_name == 'workflow_dispatch' || github.event.action == + 'ready_for_review' || !github.event.pull_request.draft runs-on: ubuntu-latest permissions: @@ -100,17 +108,17 @@ jobs: uses: actions/checkout@v6 with: repository: EveryInc/compound-engineering-plugin - ref: v2.42.0 + ref: compound-engineering-v3.6.1 path: ce-plugin - - name: Run Compound Engineering review + - name: Run deep review id: review uses: anthropics/claude-code-action@v1 with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} github_token: ${{ secrets.GITHUB_TOKEN }} # bypasses OIDC auth (required for pull_request_target) allowed_bots: dependabot,dependabot[bot],kodiakhq,kodiakhq[bot],github-actions,github-actions[bot],cursor,cursor[bot],claude,claude[bot] - allowed_non_write_users: '*' # allow fork contributors to trigger via label + allowed_non_write_users: '*' # allow fork-PR contributors to trigger reviews plugin_marketplaces: | ./ce-plugin @@ -137,9 +145,11 @@ jobs: - `base:` short-circuits the skill's own scope detection so it does not try to `gh pr checkout` (which `report-only` would block). - The skill will fan out to ~6-12 specialist reviewer sub-agents - (correctness, security, performance, maintainability, etc.) and - return a merged, deduplicated findings report. + The skill will fan out to ~6-13 reviewer sub-agents -- 4 + always-on (correctness, testing, maintainability, project- + standards) plus cross-cutting and stack-specific reviewers + selected by the orchestrator based on the diff -- and return a + merged, deduplicated findings report. Step 2. Condense the merged findings into the JSON envelope below. Be concise -- one line per finding, grouped by severity (P0, P1, @@ -157,23 +167,23 @@ jobs: wrapping it a second time, which posts raw JSON in the comment. The `review` value must be markdown text only. 2. The review markdown MUST start with EXACTLY these two lines: - - ## Compound Engineering Review + + ## Deep Review 3. Do NOT post the review yourself with `gh` or any comment tool -- the workflow posts the structured output as a sticky comment. claude_args: | --setting-sources user --allowedTools "Bash(git:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr list:*),Bash(gh issue view:*),Bash(gh issue list:*),Bash(gh search:*),Bash(gh api:*)" - --json-schema '{"type":"object","properties":{"review":{"type":"string","description":"Complete markdown review starting with on the first line and ## Compound Engineering Review on the second line"}},"required":["review"]}' + --json-schema '{"type":"object","properties":{"review":{"type":"string","description":"Complete markdown review starting with on the first line and ## Deep Review on the second line"}},"required":["review"]}' - - name: Find existing compound review comment + - name: Find existing deep review comment uses: peter-evans/find-comment@v4 id: find-comment with: issue-number: ${{ steps.pr.outputs.number }} comment-author: github-actions[bot] - body-includes: '' + body-includes: '' direction: last # fromJSON() in `with:` has been observed to leave structured_output JSON @@ -194,13 +204,13 @@ jobs: REVIEW="$(printf '%s' "$REVIEW" | jq -r '.review')" fi { - echo 'review<> "$GITHUB_OUTPUT" - - name: Post or update compound review + - name: Post or update deep review uses: peter-evans/create-or-update-comment@v5 with: comment-id: ${{ steps.find-comment.outputs.comment-id }}