"""ORCH-41: tests for resolve_agent_effort + effort validation + flag assembly. Mirrors test_resolve_agent_model's 4-level priority for the --effort lever, and adds: - validation: a value outside {low,medium,high,xhigh,max} is dropped -> "" - flag assembly: --model / --effort / --fallback-model are present/absent in the built command exactly when the resolved value is non-empty. """ import os import tempfile import pytest os.environ.setdefault("ORCH_DB_PATH", os.path.join(tempfile.gettempdir(), "test_orch41_effort.db")) os.environ.setdefault("ORCH_GITEA_TOKEN", "test-token") os.environ.setdefault("ORCH_PLANE_API_TOKEN", "test-token") from src.agents.launcher import ( resolve_agent_effort, resolve_agent_model, VALID_EFFORTS, ) from src.config import settings from src import projects as P from src.projects import ProjectConfig, reload_projects ORCH_PLANE_ID = "8da6aa25-a60e-44d6-a1e2-d8ae59aa7d6a" # ORCH-081/ORCH-52h: canonical effort per role (developer upgraded high -> xhigh). CANON_EFFORT = { "analyst": "high", "architect": "high", "developer": "xhigh", "reviewer": "high", "tester": "medium", "deployer": "medium", } @pytest.fixture(autouse=True) def _clean_settings(monkeypatch): monkeypatch.setattr(settings, "agent_effort_default", "high") for a, e in CANON_EFFORT.items(): monkeypatch.setattr(settings, f"agent_effort_{a}", e) monkeypatch.setattr(P.settings, "projects_json", "") reload_projects() yield reload_projects() def _install_registry(monkeypatch, agent_efforts): reg = [ProjectConfig( plane_project_id=ORCH_PLANE_ID, repo="orchestrator", work_item_prefix="ORCH", name="orchestrator", agent_efforts=agent_efforts, )] monkeypatch.setattr(P, "PROJECTS", reg) monkeypatch.setattr(P, "_BY_PLANE_ID", {p.plane_project_id: p for p in reg}) monkeypatch.setattr(P, "_BY_REPO", {p.repo: p for p in reg}) # ---- TC-01: canonical defaults (AC-1 / FR-4) -------------------------------- def test_default_split(): assert resolve_agent_effort("developer") == "xhigh" assert resolve_agent_effort("architect") == "high" assert resolve_agent_effort("tester") == "medium" assert resolve_agent_effort("deployer") == "medium" @pytest.mark.parametrize("agent,expected", list(CANON_EFFORT.items())) def test_canonical_effort_all_roles(agent, expected): assert resolve_agent_effort(agent) == expected # ---- TC-02: empty env -> per-role floor (variant c, AC-2) ------------------- @pytest.mark.parametrize("agent,expected", list(CANON_EFFORT.items())) def test_empty_env_falls_back_to_per_role_floor(monkeypatch, agent, expected): """Models the prod bug: ORCH_AGENT_EFFORT_*= present-but-empty -> every level resolves to '' on the instance; the per-role floor (config class-default) must still yield the canonical level (NOT '').""" monkeypatch.setattr(settings, "agent_effort_default", "") for a in CANON_EFFORT: monkeypatch.setattr(settings, f"agent_effort_{a}", "") result = resolve_agent_effort(agent) assert result == expected assert result != "" # ---- unknown agent floor degrades to default (high), never '' --------------- def test_empty_env_unknown_agent_floor_is_default(monkeypatch): monkeypatch.setattr(settings, "agent_effort_default", "") monkeypatch.setattr(settings, "agent_effort_tester", "") # An agent with no agent_effort_ field falls back to the # agent_effort_default class-default (high), a safe non-empty floor. assert resolve_agent_effort("nonexistent_role") == "high" # ---- level 2: per-agent env beats default ----------------------------------- def test_per_agent_env(monkeypatch): monkeypatch.setattr(settings, "agent_effort_tester", "low") assert resolve_agent_effort("tester") == "low" # ---- level 1: project override wins ----------------------------------------- def test_project_override(monkeypatch): monkeypatch.setattr(settings, "agent_effort_developer", "high") _install_registry(monkeypatch, {"developer": "xhigh"}) assert resolve_agent_effort("developer", ORCH_PLANE_ID) == "xhigh" assert resolve_agent_effort("developer") == "high" # ---- validation: invalid value dropped -------------------------------------- def test_invalid_default_dropped(monkeypatch): monkeypatch.setattr(settings, "agent_effort_developer", "") monkeypatch.setattr(settings, "agent_effort_default", "turbo") assert resolve_agent_effort("developer") == "" def test_invalid_env_dropped(monkeypatch): monkeypatch.setattr(settings, "agent_effort_reviewer", "ultra") assert resolve_agent_effort("reviewer") == "" def test_invalid_project_override_dropped(monkeypatch): _install_registry(monkeypatch, {"developer": "bogus"}) assert resolve_agent_effort("developer", ORCH_PLANE_ID) == "" def test_all_valid_efforts_pass(monkeypatch): monkeypatch.setattr(settings, "agent_effort_developer", "") for e in VALID_EFFORTS: monkeypatch.setattr(settings, "agent_effort_default", e) assert resolve_agent_effort("developer") == e # ---- TC-03: floor does NOT mask a typo (FR-3 / AC-5) ------------------------ def test_floor_does_not_mask_typo(monkeypatch): """An explicit invalid value is non-empty, so the floor is NOT applied: the value is validated and dropped to '' (never-break ORCH-41), even though the developer floor (xhigh) exists.""" monkeypatch.setattr(settings, "agent_effort_default", "") monkeypatch.setattr(settings, "agent_effort_developer", "turbo") assert resolve_agent_effort("developer") == "" # ---- TC-04: priority preserved — explicit config beats floor (FR-2) --------- def test_explicit_env_beats_floor(monkeypatch): """Operator may deliberately downgrade developer to high; the explicit non-empty env wins over the xhigh floor.""" monkeypatch.setattr(settings, "agent_effort_developer", "high") assert resolve_agent_effort("developer") == "high" def test_default_beats_floor(monkeypatch): """A non-empty global default wins over the per-role floor (floor is strictly below default): default=max with empty per-agent -> max, not the xhigh floor.""" monkeypatch.setattr(settings, "agent_effort_developer", "") monkeypatch.setattr(settings, "agent_effort_default", "max") assert resolve_agent_effort("developer") == "max" def test_project_override_beats_floor(monkeypatch): monkeypatch.setattr(settings, "agent_effort_developer", "") _install_registry(monkeypatch, {"developer": "high"}) assert resolve_agent_effort("developer", ORCH_PLANE_ID) == "high" # ---- TC-05: xhigh is a valid effort (FR-5) ---------------------------------- def test_xhigh_is_valid(): assert "xhigh" in VALID_EFFORTS # developer canonical xhigh resolves (is not dropped by validation) assert resolve_agent_effort("developer") == "xhigh" # ---- flag assembly (mirror of launcher cmd construction) -------------------- def _build_flags(model, effort, fb): model_flag = f"--model {model} " if model else "" effort_flag = f"--effort {effort} " if effort else "" fb_flag = f"--fallback-model {fb} " if fb else "" return f"{model_flag}{effort_flag}{fb_flag}" # ---- TC-06: flag assembly (AC-3) -------------------------------------------- def test_flags_present_when_configured(monkeypatch): monkeypatch.setattr(settings, "agent_fallback_model", "claude-sonnet-4-6") model = resolve_agent_model("developer") effort = resolve_agent_effort("developer") fb = settings.agent_fallback_model flags = _build_flags(model, effort, fb) assert "--model claude-opus-4-8 " in flags assert "--effort xhigh " in flags assert "--fallback-model claude-sonnet-4-6 " in flags def test_flags_effort_per_role(monkeypatch): """developer -> --effort xhigh; tester -> --effort medium (mirrors _spawn).""" assert "--effort xhigh " in _build_flags("", resolve_agent_effort("developer"), "") assert "--effort medium " in _build_flags("", resolve_agent_effort("tester"), "") def test_flags_absent_when_effort_empty(): """When the resolved effort is empty, --effort is omitted entirely. Mirrors the `f"--effort {effort} " if effort else ""` branch in _spawn (AC-3 negative case).""" flags = _build_flags("", "", "") assert flags == "" assert "--effort" not in flags def test_flags_absent_when_model_empty(monkeypatch): monkeypatch.setattr(settings, "agent_model_default", "") monkeypatch.setattr(settings, "agent_model_developer", "") monkeypatch.setattr(settings, "agent_fallback_model", "") model = resolve_agent_model("developer") fb = settings.agent_fallback_model flags = _build_flags(model, "", fb) assert flags == "" assert "--model" not in flags assert "--fallback-model" not in flags assert "--fallback-model" not in flags