From 6b373b9294c56da1ca8e6961c37a45b412c80021 Mon Sep 17 00:00:00 2001 From: William Aaron Cheung Date: Wed, 19 Aug 2026 15:51:37 +0800 Subject: [PATCH] feat(pr-review): add optional max_turns input to override turn budget The claude-pr-review composite action derived its per-invocation turn budget (12 fast / 44 standard / 56 deep) entirely internally, so a consumer repo could not tune the analysis ceiling without editing the centralized action. Add an optional `max_turns` input: empty (default) preserves the existing tier/depth-derived budget exactly, and a positive integer overrides it for the main analysis pass while the retry keeps its 1.5x headroom relative to the chosen value. A non-integer or non-positive value fails the compose step loudly rather than silently disabling the cap. Also correct the README's turn-budget numbers, which had drifted from the action (it stated 36 for strong and, separately, 24/40 for standard/deep, while the action uses 44 and 56). Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01GCc8MLBBAp5jAxc2x19swa --- .github/actions/README.md | 10 +++++++--- .github/actions/claude-pr-review/action.yml | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.github/actions/README.md b/.github/actions/README.md index e587579..521c1c3 100644 --- a/.github/actions/README.md +++ b/.github/actions/README.md @@ -71,13 +71,17 @@ The `pr-review` action additionally accepts: - `review_depth` - optional, defaults to `standard`. Set it to `deep` to make the semantic-analysis stage fan out relevant review dimensions and adversarially verify the candidates before returning one structured result. +- `max_turns` - optional, defaults to empty. + Overrides the per-invocation turn budget (`--max-turns`) that is otherwise derived from the + model tier and review depth. Set a positive integer to pin the main analysis ceiling; the + retry keeps its 1.5x headroom relative to it. A non-integer or non-positive value fails the run. - `premortem` - optional, defaults to `auto`. Automatic mode runs the independent production-failure analysis for initial and high-risk reviews, but skips it for ordinary incremental updates. `on` always enables it and `off` disables it. The semantic-analysis stage runs under a turn budget: 12 for a low-risk incremental review, -36 for a strong-tier one, and 56 for `deep`. +44 for a strong-tier one, and 56 for `deep`. Set `max_turns` to override any of these. Roughly ten turns go on mandated context — six pipeline files plus repo guidance — before the diff is read, and a small diff inside a large file spends many more paging through it, so the budget tracks files to understand rather than lines changed. @@ -91,8 +95,8 @@ with: github_identity_token: ${{ steps.app-token.outputs.token }} ``` -The semantic stage is bounded to 12 turns for fast incremental reviews, 24 for standard -full or high-risk reviews, and 40 for explicit deep reviews. +The semantic stage is bounded to 12 turns for fast incremental reviews, 44 for standard +full or high-risk reviews, and 56 for explicit deep reviews, unless `max_turns` overrides it. ### PR review pipeline diff --git a/.github/actions/claude-pr-review/action.yml b/.github/actions/claude-pr-review/action.yml index 65c4727..6cb89af 100644 --- a/.github/actions/claude-pr-review/action.yml +++ b/.github/actions/claude-pr-review/action.yml @@ -40,6 +40,15 @@ inputs: description: > `standard` runs one lead review. `deep` asks the lead to fan out review dimensions and adversarially verify them before returning structured data. + max_turns: + required: false + default: "" + description: > + Optional override for the per-invocation turn budget (`--max-turns`). + Empty (default) uses the built-in budget derived from model tier and + review depth (fast 12, standard 44, deep 56). Set a positive integer to + pin the ceiling for the main analysis pass; the retry pass keeps its 1.5x + headroom relative to this value. debug_logs: required: false default: "false" @@ -103,6 +112,7 @@ runs: INCREMENTAL_MODEL: ${{ inputs.incremental_model }} MODEL_TIER: ${{ steps.prepare.outputs.model_tier }} REVIEW_DEPTH: ${{ inputs.review_depth }} + MAX_TURNS_OVERRIDE: ${{ inputs.max_turns }} RUN_PREMORTEM: ${{ steps.prepare.outputs.run_premortem }} run: | set -euo pipefail @@ -133,6 +143,17 @@ runs: if [[ "$REVIEW_DEPTH" == "deep" ]]; then max_turns=56 fi + # An explicit max_turns input overrides the tier/depth-derived budget, + # letting a consumer repo tune the analysis ceiling without editing this + # action. Validate up front so a typo fails the step loudly instead of + # silently disabling the turn cap. + if [[ -n "$MAX_TURNS_OVERRIDE" ]]; then + if [[ ! "$MAX_TURNS_OVERRIDE" =~ ^[1-9][0-9]*$ ]]; then + echo "::error::max_turns must be a positive integer, got '$MAX_TURNS_OVERRIDE'" >&2 + exit 1 + fi + max_turns="$MAX_TURNS_OVERRIDE" + fi # Exhausting the budget is deterministic: retrying with the same one # burns a second full model run that cannot succeed. Give the retry # half again as many turns so it can actually finish.