diff --git a/CHANGELOG.md b/CHANGELOG.md index 39c61c142b..de078317f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ this file. The format follows Keep a Changelog, and versioned releases follow Semantic Versioning where the repository publishes a release. ## [Unreleased] +- Remove Noema's fixed 120-second LLM response timeout. The central workflow + now owns cancellation, allowing the documented multi-hour review path to + finish instead of failing after a healthy orchestrator preflight. - Harden the review sidecar's per-account catalog cap against silent drift: `contextual_orchestrator_review_launcher.py`'s two `build_zdr_prioritized_catalog` call sites now source their diff --git a/docs/doctoring/noema-orchestrator-free-zdr.md b/docs/doctoring/noema-orchestrator-free-zdr.md index ec1add661a..2ef7959d52 100644 --- a/docs/doctoring/noema-orchestrator-free-zdr.md +++ b/docs/doctoring/noema-orchestrator-free-zdr.md @@ -79,6 +79,21 @@ Runtime acceptance requires a GitHub review whose commit and embedded head SHA both match the live PR head. A successful Actions job without that review body is not Noema review evidence. +## 2026-08-31 response timeout removal + +Two exact-head naruon Noema jobs reached a healthy sidecar and then failed at +the same `urllib` call after its hard-coded 120-second response timeout. This +was shorter than the standing review contract, which permits central LLM +reviews to take two hours or more. `call_llm` now passes `timeout=None`; the +workflow remains the cancellation and concurrency boundary. Redirect refusal, +URL validation, loopback pinning, bounded prompt construction, and substantive +verdict validation are unchanged. + +Regression tests assert that both the ordinary provider seam and the rejected +verdict repair call use the unbounded request contract. Hosted acceptance still +requires an exact-head review verdict; removing the client timeout does not +turn an incomplete run into passing evidence. + For GitHub App credentials, reviewer identity is bound to the pinned token mint action's app slug and numeric installation ID. PAT and OIDC credentials continue to resolve their actor through GitHub's authenticated API. diff --git a/scripts/ci/noema_review_gate.py b/scripts/ci/noema_review_gate.py index 90a69bed31..be6a666cce 100644 --- a/scripts/ci/noema_review_gate.py +++ b/scripts/ci/noema_review_gate.py @@ -653,7 +653,8 @@ def call_llm( method="POST", ) opener = urllib.request.build_opener(NoRedirectHandler()) - with opener.open(request, timeout=120) as response: # nosec B310 + # Noema reviews can legitimately take hours; the workflow owns cancellation. + with opener.open(request, timeout=None) as response: # nosec B310 raw = response.read().decode("utf-8") data = json.loads(raw) content = (((data.get("choices") or [{}])[0].get("message") or {}).get("content") or "").strip() diff --git a/tests/test_noema_review_gate.py b/tests/test_noema_review_gate.py index 338d46ba81..6aee3fdfab 100644 --- a/tests/test_noema_review_gate.py +++ b/tests/test_noema_review_gate.py @@ -688,7 +688,7 @@ def read(self): class Opener: def open(self, request, timeout): - assert timeout == 120 + assert timeout is None payloads.append(json.loads(request.data)) return Response(invalid if len(payloads) == 1 else valid) diff --git a/tests/test_repository_branch_coverage_review_schedulers.py b/tests/test_repository_branch_coverage_review_schedulers.py index 85cdc0b964..8ce3361292 100644 --- a/tests/test_repository_branch_coverage_review_schedulers.py +++ b/tests/test_repository_branch_coverage_review_schedulers.py @@ -62,8 +62,8 @@ def read(self) -> bytes: class Opener: """Open one deterministic provider response.""" - def open(self, _request: Any, timeout: int) -> Response: - assert timeout == 120 + def open(self, _request: Any, timeout: None) -> Response: + assert timeout is None return Response() monkeypatch.setattr(noema.urllib.request, "build_opener", lambda *_args: Opener())