"""Focused HUX-06 backend tests.""" from __future__ import annotations import json import sys from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] FOUNDATION = ROOT / "dockerfiles" / "hermes-hux-foundation" if str(FOUNDATION) not in sys.path: sys.path.insert(0, str(FOUNDATION)) from hux import contracts, identity, modes, store from hux.errors import Invalid from hux.server import build_router HEADERS = {"X-Hermes-Tenant-Identity": "slot-3", "X-Hux-Subject": "usr_0123456789abcdef", "X-Hux-Surface": "chat", "X-Hux-Relay-Key": "rk"} OTHER = {**HEADERS, "X-Hux-Subject": "usr_fedcba9876543210"} ALL_ON = ",".join(card["flag"] for card in contracts.load_flags()["cards"]) def call(router, method, path, body=None, headers=None): raw = b"" if body is None else json.dumps(body).encode() response = router.dispatch(method, path, {**HEADERS, **(headers or {})}, raw) return response.status, response.body, response.headers @pytest.fixture def setup(tmp_path, monkeypatch): monkeypatch.setenv("HUX_SWITCHYARD_ROUTE_CATALOG", "atlas/manual/codex/gpt-5,atlas/manual/claude/opus,atlas/manual/local/qwen-14b") router = build_router(tmp_path, {"HUX_FLAGS": ALL_ON, "HUX_ROUTER_KEY": "rk"}) _, project, _ = call(router, "POST", "/hux/v1/projects", {"name": "P"}) _, conversation, _ = call(router, "POST", "/hux/v1/conversations", {"title": "C", "project_id": project["id"]}) base = f"/hux/v1/projects/{project['id']}/conversations/{conversation['id']}/mode" return router, project, conversation, base def test_catalog_is_provider_neutral_and_private_is_local(setup): router, _, _, _ = setup status, body, _ = call(router, "GET", "/hux/v1/modes") assert status == 200 and [row["mode"] for row in body["items"]] == list(modes.MODE_NAMES) for row in body["items"]: assert contracts.validate("mode.schema.json", row) == [] if row["mode"] != "private": assert row["switchyard"]["route_id"].startswith("atlas/auto/") assert "/codex/" not in row["switchyard"]["route_id"] and "/claude/" not in row["switchyard"]["route_id"] private = body["items"][-1] assert private["constraints"]["providers"] == ["local"] and private["constraints"]["local_only"] is True def test_select_get_replay_and_conversation_privacy_mode(setup): router, project, conversation, base = setup body = {"project_id": project["id"], "mode": "private"} status, selected, headers = call(router, "PUT", base, body, {"If-Match": "0", "Idempotency-Key": "mode-key-0001"}) assert (status, selected["revision"], headers["ETag"]) == (200, 1, "1") assert selected["mode"]["mode"] == "private" and selected["mode"]["switchyard"]["route_id"].startswith("atlas/manual/local/") assert call(router, "GET", base)[1] == selected stored_conversation = call(router, "GET", f"/hux/v1/conversations/{conversation['id']}")[1] assert stored_conversation["mode"] == "private" status, replay, replay_headers = call(router, "PUT", base, body, {"If-Match": "0", "Idempotency-Key": "mode-key-0001"}) assert status == 200 and replay == selected and replay_headers["HUX-Replayed"] == "true" status, error, _ = call(router, "PUT", base, {**body, "mode": "fast"}, {"If-Match": "1", "Idempotency-Key": "mode-key-0001"}) assert (status, error["code"]) == (409, "conflict") def test_advanced_pin_is_explicit_catalogued_and_constrained(setup): router, project, _, base = setup common = {"project_id": project["id"], "mode": "thoughtful"} pin = "atlas/manual/claude/opus" status, selected, _ = call(router, "PUT", base, {**common, "advanced": True, "override_route_id": pin}, {"If-Match": "0", "Idempotency-Key": "mode-key-0002"}) assert status == 200 and selected["mode"]["switchyard"]["override_route_id"] == pin next_headers = {"If-Match": "1", "Idempotency-Key": "mode-key-0003"} bad = [ {**common, "override_route_id": pin}, {**common, "advanced": True}, {**common, "advanced": True, "override_route_id": "atlas/manual/claude/not-catalogued"}, {**common, "advanced": True, "override_route_id": "atlas/auto/deep"}, {"project_id": project["id"], "mode": "private", "advanced": True, "override_route_id": "atlas/manual/claude/opus"}, ] for index, body in enumerate(bad): status, error, _ = call(router, "PUT", base, body, {**next_headers, "Idempotency-Key": f"bad-mode-{index:03}"}) assert status == 400 and error["code"] == "invalid" status, local, _ = call(router, "PUT", base, {"project_id": project["id"], "mode": "private", "advanced": True, "override_route_id": "atlas/manual/local/qwen-14b"}, next_headers) assert status == 200 and local["revision"] == 2 @pytest.mark.parametrize("body,headers", [ ({"project_id": None, "mode": "fast"}, {"If-Match": "0", "Idempotency-Key": "mode-key-0100"}), ({"project_id": "prj_wrong0000", "mode": "fast"}, {"If-Match": "0", "Idempotency-Key": "mode-key-0101"}), ({"mode": "fast"}, {"If-Match": "0"}), ({"mode": "fast"}, {"Idempotency-Key": "mode-key-0102"}), ({"mode": "unknown"}, {"If-Match": "0", "Idempotency-Key": "mode-key-0103"}), ]) def test_selection_fails_closed(setup, body, headers): router, project, _, base = setup if "project_id" not in body: body["project_id"] = project["id"] status, _, _ = call(router, "PUT", base, body, headers) assert status in {400, 404} def test_revision_scope_and_catalog_bounds(setup, monkeypatch): router, project, _, base = setup body = {"project_id": project["id"], "mode": "fast"} assert call(router, "PUT", base, body, {"If-Match": "1", "Idempotency-Key": "mode-key-0200"})[0] == 409 assert call(router, "GET", base)[0] == 404 assert call(router, "GET", base, headers=OTHER)[0] == 404 wrong = base.replace(project["id"], "prj_missing0000") assert call(router, "GET", wrong)[0] == 404 monkeypatch.setenv("HUX_SWITCHYARD_ROUTE_CATALOG", ",".join(f"atlas/manual/codex/r{i}" for i in range(257))) advanced = {**body, "advanced": True, "override_route_id": "atlas/manual/codex/r1"} assert call(router, "PUT", base, advanced, {"If-Match": "0", "Idempotency-Key": "mode-key-0201"})[0] == 400 monkeypatch.setenv("HUX_SWITCHYARD_ROUTE_CATALOG", "garbage,atlas/manual/codex/gpt-5") assert modes._catalog() == {"atlas/manual/codex/gpt-5"} def test_body_and_header_validation(setup): router, project, _, base = setup assert router.dispatch("PUT", base, HEADERS, b"[]").status == 400 body = {"project_id": project["id"], "mode": "fast"} assert call(router, "PUT", base, body, {"If-Match": "x", "Idempotency-Key": "mode-key-0300"})[0] == 400 assert call(router, "PUT", base, body, {"If-Match": "0", "Idempotency-Key": "short"})[0] == 400 assert call(router, "PUT", base, {**body, "provider": "claude"}, {"If-Match": "0", "Idempotency-Key": "mode-key-0301"})[0] == 400 def test_missing_project_and_defensive_contract_failures(setup, monkeypatch): router, project, _, base = setup scoped = store.TenantStore(router.data_root, identity.resolve(HEADERS, {"HUX_ROUTER_KEY": "rk"})) scoped.delete("projects", project["id"]) assert call(router, "GET", base)[0] == 404 original = modes.rules.mode_contract monkeypatch.setattr(modes.rules, "mode_contract", lambda *_: (_ for _ in ()).throw(ValueError("bad mapping"))) with pytest.raises(Invalid, match="bad mapping"): modes._contract("fast", False, None) monkeypatch.setattr(modes.rules, "mode_contract", lambda *_: {"schema": "broken"}) with pytest.raises(Invalid, match="contract validation"): modes._contract("fast", False, None) monkeypatch.setattr(modes.rules, "mode_contract", original) record = original("fast") record["switchyard"]["route_id"] = "atlas/manual/codex/gpt-5" monkeypatch.setattr(modes.rules, "mode_contract", lambda *_: record) with pytest.raises(Invalid, match="may not pin"): modes._contract("fast", False, None) def test_source_and_test_files_stay_bounded(): assert len((FOUNDATION / "hux" / "modes.py").read_text().splitlines()) <= 500 assert len(Path(__file__).read_text().splitlines()) <= 500