From b6d9cdaf0a4afc8f7429afbe7a713dc5888ad0c5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 30 Sep 2026 14:29:17 +0900 Subject: [PATCH 1/2] test(opencode): bind route proof to sent HTTP status, not CLI rendering Preserve real CLI URL assertions and require the stub to have written 200 or 404. The inherited stderr wording assertion raced fixture cleanup on busy hosts; this does not change any production timeout, retry or security gate. Co-Authored-By: Claude Code --- ...-route-proof-not-cli-rendering-20260930.md | 28 +++++++++++++++++++ ...test_opencode_gateway_route_integration.py | 18 +++++++----- 2 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 docs/doctoring/gateway-route-proof-not-cli-rendering-20260930.md diff --git a/docs/doctoring/gateway-route-proof-not-cli-rendering-20260930.md b/docs/doctoring/gateway-route-proof-not-cli-rendering-20260930.md new file mode 100644 index 0000000000..a09925febf --- /dev/null +++ b/docs/doctoring/gateway-route-proof-not-cli-rendering-20260930.md @@ -0,0 +1,28 @@ +# Gateway route proof and CLI rendering + +The executed route test introduced in `9c6d05374` correctly observes the +installed OpenCode CLI's request URL, but its negative case additionally +required `not found` to appear in CLI output before fixture cleanup. On a busy +host the expected `/chat/completions` request and gateway 404 occurred without +that display text. A full run therefore failed with 5,176 other tests passing, +while the same two CLI tests separately passed in 47.70 seconds. + +The fixture intentionally stops the CLI after observing a request; that is +transport evidence, not a terminal CLI error-rendering receipt. No production +request timeout, provider retry, review verdict, or sanitizer is changed. + +The repair records HTTP statuses only after the stub writes its response. +The real installed CLI must still request `/v1/chat/completions` for the shipped +configuration and `/chat/completions` for the bare-origin regression. Those +requests must respectively receive a sent 200 and 404 response. Delayed or +redacted CLI text is no longer confused with the network path. The stub retains +the pinned gateway's error body; this does not require production logs to expose +raw provider errors. + +Before repair: the unchanged negative case failed at the display-text assertion. +After repair: both real CLI cases passed in 40.56 seconds. The complete suite +and current-head hosted evidence remain separate acceptance steps. + +This is an inherited test-reliability repair, separated from the Noema +input-modality catalog change. It is not a security-finding exception or proof +that any provider HTTP 400 incident has been resolved. diff --git a/tests/test_opencode_gateway_route_integration.py b/tests/test_opencode_gateway_route_integration.py index 3893914c0e..c1560872c7 100644 --- a/tests/test_opencode_gateway_route_integration.py +++ b/tests/test_opencode_gateway_route_integration.py @@ -8,9 +8,10 @@ These tests run the installed OpenCode CLI against a stub that answers exactly like the vendored gateway — the served route succeeds, every other route 404s -with the gateway's own wording — and record which path the CLI asked for. The -tracked ``opencode.jsonc`` provider block is the input, so the proof follows -the shipped config instead of a copy of it. +with the gateway's own wording — and record the requested path and sent status. +The tracked ``opencode.jsonc`` provider block is the input, so the proof follows +the shipped config instead of a copy of it. CLI error rendering is not a +transport receipt and can lag the response on a busy host. They skip when no ``opencode`` binary is present (CI images for the quality workflows do not install it); local execution is the evidence. @@ -52,6 +53,7 @@ class _GatewayStub(BaseHTTPRequestHandler): """Answer like the vendored gateway: one served route, 404 elsewhere.""" requested_paths: list[str] = [] + responses: list[tuple[str, int]] = [] def do_POST(self) -> None: # noqa: N802 - BaseHTTPRequestHandler API """Record the requested path and answer as the gateway would.""" @@ -92,6 +94,7 @@ def _send(self, status: int, payload: dict) -> None: self.send_header("content-length", str(len(body))) self.end_headers() self.wfile.write(body) + type(self).responses.append((self.path, status)) def log_message(self, *args: object) -> None: """Silence the default stderr access log.""" @@ -101,6 +104,7 @@ def log_message(self, *args: object) -> None: def gateway_stub_fixture(): """Serve the gateway stub on a loopback port for one test.""" _GatewayStub.requested_paths = [] + _GatewayStub.responses = [] server = HTTPServer(("127.0.0.1", 0), _GatewayStub) thread = threading.Thread(target=server.serve_forever, daemon=True) thread.start() @@ -190,15 +194,15 @@ def test_tracked_config_requests_the_gateway_served_route(gateway_stub, tmp_path _run_opencode(tmp_path, base_url, origin, requested_paths) assert requested_paths, "the CLI issued no request to the gateway stub" assert requested_paths[0] == GATEWAY_SERVED_ROUTE + assert _GatewayStub.responses[0] == (GATEWAY_SERVED_ROUTE, 200) def test_bare_origin_reproduces_the_route_not_found_outage(gateway_stub, tmp_path) -> None: - """Dropping /v1 must reproduce the unserved path and the gateway wording.""" + """Dropping /v1 must request an unserved path for which the stub sends 404.""" origin, requested_paths = gateway_stub bare = "{env:CONTEXTUAL_ORCHESTRATOR_BASE_URL}" - stdout, stderr = _run_opencode(tmp_path, bare, origin, requested_paths) + _run_opencode(tmp_path, bare, origin, requested_paths) assert requested_paths, "the CLI issued no request to the gateway stub" assert requested_paths[0] == "/chat/completions" assert requested_paths[0] != GATEWAY_SERVED_ROUTE - combined = f"{stdout}\n{stderr}".casefold() - assert GATEWAY_ROUTE_NOT_FOUND_MESSAGE in combined + assert _GatewayStub.responses[0] == ("/chat/completions", 404) From 62f3797982e4d137d9914c04d190a355d0e9b50a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 30 Sep 2026 20:41:58 +0900 Subject: [PATCH 2/2] ci: refresh checks on security prerequisite