"""Release gates for bounded, advisory-only voice route preflight.""" from __future__ import annotations import importlib.util import json import sys import threading import time from http.server import ThreadingHTTPServer from types import SimpleNamespace from urllib.error import HTTPError from urllib.request import Request, urlopen import pytest from testing.tests.test_hermes_chat_support import ROOT HERMES = ROOT / "services" / "hermes" def _load_runtime(monkeypatch): """Load the sibling runtime modules without requiring httpx in image CI.""" monkeypatch.setitem(sys.modules, "httpx", SimpleNamespace()) preflight_path = HERMES / "scripts" / "voice_route_preflight.py" spec = importlib.util.spec_from_file_location("voice_route_preflight", preflight_path) assert spec and spec.loader preflight = importlib.util.module_from_spec(spec) spec.loader.exec_module(preflight) monkeypatch.setitem(sys.modules, "voice_route_preflight", preflight) broker_path = HERMES / "scripts" / "classifier_broker.py" spec = importlib.util.spec_from_file_location("classifier_broker", broker_path) assert spec and spec.loader broker = importlib.util.module_from_spec(spec) spec.loader.exec_module(broker) return preflight, broker @pytest.mark.parametrize( "payload", [ {}, {"turn_id": "bad/id", "revision": 1, "transcript": "long enough text"}, {"turn_id": "nonce-1", "revision": True, "transcript": "long enough text"}, {"turn_id": "nonce-1", "revision": 0, "transcript": "long enough text"}, {"turn_id": "nonce-1", "revision": 1, "transcript": None}, {"turn_id": "nonce-1", "revision": 1, "transcript": "short"}, {"turn_id": "nonce-1", "revision": 1, "transcript": "x" * 513}, ], ) def test_preflight_input_bounds_fail_closed(monkeypatch, payload): preflight, _ = _load_runtime(monkeypatch) with pytest.raises(ValueError): preflight.validate_request(payload) def test_preflight_is_same_14b_model_and_never_hosts_a_foreground_turn(monkeypatch): preflight, _ = _load_runtime(monkeypatch) payload = preflight.inference_payload("Please compare these two safe approaches") assert preflight.MODEL == "qwen2.5:14b-instruct-q4_0" assert payload["model"] == preflight.MODEL assert payload["stream"] is True assert payload["max_tokens"] <= 16 assert payload["temperature"] == 0 assert "tools" not in payload assert "provider" not in payload assert preflight.TIMEOUT_SECONDS <= 0.75 def test_preflight_is_once_per_random_browser_turn_and_authority_preempts(monkeypatch): preflight, _ = _load_runtime(monkeypatch) coordinator = preflight.Coordinator() cancel = coordinator.begin("8f" * 16 + "-1-1") assert cancel is not None class Resource: closed = False def close(self): self.closed = True client = Resource() response = Resource() assert coordinator.register(cancel, client=client, response=response) started = time.monotonic() coordinator.begin_authoritative() assert time.monotonic() - started < 0.1 assert cancel.is_set() assert client.closed and response.closed assert coordinator.begin("9e" * 16 + "-1-1") is None coordinator.end_authoritative() coordinator.end() # A completed browser turn cannot spend another 750 ms on a later partial. assert coordinator.begin("8f" * 16 + "-1-1") is None def test_coordinator_prunes_seen_turns_and_tolerates_close_failures(monkeypatch): preflight, _ = _load_runtime(monkeypatch) coordinator = preflight.Coordinator() now = time.monotonic() coordinator.seen = {f"turn-{index}": now for index in range(300)} coordinator._prune(now) assert len(coordinator.seen) == preflight.MAX_SEEN_TURNS class BrokenResource: def close(self): raise RuntimeError("close failed") cancel = coordinator.begin("fresh-turn") assert cancel is not None assert coordinator.register(cancel, client=BrokenResource(), response=BrokenResource()) coordinator.begin_authoritative() assert cancel.is_set() coordinator.end_authoritative() coordinator.end_authoritative() coordinator.end() unrelated = threading.Event() assert coordinator.register(unrelated) is False assert unrelated.is_set() idle = preflight.Coordinator() idle.begin_authoritative() idle.end_authoritative() def _stream_with_fake_httpx( monkeypatch, preflight, coordinator, lines, *, fail_build=False, close_raises=False, preempt_on_send=False, ): """Drive the streamed parser and cleanup branches without network I/O.""" class Response: def raise_for_status(self): return None def iter_lines(self): yield from lines def close(self): if close_raises: raise RuntimeError("response close failed") response = Response() class Client: def __init__(self, timeout): self.timeout = timeout def build_request(self, *args, **kwargs): if fail_build: raise RuntimeError("build failed") return (args, kwargs) def send(self, request, stream=False): assert stream is True if preempt_on_send: coordinator.begin_authoritative() return response def close(self): if close_raises: raise RuntimeError("client close failed") monkeypatch.setattr( preflight, "httpx", SimpleNamespace(Timeout=lambda *args, **kwargs: (args, kwargs), Client=Client), ) cancel = coordinator.begin("stream-" + str(time.monotonic_ns())) assert cancel is not None result = coordinator.stream("This provisional request is stable", cancel) if preempt_on_send: coordinator.end_authoritative() coordinator.end() return result def test_stream_parser_accepts_only_valid_bounded_json(monkeypatch): preflight, _ = _load_runtime(monkeypatch) coordinator = preflight.Coordinator() content = json.dumps({"tier": "deep"}) lines = [ "ignored", "data: not-json", 'data: {"choices":[]}', 'data: {"choices":[{"delta":{"content":7}}]}', "data: " + json.dumps({"choices": [{"delta": {"content": content}}]}), "data: [DONE]", ] assert _stream_with_fake_httpx(monkeypatch, preflight, coordinator, lines) == "deep" assert 'outcome="success"} 1' in coordinator.metrics() invalid = preflight.Coordinator() lines = [ "data: " + json.dumps( {"choices": [{"delta": {"content": json.dumps({"tier": "hosted"})}}]} ) ] assert _stream_with_fake_httpx(monkeypatch, preflight, invalid, lines) == "" assert 'outcome="failure"} 1' in invalid.metrics() def test_stream_fails_closed_on_oversize_preemption_and_cleanup_errors(monkeypatch): preflight, _ = _load_runtime(monkeypatch) oversized = preflight.Coordinator() line = "data: " + json.dumps({"choices": [{"delta": {"content": "x" * 129}}]}) assert _stream_with_fake_httpx(monkeypatch, preflight, oversized, [line]) == "" assert 'outcome="cancelled"} 1' in oversized.metrics() preempted = preflight.Coordinator() assert ( _stream_with_fake_httpx( monkeypatch, preflight, preempted, [], preempt_on_send=True ) == "" ) assert 'outcome="cancelled"} 1' in preempted.metrics() failed = preflight.Coordinator() assert ( _stream_with_fake_httpx( monkeypatch, preflight, failed, [], fail_build=True, close_raises=True, ) == "" ) assert 'outcome="failure"} 1' in failed.metrics() def test_stream_rejects_a_cancelled_reservation_before_network(monkeypatch): preflight, _ = _load_runtime(monkeypatch) coordinator = preflight.Coordinator() cancel = coordinator.begin("cancel-before-network") assert cancel is not None cancel.set() closed = {"value": False} class Client: def __init__(self, timeout): self.timeout = timeout def close(self): closed["value"] = True monkeypatch.setattr( preflight, "httpx", SimpleNamespace(Timeout=lambda *args, **kwargs: None, Client=Client), ) assert coordinator.stream("This request will be cancelled", cancel) == "" assert closed["value"] is True assert 'outcome="cancelled"} 1' in coordinator.metrics() coordinator.end() def test_absolute_deadline_closes_a_stalled_stream(monkeypatch): preflight, _ = _load_runtime(monkeypatch) monkeypatch.setattr(preflight, "TIMEOUT_SECONDS", 0.05) closed = threading.Event() class Response: def raise_for_status(self): return None def iter_lines(self): closed.wait(1) if False: yield "" def close(self): closed.set() response = Response() class Client: def __init__(self, timeout): self.timeout = timeout def build_request(self, *args, **kwargs): return (args, kwargs) def send(self, request, stream=False): assert stream is True return response def close(self): response.close() monkeypatch.setattr( preflight, "httpx", SimpleNamespace(Timeout=lambda *args, **kwargs: (args, kwargs), Client=Client), ) coordinator = preflight.Coordinator() cancel = coordinator.begin("ab" * 16 + "-2-1") assert cancel is not None started = time.monotonic() assert coordinator.stream("This provisional request is stable", cancel) == "" elapsed = time.monotonic() - started coordinator.end() assert elapsed < 0.25 assert 'outcome="timeout"} 1' in coordinator.metrics() def test_preflight_is_warm_only_and_final_payload_semantics_never_change(monkeypatch): preflight, broker = _load_runtime(monkeypatch) coordinator = preflight.Coordinator() authoritative = { "model": "qwen2.5:14b-instruct-q4_0", "messages": [ {"role": "system", "content": "normal routing contract"}, {"role": "user", "content": "Please compare the two deployments"}, ], "response_format": {"type": "json_object"}, } before = broker.compact_payload(authoritative) cancel = coordinator.begin("aa" * 16 + "-2-1") assert cancel is not None coordinator.end() after = broker.compact_payload(authoritative) assert before == after assert not hasattr(coordinator, "cache") assert not hasattr(coordinator, "remember") assert not hasattr(coordinator, "take_hint") assert not hasattr(preflight, "add_advisory_hint") def _post(server, payload): request = Request( f"http://127.0.0.1:{server.server_port}/voice/route-preflight", data=json.dumps(payload).encode(), headers={"Content-Type": "application/json"}, method="POST", ) with urlopen(request, timeout=2) as response: return response.status, response.headers, response.read() def test_handler_returns_exact_sanitized_binding_and_204_when_busy(monkeypatch): preflight, broker = _load_runtime(monkeypatch) coordinator = preflight.Coordinator() monkeypatch.setattr(broker, "VOICE_PREFLIGHT", coordinator) monkeypatch.setattr(coordinator, "stream", lambda transcript, cancel: "balanced") server = ThreadingHTTPServer(("127.0.0.1", 0), broker.VoiceHandler) thread = threading.Thread(target=server.serve_forever, daemon=True) thread.start() payload = { "turn_id": "cd" * 16 + "-3-1", "revision": 4, "transcript": "Private words that must never leave this boundary", } try: status, headers, raw = _post(server, payload) result = json.loads(raw) assert status == 200 assert headers["Cache-Control"] == "no-store" assert result == { "turn_id": payload["turn_id"], "revision": 4, "tier": "balanced", "target": "atlas/auto/balanced", "advisory": True, } assert b"Private words" not in raw status, headers, raw = _post(server, payload) assert status == 204 assert headers["Cache-Control"] == "no-store" assert raw == b"" finally: server.shutdown() server.server_close() thread.join(timeout=2) def test_public_and_authoritative_listeners_have_disjoint_route_surfaces(monkeypatch): _, broker = _load_runtime(monkeypatch) def post_status(handler, path): server = ThreadingHTTPServer(("127.0.0.1", 0), handler) thread = threading.Thread(target=server.serve_forever, daemon=True) thread.start() request = Request( f"http://127.0.0.1:{server.server_port}{path}", data=b"{}", headers={"Content-Type": "application/json"}, method="POST", ) try: with urlopen(request, timeout=2) as response: return response.status except HTTPError as error: return error.code finally: server.shutdown() server.server_close() thread.join(timeout=2) assert post_status(broker.Handler, "/voice/route-preflight") == 404 assert post_status(broker.VoiceHandler, "/v1/chat/completions") == 404