From 516062415166871ffe47d3f6fb6f49d766b88abb Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Mon, 28 Sep 2026 18:29:42 -0400 Subject: [PATCH 1/2] fix(claude-lanes): drop the repo-wide code-review queue The code-review callers carried a job-level concurrency group keyed on the repository with `queue: max`, so every pull request's review ran one at a time across the whole repository. On claude-code-plugins 47 reviews sat pending behind a single running one. Reviews now run in parallel. The workflow-level per-PR group still cancels superseded runs. A usage limit (429) already fails fast in the reusable workflow (continue-on-error, classified as rate-limit) and the lane is advisory, so contention for the shared seat costs a red advisory check, never a blocked merge. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LnQjBqtHLbX5UWPWggk7vg --- .github/workflows/claude-review.yml | 10 ---------- components/claude-lanes-hosted/claude-review.yml | 10 ---------- .../claude-security-review.yml | 2 +- components/claude-lanes/claude-lanes.test.sh | 15 --------------- components/claude-lanes/claude-review.yml | 10 ---------- .../claude-lanes/claude-security-review.yml | 2 +- distribution/README.md | 2 +- 7 files changed, 3 insertions(+), 48 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 0ae0986..0de5c9b 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -46,16 +46,6 @@ jobs: pull-requests: write # post review + track_progress tracking comment id-token: write # OIDC — mints the Claude GitHub App token (required # even with an OAuth/API-key credential) - # Repo-wide review queue — a SEPARATE block from the workflow-level cancel - # group above, because `queue: max` cannot be combined with - # `cancel-in-progress: true`, the value that block sets - # (https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idconcurrency) - # — and because this group is job-scoped and repo-wide, not per-PR. - # Serializes reviews repo-wide so parallel PRs queue for the shared Claude - # seat instead of contending for it. - concurrency: - group: claude-review-${{ github.repository }} - queue: max uses: melodic-software/ci-workflows/.github/workflows/claude-review.yml@35880dcbb2f174aac90159e276dc7eddf1bc20b9 # v0.30.1 with: # DEVIATION from the component, which names the managed fleet label: diff --git a/components/claude-lanes-hosted/claude-review.yml b/components/claude-lanes-hosted/claude-review.yml index 8418c6e..a813e1d 100644 --- a/components/claude-lanes-hosted/claude-review.yml +++ b/components/claude-lanes-hosted/claude-review.yml @@ -75,16 +75,6 @@ jobs: pull-requests: write # post review + tracking comment id-token: write # OIDC, mints the Claude GitHub App token (required # even with an OAuth/API-key credential) - # Repo-wide review queue: a SEPARATE block from the workflow-level - # cancel group above, because `queue: max` cannot be combined with - # `cancel-in-progress: true`, the value that block sets - # (https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idconcurrency), - # and because this group is job-scoped and repo-wide, not per-PR. - # Serializes reviews repo-wide so parallel PRs queue for the shared - # Claude seat instead of contending for it. - concurrency: - group: claude-review-${{ github.repository }} - queue: max uses: melodic-software/ci-workflows/.github/workflows/claude-review.yml@35880dcbb2f174aac90159e276dc7eddf1bc20b9 # v0.30.1 with: runner: ubuntu-24.04 diff --git a/components/claude-lanes-hosted/claude-security-review.yml b/components/claude-lanes-hosted/claude-security-review.yml index 6e7bed6..682398f 100644 --- a/components/claude-lanes-hosted/claude-security-review.yml +++ b/components/claude-lanes-hosted/claude-security-review.yml @@ -60,7 +60,7 @@ permissions: # queue group: a full queue CANCELS new arrivals, which is the same wedge; a # queue is added only if overflow smoke-testing proves otherwise. These are # per-LANE values, deliberately different from the code-review caller's (which -# cancels superseded runs and queues repo-wide). Do not normalize the two. +# cancels superseded runs). Do not normalize the two. jobs: security-review: diff --git a/components/claude-lanes/claude-lanes.test.sh b/components/claude-lanes/claude-lanes.test.sh index 6e64569..92aa03a 100755 --- a/components/claude-lanes/claude-lanes.test.sh +++ b/components/claude-lanes/claude-lanes.test.sh @@ -16,7 +16,6 @@ manifest='distribution/sync-manifest.yml' config='.github/actionlint.yaml' # The fleet callers and their hosted siblings (components/claude-lanes-hosted/). source_prefix_re='components/claude-lanes(-hosted)?/' -queue_message='unexpected key "queue" for "concurrency" section' if ! command -v actionlint >/dev/null 2>&1; then skip_suite 'actionlint not installed' @@ -126,18 +125,4 @@ for target in "${lane_targets[@]}"; do assert_silent "$target sync emits no findings" "$out" done -# Control: the suppression is load-bearing for every one of those targets, not -# a nicety. A target that owns actionlint locally must carry its own -# equivalent or its first sync PR fails its own lane. When this case stops -# failing, the upstream fix shipped — fire the removal trigger recorded in the -# canonical config instead of patching this test. -control="$scratch/no-config" -consumer_checkout "${lane_targets[0]}" "$control" -bash distribution/sync-manifest.sh apply --target "${lane_targets[0]}" --target-root "$control" >/dev/null -rm -f "$control/$config" -out="$(cd "$control" && actionlint -no-color 2>&1)" -rc=$? -assert_nonzero 'a synced lane caller fails actionlint without the suppression' "$rc" -assert_contains 'control run reports the suppressed message' "$out" "$queue_message" - [[ $FAILED -eq 0 ]] || exit 1 diff --git a/components/claude-lanes/claude-review.yml b/components/claude-lanes/claude-review.yml index c76832d..aa26f6d 100644 --- a/components/claude-lanes/claude-review.yml +++ b/components/claude-lanes/claude-review.yml @@ -71,16 +71,6 @@ jobs: pull-requests: write # post review + tracking comment id-token: write # OIDC, mints the Claude GitHub App token (required # even with an OAuth/API-key credential) - # Repo-wide review queue: a SEPARATE block from the workflow-level - # cancel group above, because `queue: max` cannot be combined with - # `cancel-in-progress: true`, the value that block sets - # (https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idconcurrency), - # and because this group is job-scoped and repo-wide, not per-PR. - # Serializes reviews repo-wide so parallel PRs queue for the shared - # Claude seat instead of contending for it. - concurrency: - group: claude-review-${{ github.repository }} - queue: max uses: melodic-software/ci-workflows/.github/workflows/claude-review.yml@35880dcbb2f174aac90159e276dc7eddf1bc20b9 # v0.30.1 with: runner: melodic-review-ubuntu-24.04-x64 diff --git a/components/claude-lanes/claude-security-review.yml b/components/claude-lanes/claude-security-review.yml index 736984a..4d8ffac 100644 --- a/components/claude-lanes/claude-security-review.yml +++ b/components/claude-lanes/claude-security-review.yml @@ -56,7 +56,7 @@ permissions: # queue group: a full queue CANCELS new arrivals, which is the same wedge; a # queue is added only if overflow smoke-testing proves otherwise. These are # per-LANE values, deliberately different from the code-review caller's (which -# cancels superseded runs and queues repo-wide). Do not normalize the two. +# cancels superseded runs). Do not normalize the two. jobs: security-review: diff --git a/distribution/README.md b/distribution/README.md index 76c11a0..1f30be4 100644 --- a/distribution/README.md +++ b/distribution/README.md @@ -368,7 +368,7 @@ non-draft same-repository PR whose actor is not a bot, and a target's `.github/c no longer read. The manifest never managed that file. The two callers deliberately carry different concurrency values (per-PR -cancel plus a repo-wide queue on the code-review caller; cancel disabled and +cancel on the code-review caller; cancel disabled and no queue on the security caller, whose check may be a required execution-evidence context). The component sources record the rationale inline. Do not normalize the two. From 6f498274d28f0138c11cf3248ea08ad3cf40b040 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Mon, 28 Sep 2026 19:09:39 -0400 Subject: [PATCH 2/2] docs(distribution): drop the obsolete ci-runner queue-ignore prerequisite No lane caller carries `concurrency.queue` now, so ci-runner's actionlint config no longer needs the `queue` ignore for the hosted review caller. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LnQjBqtHLbX5UWPWggk7vg --- distribution/README.md | 3 --- distribution/sync-manifest.yml | 5 ----- 2 files changed, 8 deletions(-) diff --git a/distribution/README.md b/distribution/README.md index 1f30be4..3e01d4a 100644 --- a/distribution/README.md +++ b/distribution/README.md @@ -406,9 +406,6 @@ and cursor-plugins. - The sync never deletes a file. A target that moves between the hosted and fleet variants must delete the old caller in a repo-local pull request, or both run. -- ci-runner owns its actionlint config, which must extend its `queue` ignore to - `.github/workflows/claude-review-hosted.yml` before its sync pull request can - pass. - Removal trigger: the one-shape work below landing, after which the hosted pair retires. diff --git a/distribution/sync-manifest.yml b/distribution/sync-manifest.yml index 9074dc8..6d0265e 100644 --- a/distribution/sync-manifest.yml +++ b/distribution/sync-manifest.yml @@ -385,11 +385,6 @@ targets: - repository-text - shellcheck - typos - # The hosted review caller carries a job-level `concurrency.queue`, which - # the pinned actionlint rejects. ci-runner owns its actionlint config, so - # its `.github/actionlint.yaml` must extend the `queue` ignore to - # `.github/workflows/claude-review-hosted.yml` before the sync pull - # request that adds the caller can pass its own actionlint lane. locally-owned: - actionlint melodic-software/ci-workflows: