feat(code-review): parallelize GitHub-mode reviewer/verifier fleets - #178
Merged
Conversation
GitHub/headless reviews dispatched the reviewer fleet (stage_20) and verifier fleet (stage_23) synchronously one agent at a time, so CI wall-clock was the SUM of every agent — a shallow review with 3 serial reviewers + 2 serial verifiers took ~30 min. The synchronous rule existed because headless `claude -p` used to terminate before background subagents finished. As of Claude Code v2.1.182+ (shipped by claude-code-action@v1), `claude -p` waits for background subagents to complete because their output is part of the final result, so a blocking TaskOutput keeps the turn alive until reviewers finish. Unify both modes on the local parallel pattern: spawn every standard-flow reviewer/verifier with run_in_background: true and collect all with blocking TaskOutput before advancing. Fleet stages now take the SLOWEST agent, not the sum — roughly halving shallow-tier CI review time. A synchronous one-at-a-time fallback stays documented for Claude Code < v2.1.182, and CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS can raise the 10-min per-agent wait cap for long reviewers. Updates spawn-reviewers + verify-findings skills and start.md; replaces the FEA-2162 synchronous-GitHub test class with the parallel-dispatch contract. Full code-review suite green (1308 passed), ruff + pyright clean. Bump 3.4.1 -> 3.5.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ncern Address deep-review findings on the parallel-fleet contract: - The "Legacy fallback (Claude Code < v2.1.182)" branch was written as if the orchestrating agent picks between parallel and synchronous dispatch at runtime, but the agent cannot introspect its own CLI version from inside the prompt, so the fallback was an unreachable branch. Reframe it in spawn-reviewers/SKILL.md and start.md as an operator/environment concern (claude-code-action@v1 ships >= v2.1.182, so CI is always parallel; an operator on an older CLI must edit the skill), not a path the live agent resolves. - Add the matching legacy-fallback note to verify-findings/SKILL.md so the reviewer and verifier fleets document the same degradation on older CLIs. - Scope the CHANGELOG entry: only stage_20 removed a synchronous-GitHub branch; stage_23 was already background-dispatched in both modes and is now only documented explicitly. Drop the inflated "halving" estimate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
peterulsteen
added a commit
that referenced
this pull request
Jul 14, 2026
…nous headless dispatch (FEA-3085) (#179) * fix(code-review): revert #178 parallel GitHub fleet; restore synchronous headless dispatch (FEA-3085) Reverts d7362f0 (v3.5.0, #178) and bumps 3.4.1 -> 3.6.0. #178 unified GitHub and local reviewer-fleet dispatch (stage_20) on run_in_background: true + blocking TaskOutput, on the premise that headless `claude -p` (Claude Code >= v2.1.182) reliably awaits background subagents as long as the orchestrator issues the blocking collection. Empirically the orchestrator does NOT reliably issue it. In ~18% of symphony-alpha claude-code-review.yml pull_request runs on 2026-07-13 (9/50, up from 1/10 the day #178 went live) it launched the fleet (Bug Hunter A/B, Unified Auditor) as background agents and then ended its turn ('I'll wait for the harness to notify me') with no pending synchronous tool call, so claude -p exited (terminal_reason: completed) before stage_21_collect_findings..stage_30_footer ran. No findings were collected, no .closedloop-ai/code-review-* artifacts were written, and the workflow's 'Validate migrated review artifacts' guard failed the job. Runs that took the synchronous fast-path branch were unaffected, which is why the failure was intermittent. Restore the known-good split: GitHub/headless standard flow dispatches reviewers synchronously one-at-a-time (run_in_background: false, wait for each 'DONE findings=N file=...' before the next), which keeps the turn alive by construction rather than depending on the model choosing to issue a blocking TaskOutput; local mode keeps parallel background dispatch + blocking TaskOutput. Restores the FEA-2162 synchronous-GitHub reviewer contract and its test class. Trade-off: GitHub review wall-clock returns to sum-of-reviewers -- correctness over speed for a merge-adjacent gate. Full code-review suite green (2079 passed, 3 skipped), ruff + pyright clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(code-review): restore v3.5.0 changelog entry; add v3.6.0 above it (not replace) Address review: v3.5.0 shipped to main, so its changelog block must stay (entries are newest-first + treated as released on merge). Put v3.6.0 on top of the retained v3.5.0 Changed block instead of deleting it. Also note in v3.6.0 that stage_23 verifiers are unchanged and their headless exposure is tracked in FEA-3154. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Shallow code reviews take ~30 minutes in GitHub CI. Root cause (traced from a real CI log): GitHub/headless mode dispatched the reviewer fleet (
stage_20) and verifier fleet (stage_23) synchronously, one agent at a time, so wall-clock = SUM of every agent instead of MAX. A shallow run's 3 reviewers ran serially (~6m + ~10.5m + ~6m ≈ 22.5m) plus 2 serial verifiers (~5m) ≈ 30m. Local reviews don't have this because they spawn the fleet as parallel background tasks.The synchronous rule was correct once: headless
claude -pused to terminate before outstanding background subagents finished. That constraint is stale.Why it's safe now (verified)
Per the Claude Code headless docs: since v2.1.182,
claude -p"waits for [background subagents] to complete" because their output is part of the final result (10-min-per-agent cap, tunable viaCLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS). A blockingTaskOutputis a pending synchronous call, so the turn never ends with a reviewer outstanding.claude-code-action@v1already ships v2.1.206.Change
Unify both modes on the local parallel pattern — spawn every standard-flow reviewer/verifier with
run_in_background: true, collect all with blockingTaskOutputbefore advancing. Fleet stages now take the slowest agent, not the sum → roughly halves shallow-tier CI review time (deep tier gains more).skills/spawn-reviewers/SKILL.md— unified Spawn + Collection Contract; headless note rewritten for v2.1.182+ await; legacy synchronous fallback documented for CLI < v2.1.182; wait-loop substitutes (watcher files / sleep / polling) still banned.skills/verify-findings/SKILL.md— explicit parallel-in-both-modes dispatch (stops the orchestrator serializing verifiers).commands/start.md— stage-20 walker guard reframed around blockingTaskOutputcollection.test_code_review_helpers.py— replaced the FEA-2162 synchronous-GitHub test class with the parallel-dispatch contract (11 tests).Validation
The plugin change alone isn't enough — the GitHub Actions workflow that runs
/code-reviewmust also:TaskOutputtoclaude_args'--allowedTools(currently onlyTaskis allowed → the collection call would be denied).CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MSabove 10 min (e.g.1500000, or0) — a single reviewer already ran 10.5m serially, so a slow parallel reviewer could otherwise be orphaned at the 10-min default.Recommend validating on one real CI review before relying on the speedup.
🤖 Generated with Claude Code