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
37 changes: 21 additions & 16 deletions .github/workflows/opencode-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1529,10 +1529,10 @@ jobs:
)
runs-on: ubuntu-latest
# Coverage and current-head evidence are prepared before the model pool.
# The model pool has a 25-minute retry budget and its publish gate has an
# 8-minute cap, so 45 minutes releases genuinely hung runners without
# truncating the bounded multi-provider review path.
timeout-minutes: 45
# The model pool step is capped at 50 minutes (2880s shell watchdog) and
# its publish gate has an 8-minute cap, so 75 minutes releases genuinely
# hung runners without truncating the bounded multi-provider review path.
timeout-minutes: 75
permissions:
actions: read
checks: read
Expand Down Expand Up @@ -3251,7 +3251,7 @@ jobs:
- name: Run OpenCode PR Review model pool
id: opencode_review_model_pool
if: needs.coverage-evidence.result == 'success'
timeout-minutes: 20
timeout-minutes: 50
continue-on-error: true
env:
STRIX_GITHUB_MODELS_TOKEN: ${{ secrets.STRIX_GITHUB_MODELS_TOKEN || github.token }}
Expand Down Expand Up @@ -3285,22 +3285,27 @@ jobs:
OPENCODE_RUN_TIMEOUT_SECONDS: "300"
OPENCODE_EXPORT_TIMEOUT_SECONDS: "120"
OPENCODE_TOTAL_RETRY_BUDGET_SECONDS: "600"
OPENCODE_POOL_STEP_TIMEOUT_SECONDS: "1080"
OPENCODE_POOL_STEP_TIMEOUT_SECONDS: "2880"
# Visit the high-sensitivity candidate catalog once. Per-provider
# failures and timeouts are logged before the publish gate evaluates
# the current-head result and fails closed when no verdict exists.
OPENCODE_POOL_MAX_CYCLES: "1"
OPENCODE_DYNAMIC_REVIEW_CADENCE: "true"
OPENCODE_SMALL_CHANGE_FILE_THRESHOLD: "3"
OPENCODE_MEDIUM_CHANGE_FILE_THRESHOLD: "20"
OPENCODE_SMALL_CHANGE_RUN_TIMEOUT_SECONDS: "300"
OPENCODE_SMALL_CHANGE_TOTAL_BUDGET_SECONDS: "600"
OPENCODE_MEDIUM_CHANGE_RUN_TIMEOUT_SECONDS: "420"
OPENCODE_MEDIUM_CHANGE_TOTAL_BUDGET_SECONDS: "900"
OPENCODE_LARGE_CHANGE_RUN_TIMEOUT_SECONDS: "420"
OPENCODE_LARGE_CHANGE_TOTAL_BUDGET_SECONDS: "1080"
OPENCODE_UNKNOWN_CHANGE_RUN_TIMEOUT_SECONDS: "420"
OPENCODE_UNKNOWN_CHANGE_TOTAL_BUDGET_SECONDS: "900"
# Cadence sized for the direct-OpenAI slot (gpt-5.6-luna), the only
# candidate producing verdicts while the GitHub Models org budget is
# capped: at the previous 420s/900s a substantive multi-file review
# timed out mid-run and the exhausted pool stalled the org merge
# queue (2026-07-13). The outer watchdog still bounds the step.
OPENCODE_SMALL_CHANGE_RUN_TIMEOUT_SECONDS: "900"
OPENCODE_SMALL_CHANGE_TOTAL_BUDGET_SECONDS: "1500"
OPENCODE_MEDIUM_CHANGE_RUN_TIMEOUT_SECONDS: "1500"
OPENCODE_MEDIUM_CHANGE_TOTAL_BUDGET_SECONDS: "2400"
OPENCODE_LARGE_CHANGE_RUN_TIMEOUT_SECONDS: "1800"
OPENCODE_LARGE_CHANGE_TOTAL_BUDGET_SECONDS: "2700"
OPENCODE_UNKNOWN_CHANGE_RUN_TIMEOUT_SECONDS: "1500"
OPENCODE_UNKNOWN_CHANGE_TOTAL_BUDGET_SECONDS: "2400"
OPENCODE_DYNAMIC_MAX_CYCLES: "1"
CENTRAL_REVIEW_PROCESS_FALLBACK_ELIGIBLE: ${{ steps.central_review_process_fallback_scope.outputs.eligible || 'false' }}
CENTRAL_REVIEW_PROCESS_FALLBACK_SCOPE_LABEL: ${{ steps.central_review_process_fallback_scope.outputs.scope_label || 'unsupported' }}
Expand All @@ -3326,13 +3331,13 @@ jobs:
run: |
set -euo pipefail
set +e
timeout --kill-after=30s "${OPENCODE_POOL_STEP_TIMEOUT_SECONDS:-1080}s" \
timeout --kill-after=30s "${OPENCODE_POOL_STEP_TIMEOUT_SECONDS:-2880}s" \
bash "$GITHUB_WORKSPACE/scripts/ci/run_opencode_review_model_pool.sh"
pool_status=$?
set -e
if [ "$pool_status" -eq 124 ] || [ "$pool_status" -eq 137 ] || [ "$pool_status" -eq 143 ]; then
printf 'OpenCode model pool exceeded the outer %ss step budget; marking the pool exhausted so current-head evidence fallback can publish a bounded reason instead of blocking the org queue.\n' \
"${OPENCODE_POOL_STEP_TIMEOUT_SECONDS:-1080}"
"${OPENCODE_POOL_STEP_TIMEOUT_SECONDS:-2880}"
{
printf 'review_model=\n'
printf 'review_status=exhausted\n'
Expand Down
2 changes: 1 addition & 1 deletion scripts/ci/test_strix_quick_gate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ assert_opencode_review_uses_codegraph_and_gpt5_fallback() {
assert_file_contains "$REPO_ROOT/scripts/ci/run_opencode_review_model_pool.sh" "not a generic model-exhaustion message" "opencode review tells models to return concrete missing-evidence findings instead of progress-only output"
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: 45' "opencode review target releases stalled review runners within the bounded queue budget"
assert_file_contains "$workflow_file" 'timeout-minutes: 75' "opencode review target releases stalled review runners within the bounded queue budget"
assert_file_contains "$workflow_file" 'timeout-minutes: 12' "opencode evidence preparation fails closed before it ties up the review queue"
assert_file_contains "$workflow_file" 'timeout-minutes: 12' "opencode model pool gives multiple candidates a bounded review window while capping stalled model attempts"
assert_file_contains "$workflow_file" 'timeout-minutes: 8' "opencode approval publication is bounded so a stalled review releases queue capacity promptly"
Expand Down
34 changes: 17 additions & 17 deletions tests/test_opencode_agent_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -670,17 +670,17 @@ def test_workflow_provisions_sandbox_tool_and_reviewer_agent():
assert '"## Check outcome"' not in workflow
assert "publish REQUEST_CHANGES when coverage-evidence blocker states" in workflow
assert re.search(r"Prepare bounded OpenCode review evidence[\s\S]{0,120}timeout-minutes: 12", workflow)
assert re.search(r"opencode-review-target:[\s\S]*?timeout-minutes: 45", workflow)
assert re.search(r"opencode-review-target:[\s\S]*?timeout-minutes: 75", workflow)
assert 'timeout-minutes: 12' in workflow
assert re.search(r"Run OpenCode PR Review model pool[\s\S]{0,240}timeout-minutes: 20", workflow)
assert 'OPENCODE_SMALL_CHANGE_TOTAL_BUDGET_SECONDS: "600"' in workflow
assert 'OPENCODE_MEDIUM_CHANGE_TOTAL_BUDGET_SECONDS: "900"' in workflow
assert 'OPENCODE_LARGE_CHANGE_TOTAL_BUDGET_SECONDS: "1080"' in workflow
assert 'OPENCODE_UNKNOWN_CHANGE_TOTAL_BUDGET_SECONDS: "900"' in workflow
assert re.search(r"Run OpenCode PR Review model pool[\s\S]{0,240}timeout-minutes: 50", workflow)
assert 'OPENCODE_SMALL_CHANGE_TOTAL_BUDGET_SECONDS: "1500"' in workflow
assert 'OPENCODE_MEDIUM_CHANGE_TOTAL_BUDGET_SECONDS: "2400"' in workflow
assert 'OPENCODE_LARGE_CHANGE_TOTAL_BUDGET_SECONDS: "2700"' in workflow
assert 'OPENCODE_UNKNOWN_CHANGE_TOTAL_BUDGET_SECONDS: "2400"' in workflow
assert 'OPENCODE_RUN_TIMEOUT_SECONDS: "300"' in workflow
assert 'OPENCODE_TOTAL_RETRY_BUDGET_SECONDS: "600"' in workflow
assert 'OPENCODE_POOL_STEP_TIMEOUT_SECONDS: "1080"' in workflow
assert 'timeout --kill-after=30s "${OPENCODE_POOL_STEP_TIMEOUT_SECONDS:-1080}s"' in workflow
assert 'OPENCODE_POOL_STEP_TIMEOUT_SECONDS: "2880"' in workflow
assert 'timeout --kill-after=30s "${OPENCODE_POOL_STEP_TIMEOUT_SECONDS:-2880}s"' in workflow
assert "OpenCode model pool exceeded the outer" in workflow
assert 'OPENCODE_POOL_MAX_CYCLES: "1"' in workflow
assert re.search(r"Run OpenCode PR Review model pool[\s\S]{0,280}continue-on-error: true", workflow)
Expand All @@ -703,18 +703,18 @@ def test_workflow_provisions_sandbox_tool_and_reviewer_agent():
assert 'OPENCODE_RUN_TIMEOUT_SECONDS: "300"' in workflow
assert 'OPENCODE_EXPORT_TIMEOUT_SECONDS: "120"' in workflow
assert 'OPENCODE_TOTAL_RETRY_BUDGET_SECONDS: "600"' in workflow
assert 'OPENCODE_POOL_STEP_TIMEOUT_SECONDS: "1080"' in workflow
assert 'OPENCODE_POOL_STEP_TIMEOUT_SECONDS: "2880"' in workflow
assert 'OPENCODE_POOL_MAX_CYCLES: "1"' in workflow
assert 'OPENCODE_DYNAMIC_REVIEW_CADENCE: "true"' in workflow
assert 'OPENCODE_CHANGED_FILES_FILE: ${{ runner.temp }}/opencode-changed-files.txt' in workflow
assert 'OPENCODE_SMALL_CHANGE_RUN_TIMEOUT_SECONDS: "300"' in workflow
assert 'OPENCODE_SMALL_CHANGE_TOTAL_BUDGET_SECONDS: "600"' in workflow
assert 'OPENCODE_MEDIUM_CHANGE_RUN_TIMEOUT_SECONDS: "420"' in workflow
assert 'OPENCODE_MEDIUM_CHANGE_TOTAL_BUDGET_SECONDS: "900"' in workflow
assert 'OPENCODE_LARGE_CHANGE_RUN_TIMEOUT_SECONDS: "420"' in workflow
assert 'OPENCODE_LARGE_CHANGE_TOTAL_BUDGET_SECONDS: "1080"' in workflow
assert 'OPENCODE_UNKNOWN_CHANGE_RUN_TIMEOUT_SECONDS: "420"' in workflow
assert 'OPENCODE_UNKNOWN_CHANGE_TOTAL_BUDGET_SECONDS: "900"' in workflow
assert 'OPENCODE_SMALL_CHANGE_RUN_TIMEOUT_SECONDS: "900"' in workflow
assert 'OPENCODE_SMALL_CHANGE_TOTAL_BUDGET_SECONDS: "1500"' in workflow
assert 'OPENCODE_MEDIUM_CHANGE_RUN_TIMEOUT_SECONDS: "1500"' in workflow
assert 'OPENCODE_MEDIUM_CHANGE_TOTAL_BUDGET_SECONDS: "2400"' in workflow
assert 'OPENCODE_LARGE_CHANGE_RUN_TIMEOUT_SECONDS: "1800"' in workflow
assert 'OPENCODE_LARGE_CHANGE_TOTAL_BUDGET_SECONDS: "2700"' in workflow
assert 'OPENCODE_UNKNOWN_CHANGE_RUN_TIMEOUT_SECONDS: "1500"' in workflow
assert 'OPENCODE_UNKNOWN_CHANGE_TOTAL_BUDGET_SECONDS: "2400"' in workflow
assert 'OPENCODE_DYNAMIC_MAX_CYCLES: "1"' in workflow
assert 'OPENCODE_BACKOFF_MAX_SECONDS: "30"' in workflow
publish_step = workflow.split(" - name: Publish OpenCode review outcome", 1)[1].split(
Expand Down
Loading