"""S2.5 (Step 9) consolidation guard (T-2.5e): the four scripted ``_inner_get_response`` bodies collapsed to ONE canonical client (``simulation.ScriptedChatClient``); conftest's three test doubles now SUBCLASS it. These grep-guards lock that in — they go RED if a divergent ``_inner_get_response`` is re-added, if a ``src``→``tests`` import creeps in, or if a double stops subclassing the canonical. The guard is a regression lock over an already-verified consolidation: before the collapse there were five ``def _inner_get_response`` sites (four scripted + test_step5's own-lineage double); after, two. """ from __future__ import annotations from pathlib import Path _ROOT = Path(__file__).resolve().parents[1] def _py_files(base: str) -> list[Path]: return sorted((_ROOT / base).rglob("*.py")) def test_inner_get_response_collapsed_to_two_sites() -> None: """The four scripted clients collapse to ONE canonical ``_inner_get_response`` (simulation.py); test_step5's own-lineage double is the only other def. So exactly 2 def-sites remain — NOT 5.""" sites = [ p.relative_to(_ROOT).as_posix() for base in ("src", "tests") for p in _py_files(base) if p.name != Path(__file__).name # this guard file references the pattern in prose and "def _inner_get_response" in p.read_text(encoding="utf-8") ] assert sorted(sites) == [ "src/portfolio_optimiser/simulation.py", "tests/test_step5_refine_loadbearing.py", ], f"expected the four scripted bodies collapsed to one canonical + test_step5's, got: {sites}" def test_no_src_imports_tests() -> None: """No ``src`` module imports from ``tests`` — the canonical lives in ``src/simulation.py`` so ``conftest`` imports ``src``, never the reverse (the forbidden src→tests direction).""" offenders = [ p.relative_to(_ROOT).as_posix() for p in _py_files("src") if ("from tests" in (text := p.read_text(encoding="utf-8")) or "import tests" in text) ] assert offenders == [], f"src must not import tests: {offenders}" def test_conftest_doubles_subclass_canonical() -> None: """conftest's three test doubles genuinely SUBCLASS the canonical ``ScriptedChatClient`` (delegating the shared body) — so the consolidation is real, not cosmetic.""" from conftest import ( ScriptedChatClient, SyntheticUsageChatClient, _ProjectAwareUsageChatClient, _RecordingChatClient, ) assert issubclass(SyntheticUsageChatClient, ScriptedChatClient) assert issubclass(_ProjectAwareUsageChatClient, ScriptedChatClient) assert issubclass(_RecordingChatClient, ScriptedChatClient)