From 7ad6d784ce552c95074aeb54dd0a2e0ba52b0409 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 10:16:21 +0900 Subject: [PATCH] fix(strix): remove repository-side scan retries Signed-off-by: Seongho Bae --- .github/workflows/strix.yml | 57 ++----------------- ...kend_unavailable_after_exempted_finding.py | 30 ++-------- 2 files changed, 11 insertions(+), 76 deletions(-) diff --git a/.github/workflows/strix.yml b/.github/workflows/strix.yml index 4f621b1f14..9caeca287e 100644 --- a/.github/workflows/strix.yml +++ b/.github/workflows/strix.yml @@ -920,9 +920,6 @@ jobs: # The gateway auto pool is provider-diverse. Strix function tools # must not send a provider-specific reasoning setting to every route. STRIX_REASONING_EFFORT: none - STRIX_LLM_MAX_RETRIES: 1 - STRIX_TRANSIENT_RETRY_PER_MODEL: 2 - STRIX_TRANSIENT_RETRY_BACKOFF_SECONDS: 60 # The gateway owns discovery and provider failover; Strix must not # bypass its ZDR/privacy policy with an external fallback model. STRIX_FALLBACK_MODELS: "" @@ -968,60 +965,16 @@ jobs: # evidence, but remains non-passing because no authoritative complete # vulnerability result exists. # - # A typed provider outage with no reported vulnerability finding is - # retried with linear backoff inside this step so transient - # provider failures do not fail the required check on the first - # attempt. Genuine findings, configuration failures, and unexpected - # exit codes never retry, and all-terminal outcomes remain fail-closed. + # The gateway owns provider discovery, repair, and failover. Invoke + # the trusted gate once so repository-side retries cannot multiply a + # single PR scan into hours of shared-runner occupancy. strix_run_log="$RUNNER_TEMP/strix_gate_console.log" : > "$strix_run_log" strix_terminal_log="$strix_run_log" strix_rc=0 - strix_gate_attempt=1 set +e - while : ; do - strix_attempt_log="$RUNNER_TEMP/strix_gate_console_attempt_${strix_gate_attempt}.log" - : > "$strix_attempt_log" - bash "$TRUSTED_STRIX_GATE" 2>&1 | tee "$strix_attempt_log" - strix_rc="${PIPESTATUS[0]}" - cat "$strix_attempt_log" >> "$strix_run_log" - strix_terminal_log="$strix_attempt_log" - if [ "$strix_rc" -eq 0 ]; then - break - fi - # Only exit-code 1 scan failures can be infrastructure outcomes. - if [ "$strix_rc" -ne 1 ]; then - break - fi - # Scope this attempt's retry decision to the log tail after the - # last pipeline-continuation marker, exactly like the terminal - # classification below: an already-exempted finding before the - # marker must not mask a retryable outage after it. - strix_retry_scope_log="$strix_terminal_log" - if grep -Fq 'allowing pipeline continuation' "$strix_terminal_log"; then - strix_retry_scope_log="$RUNNER_TEMP/strix_gate_console_tail.log" - awk '/allowing pipeline continuation/{buf=""; next} {buf=buf $0 "\n"} END{printf "%s", buf}' \ - "$strix_terminal_log" > "$strix_retry_scope_log" - fi - # A reported vulnerability is authoritative evidence: never retry - # and never risk downgrading it. - if grep -Eiq "$reported_vulnerability_signal" "$strix_retry_scope_log"; then - break - fi - # Retry only recognized provider-outage / model-behavior classes. - if ! grep -Eiq "$backend_unavailable_signal" "$strix_retry_scope_log" \ - && ! grep -Eq "$model_behavior_error_signal" "$strix_retry_scope_log"; then - break - fi - backoff_seconds=$(( ${STRIX_GATE_RETRY_BACKOFF_SECONDS:-90} * strix_gate_attempt )) - if [ "$strix_gate_attempt" -ge 3 ]; then - echo "Provider-unavailable Strix attempt ${strix_gate_attempt} reached the retry limit; failing closed." >&2 - break - fi - echo "Strix provider outage on attempt ${strix_gate_attempt}; retrying after ${backoff_seconds}s backoff." >&2 - sleep "$backoff_seconds" - strix_gate_attempt=$(( strix_gate_attempt + 1 )) - done + bash "$TRUSTED_STRIX_GATE" 2>&1 | tee "$strix_terminal_log" + strix_rc="${PIPESTATUS[0]}" set -e if [ "$strix_rc" -eq 0 ]; then diff --git a/tests/test_strix_backend_unavailable_after_exempted_finding.py b/tests/test_strix_backend_unavailable_after_exempted_finding.py index f9b75e313d..029f43ec55 100644 --- a/tests/test_strix_backend_unavailable_after_exempted_finding.py +++ b/tests/test_strix_backend_unavailable_after_exempted_finding.py @@ -240,26 +240,6 @@ def test_bare_backend_outage_with_no_finding_is_non_passing( self.assertEqual(_run_gate_tail(GITHUB_MODELS_BROWNOUT), 1) - def test_exempted_finding_then_outage_recovers_on_second_attempt(self) -> None: - """An exempt finding before continuation must not block outage retry.""" - - gate = r"""#!/usr/bin/env bash -calls=$(( $(cat __COUNTER__) + 1 )) -echo "$calls" > __COUNTER__ -if [ "$calls" -le 1 ]; then - printf '%s\n' \ - "Strix findings are limited to unchanged files in this pull request; allowing pipeline continuation." \ - "LLM CONNECTION FAILED" \ - "Configured model and fallback models were unavailable." - exit 1 -fi -echo "scan complete" -exit 0 -""" - returncode, calls = _run_gate_retry(gate) - self.assertEqual(returncode, 0) - self.assertEqual(calls, 2) - def test_real_finding_after_continuation_never_retries(self) -> None: """A tail-scoped real finding is authoritative: zero retries, fail closed.""" @@ -276,12 +256,14 @@ def test_real_finding_after_continuation_never_retries(self) -> None: self.assertEqual(returncode, 1) self.assertEqual(calls, 1) - def test_retry_contract_preserves_logs_without_wall_clock_budget(self) -> None: - """Retries retain every attempt without imposing an inference deadline.""" + def test_workflow_uses_one_gateway_owned_attempt_without_wall_clock_budget(self) -> None: + """The workflow does not add retries or a repository-authored deadline.""" workflow = STRIX_WORKFLOW.read_text(encoding="utf-8") - self.assertIn('strix_attempt_log="$RUNNER_TEMP/strix_gate_console_attempt_', workflow) - self.assertIn('cat "$strix_attempt_log" >> "$strix_run_log"', workflow) + self.assertNotIn("strix_gate_attempt", workflow) + self.assertNotIn("STRIX_GATE_RETRY_BACKOFF_SECONDS", workflow) + self.assertNotIn("STRIX_TRANSIENT_RETRY_PER_MODEL:", workflow) + self.assertNotIn("STRIX_LLM_MAX_RETRIES:", workflow) self.assertNotIn("strix_gate_attempt_budget_seconds", workflow) self.assertNotIn("STRIX_PROCESS_TIMEOUT_SECONDS:", workflow) self.assertNotIn("STRIX_TOTAL_TIMEOUT_SECONDS:", workflow)