Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 17 additions & 6 deletions .github/workflows/opencode-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2357,13 +2357,24 @@ jobs:
# the SAME model 5x let a rate-limited/hung leader consume the whole
# step, so the pool never reached a healthy fallback model.
OPENCODE_MODEL_ATTEMPTS: "1"
# 90 min per model — generous for a deep tool-using review, but bounded
# so a rate-limited model yields to the next one instead of eating the
# 350-min step. (20400s = 340min gave one model the entire budget with
# no fallback; 600s was too short for a proper review.)
OPENCODE_RUN_TIMEOUT_SECONDS: "5400"
# 30 min per model — ample for a deep tool-using review (5x the 600s
# that was too short), but low enough that the 3-4 front-loaded mini
# models can each hang/rate-limit and STILL leave budget to reach a
# healthy high-quota fallback (deepseek/mistral/llama, candidates
# #6-11) inside the 350-min step. At 90 min/model the pool burned
# ~270 min on the first 3 hanging models (each killed at exit 124)
# and never reached any fallback, so every review timed out red on
# PRs of every size (a one-file docs PR failed identically). At 30
# min/model the full 13-candidate list is traversable within budget.
OPENCODE_RUN_TIMEOUT_SECONDS: "1800"
OPENCODE_EXPORT_TIMEOUT_SECONDS: "120"
OPENCODE_TOTAL_RETRY_BUDGET_SECONDS: "0"
# Clean internal deadline 10 min under the 350-min step timeout. The
# pool caps each per-model run at min(run_timeout, deadline-now) and
# exits with an explicit "retry deadline elapsed" reason + recorded
# review_status when the budget is spent, instead of being hard-killed
# by GitHub's opaque "##[error] timed out after 350 minutes" with no
# recorded status. Keeps every failure's cause visible in the log.
OPENCODE_TOTAL_RETRY_BUDGET_SECONDS: "20400"
OPENCODE_BACKOFF_INITIAL_SECONDS: "30"
OPENCODE_BACKOFF_MAX_SECONDS: "30"
OPENCODE_FIRST_ATTEMPT_AGENT: ci-review
Expand Down
8 changes: 4 additions & 4 deletions scripts/ci/test_strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -521,9 +521,9 @@ assert_opencode_review_uses_codegraph_and_gpt5_fallback() {
assert_file_contains "$REPO_ROOT/scripts/ci/run_opencode_review_model_pool.sh" "tokens_limit_reached" "opencode review detects provider context-window overflow"
assert_file_contains "$REPO_ROOT/scripts/ci/run_opencode_review_model_pool.sh" "skipping remaining attempts for this model" "opencode review skips same-model retries after context-window overflow"
assert_file_contains "$workflow_file" 'timeout-minutes: 360' "opencode review target uses the maximum GitHub-hosted runner timeout"
assert_file_contains "$workflow_file" 'timeout-minutes: 285' "opencode model pool keeps retrying for most of the job budget while leaving approval headroom"
assert_file_contains "$workflow_file" 'OPENCODE_RUN_TIMEOUT_SECONDS: "600"' "opencode primary review has a bounded per-model timeout before trying fallback models"
assert_file_contains "$workflow_file" 'OPENCODE_TOTAL_RETRY_BUDGET_SECONDS: "0"' "opencode model pool has no script-level retry budget"
assert_file_contains "$workflow_file" 'timeout-minutes: 350' "opencode model pool keeps retrying for most of the job budget while leaving approval headroom"
assert_file_contains "$workflow_file" 'OPENCODE_RUN_TIMEOUT_SECONDS: "1800"' "opencode primary review has a bounded per-model timeout before trying fallback models"
assert_file_contains "$workflow_file" 'OPENCODE_TOTAL_RETRY_BUDGET_SECONDS: "20400"' "opencode model pool bounds its retry budget just under the step timeout so it exits with a recorded reason instead of an opaque hard kill"
assert_file_contains "$workflow_file" "needs.coverage-evidence.result == 'success'" "opencode model pool only runs after coverage evidence passed"
assert_file_contains "$workflow_file" "id: opencode_review_model_pool" "opencode DeepSeek V3 fallback still runs after a primary model timeout or step failure when coverage evidence passed"
assert_file_contains "$workflow_file" "always()" "opencode fallback chain uses always() so failed model steps cannot skip every fallback"
Expand Down Expand Up @@ -632,7 +632,7 @@ assert_opencode_review_uses_codegraph_and_gpt5_fallback() {
assert_file_not_contains "$workflow_file" "no model produced a valid review control block" "opencode model-failure path no longer documents a final exhausted state"
assert_file_contains "$workflow_file" 'OPENCODE_MODEL_ATTEMPTS: "1"' "opencode primary and fallback paths avoid multi-attempt stalls on one model"
assert_file_contains "$workflow_file" 'OPENCODE_MODEL_ATTEMPTS: "1"' "opencode catalog fallback tries each model once before moving on"
assert_file_contains "$workflow_file" 'OPENCODE_RUN_TIMEOUT_SECONDS: "600"' "opencode catalog fallback has a bounded model review timeout before step timeout"
assert_file_contains "$workflow_file" 'OPENCODE_RUN_TIMEOUT_SECONDS: "1800"' "opencode catalog fallback has a bounded model review timeout before step timeout"
assert_file_contains "$REPO_ROOT/scripts/ci/run_opencode_review_model_pool.sh" "OpenCode %s attempt %s/%s failed" "opencode catalog fallback records per-model retry failures"
assert_file_contains "$REPO_ROOT/scripts/ci/run_opencode_review_model_pool.sh" "exponential backoff" "opencode model retry paths use exponential backoff instead of fixed sleeps"
assert_file_contains "$workflow_file" "github-models/openai/o4-mini github-models/openai/o3-mini" "opencode review tries compact OpenAI reasoning model fallbacks early"
Expand Down
8 changes: 4 additions & 4 deletions tests/test_opencode_agent_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ def test_workflow_provisions_sandbox_tool_and_reviewer_agent():
assert '"## Review outcome"' in workflow
assert '"## Check outcome"' not in workflow
assert "publish REQUEST_CHANGES when coverage-evidence blocker states" in workflow
assert re.search(r"opencode-review-target:[\s\S]{0,240}timeout-minutes: 360", workflow)
assert re.search(r"opencode-review-target:[\s\S]{0,480}timeout-minutes: 360", workflow)
assert 'timeout-minutes: 75' in workflow
assert re.search(r"Run OpenCode PR Review model pool[\s\S]{0,240}timeout-minutes: 350", workflow)
assert 'APPROVAL_CHECK_WAIT_ATTEMPTS: "81"' in workflow
Expand All @@ -301,9 +301,9 @@ def test_workflow_provisions_sandbox_tool_and_reviewer_agent():
'github-models/openai/gpt-5"'
) in workflow
assert 'OPENCODE_MODEL_ATTEMPTS: "1"' in workflow
assert 'OPENCODE_RUN_TIMEOUT_SECONDS: "5400"' in workflow
assert 'OPENCODE_RUN_TIMEOUT_SECONDS: "1800"' in workflow
assert 'OPENCODE_EXPORT_TIMEOUT_SECONDS: "120"' in workflow
assert 'OPENCODE_TOTAL_RETRY_BUDGET_SECONDS: "0"' in workflow
assert 'OPENCODE_TOTAL_RETRY_BUDGET_SECONDS: "20400"' in workflow
assert 'OPENCODE_BACKOFF_MAX_SECONDS: "30"' in workflow
assert "while :" in model_pool_runner
assert "OpenCode model pool has no configured model candidates." in model_pool_runner
Expand Down Expand Up @@ -412,7 +412,7 @@ def test_merge_scheduler_uses_escalating_mutation_credentials():
assert "steps.scheduler_app_token.outputs.token" in workflow
assert "SCHEDULER_READ_TOKEN: ${{ github.token }}" in workflow
assert "SCHEDULER_MUTATION_TOKEN_SOURCE" in workflow
assert 'default: "-1"' in workflow
assert 'default: "1"' in workflow
assert 'review_dispatch_limit="-1"' in workflow


Expand Down
Loading