From aac82dd112ba894490b57e05a57e2321aa749d94 Mon Sep 17 00:00:00 2001 From: Agnieszka Besz Date: Wed, 20 May 2026 12:33:31 +0100 Subject: [PATCH 1/5] chore: hide stale Claude review comments instead of deleting --- .github/workflows/claude-pr-review.yml | 32 +++++++++++++------ .../workflows/dependency-security-review.yml | 22 +++++++++++-- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/.github/workflows/claude-pr-review.yml b/.github/workflows/claude-pr-review.yml index 8bcd57f63f..e1c876f3b0 100644 --- a/.github/workflows/claude-pr-review.yml +++ b/.github/workflows/claude-pr-review.yml @@ -134,7 +134,9 @@ jobs: owner, repo, issue_number: prNumber, per_page: 100 }); - const claudeComments = comments.data.filter(c => c.user?.login === 'claude[bot]'); + const claudeComments = comments.data.filter(c => + c.user?.login === 'claude[bot]' && c.body?.includes('REVIEW_RESULT:') + ); const claudeComment = claudeComments[claudeComments.length - 1]; const output = claudeComment?.body ?? ''; @@ -215,9 +217,14 @@ jobs: } for (const c of claudeComments.slice(0, -1)) { - await github.rest.issues.deleteComment({ - owner, repo, comment_id: c.id - }).catch(e => console.log(`deleteComment ${c.id}: ${e.message}`)); + await github.graphql( + `mutation($id: ID!) { + minimizeComment(input: { subjectId: $id, classifier: OUTDATED }) { + minimizedComment { isMinimized } + } + }`, + { id: c.node_id } + ).catch(e => console.log(`minimizeComment ${c.id}: ${e.message}`)); } let description; @@ -422,7 +429,9 @@ jobs: per_page: 100 }); - const claudeComments = comments.data.filter(c => c.user?.login === 'claude[bot]'); + const claudeComments = comments.data.filter(c => + c.user?.login === 'claude[bot]' && c.body?.includes('REVIEW_RESULT:') + ); const claudeComment = claudeComments[claudeComments.length - 1]; const output = claudeComment?.body ?? ''; @@ -433,11 +442,14 @@ jobs: const hasReviewResult = output.includes('REVIEW_RESULT:'); for (const c of claudeComments.slice(0, -1)) { - await github.rest.issues.deleteComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: c.id - }).catch(e => console.log(`deleteComment ${c.id}: ${e.message}`)); + await github.graphql( + `mutation($id: ID!) { + minimizeComment(input: { subjectId: $id, classifier: OUTDATED }) { + minimizedComment { isMinimized } + } + }`, + { id: c.node_id } + ).catch(e => console.log(`minimizeComment ${c.id}: ${e.message}`)); } let description; diff --git a/.github/workflows/dependency-security-review.yml b/.github/workflows/dependency-security-review.yml index 008829ea26..80ee8ad779 100644 --- a/.github/workflows/dependency-security-review.yml +++ b/.github/workflows/dependency-security-review.yml @@ -16,6 +16,10 @@ on: - '.github/workflows/**' - '.github/prompts/**' +concurrency: + group: dependency-security-review-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + jobs: detect-and-review: if: github.event.pull_request.draft == false @@ -182,9 +186,21 @@ jobs: issue_number: ${{ github.event.pull_request.number }}, }); - const claudeComment = comments - .reverse() - .find(c => c.user?.login === 'claude[bot]'); + const claudeComments = comments.filter(c => + c.user?.login === 'claude[bot]' && c.body?.includes('DEPENDENCY_REVIEW:') + ); + const claudeComment = claudeComments[claudeComments.length - 1]; + + for (const c of claudeComments.slice(0, -1)) { + await github.graphql( + `mutation($id: ID!) { + minimizeComment(input: { subjectId: $id, classifier: OUTDATED }) { + minimizedComment { isMinimized } + } + }`, + { id: c.node_id } + ).catch(e => console.log(`minimizeComment ${c.id}: ${e.message}`)); + } const output = claudeComment?.body ?? ''; const errored = '${{ steps.claude.outcome }}' === 'failure'; From e19554f56d6f889f6da5759dcf85b0469aadcdfc Mon Sep 17 00:00:00 2001 From: Agnieszka Besz Date: Wed, 20 May 2026 15:13:14 +0100 Subject: [PATCH 2/5] chore: scope claude-review concurrency per event type --- .github/workflows/claude-pr-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/claude-pr-review.yml b/.github/workflows/claude-pr-review.yml index e1c876f3b0..af485f8b4a 100644 --- a/.github/workflows/claude-pr-review.yml +++ b/.github/workflows/claude-pr-review.yml @@ -9,7 +9,7 @@ on: types: [opened, synchronize, ready_for_review] concurrency: - group: claude-review-${{ github.event.pull_request.number || github.event.issue.number || github.run_id }} + group: claude-review-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number || github.run_id }} cancel-in-progress: true jobs: From 68e72d327a9de5a1c6605a87f8d84bc23b919fe2 Mon Sep 17 00:00:00 2001 From: Agnieszka Besz Date: Wed, 20 May 2026 15:42:47 +0100 Subject: [PATCH 3/5] chore: move claude-review concurrency to job level Workflow-level concurrency joins the group before job if: filters run, so claude[bot]'s own progress comments triggered new issue_comment runs that cancelled in-flight reviews. Move concurrency to the auto-review and review jobs so skipped jobs never enter the group. --- .github/workflows/claude-pr-review.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/claude-pr-review.yml b/.github/workflows/claude-pr-review.yml index af485f8b4a..b1ffcb4875 100644 --- a/.github/workflows/claude-pr-review.yml +++ b/.github/workflows/claude-pr-review.yml @@ -8,10 +8,6 @@ on: pull_request: types: [opened, synchronize, ready_for_review] -concurrency: - group: claude-review-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number || github.run_id }} - cancel-in-progress: true - jobs: auto-review: if: | @@ -20,6 +16,9 @@ jobs: !contains(github.event.pull_request.labels.*.name, 'no review') && !contains(github.event.pull_request.labels.*.name, 'auto-pr') runs-on: ubuntu-latest + concurrency: + group: claude-auto-review-${{ github.event.pull_request.number }} + cancel-in-progress: true permissions: id-token: write contents: read @@ -317,6 +316,9 @@ jobs: needs: check-member if: needs.check-member.outputs.is-member == 'true' runs-on: ubuntu-latest + concurrency: + group: claude-on-demand-review-${{ github.event.issue.number }} + cancel-in-progress: true permissions: id-token: write contents: read From 958051115b50a0637734daec9c2dc5f29b787c81 Mon Sep 17 00:00:00 2001 From: Agnieszka Besz Date: Wed, 20 May 2026 16:43:15 +0100 Subject: [PATCH 4/5] chore: polish master-of-bots docs wording --- docs/master-of-bots.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/master-of-bots.md b/docs/master-of-bots.md index f641c17a23..c0be0dea33 100644 --- a/docs/master-of-bots.md +++ b/docs/master-of-bots.md @@ -1,5 +1,5 @@ # Master of Bots -Master Of Bots allows you to simulate big amounts (tested with up to 100 bots from a single machine) of users with real wallets for debug purposes. +Master Of Bots allows you to simulate large numbers (tested with up to 100 bots from a single machine) of users with real wallets for debug purposes. Proceed to https://github.com/decentraland/livekit-bots/tree/explorer-alpha and follow the instructions. From 7bab08cae2d8213e86a7784ed3c0459988f6132b Mon Sep 17 00:00:00 2001 From: Agnieszka Besz Date: Wed, 20 May 2026 17:32:51 +0100 Subject: [PATCH 5/5] chore: anchor verdict marker filter to line-start Substring match on REVIEW_RESULT: / DEPENDENCY_REVIEW: also catches review bodies that merely discuss the marker text, so cross-workflow verdicts were getting minimized as collateral. Require a real verdict value (PASS/FAIL/BLOCK/NEEDS_ATTENTION) on its own line. --- .github/workflows/claude-pr-review.yml | 6 ++++-- .github/workflows/dependency-security-review.yml | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/claude-pr-review.yml b/.github/workflows/claude-pr-review.yml index b1ffcb4875..c92957bb4f 100644 --- a/.github/workflows/claude-pr-review.yml +++ b/.github/workflows/claude-pr-review.yml @@ -133,8 +133,9 @@ jobs: owner, repo, issue_number: prNumber, per_page: 100 }); + const VERDICT_RE = /(?:^|\n)REVIEW_RESULT: (PASS|FAIL)\b/; const claudeComments = comments.data.filter(c => - c.user?.login === 'claude[bot]' && c.body?.includes('REVIEW_RESULT:') + c.user?.login === 'claude[bot]' && VERDICT_RE.test(c.body || '') ); const claudeComment = claudeComments[claudeComments.length - 1]; @@ -431,8 +432,9 @@ jobs: per_page: 100 }); + const VERDICT_RE = /(?:^|\n)REVIEW_RESULT: (PASS|FAIL)\b/; const claudeComments = comments.data.filter(c => - c.user?.login === 'claude[bot]' && c.body?.includes('REVIEW_RESULT:') + c.user?.login === 'claude[bot]' && VERDICT_RE.test(c.body || '') ); const claudeComment = claudeComments[claudeComments.length - 1]; diff --git a/.github/workflows/dependency-security-review.yml b/.github/workflows/dependency-security-review.yml index 80ee8ad779..6b04220e3c 100644 --- a/.github/workflows/dependency-security-review.yml +++ b/.github/workflows/dependency-security-review.yml @@ -186,8 +186,9 @@ jobs: issue_number: ${{ github.event.pull_request.number }}, }); + const VERDICT_RE = /(?:^|\n)DEPENDENCY_REVIEW: (PASS|BLOCK|NEEDS_ATTENTION)\b/; const claudeComments = comments.filter(c => - c.user?.login === 'claude[bot]' && c.body?.includes('DEPENDENCY_REVIEW:') + c.user?.login === 'claude[bot]' && VERDICT_RE.test(c.body || '') ); const claudeComment = claudeComments[claudeComments.length - 1];