"""IMP-09 PR 1 — fixture-driven regression checks. Loads the YAML snapshots under tests/phase_z2/fixtures/ and exercises build_layout_css + _attempt_zone_ratio_retry against them. Any drift in IMP-09 output forces a fixture refresh, which is the lock surface called out in Stage 3 round 4 §5. """ from __future__ import annotations from pathlib import Path import pytest import yaml from src.phase_z2_pipeline import _attempt_zone_ratio_retry, build_layout_css FIXTURES_DIR = Path(__file__).parent / "fixtures" def _load_yaml(path: Path) -> dict: with path.open(encoding="utf-8") as f: return yaml.safe_load(f) # ──────────────────────── build_layout_css fixtures ──────────────────────── _BUILD_DIR = FIXTURES_DIR / "build_layout_css" _BUILD_FIXTURES = sorted(_BUILD_DIR.glob("*.yaml")) if _BUILD_DIR.exists() else [] @pytest.mark.parametrize( "fixture_path", _BUILD_FIXTURES, ids=[p.stem for p in _BUILD_FIXTURES], ) def test_build_layout_css_matches_fixture(fixture_path: Path): payload = _load_yaml(fixture_path) inp = payload["input"] expected = payload["expected_layout_css"] result = build_layout_css( inp["layout_preset"], inp["zones_data"], override_zone_geometries=inp.get("override_zone_geometries"), ) # raw_zone_layout is intentionally not snapshotted (contains # solver internals); compare the rest. actual = {k: v for k, v in result.items() if k != "raw_zone_layout"} assert actual == expected, ( f"layout_css drift in fixture {fixture_path.name}:\n" f" expected={expected}\n actual={actual}" ) # ────────────────────────── retry_gate fixtures ────────────────────────── _RETRY_DIR = FIXTURES_DIR / "retry_gate" _RETRY_FIXTURES = sorted(_RETRY_DIR.glob("*.yaml")) if _RETRY_DIR.exists() else [] @pytest.mark.parametrize( "fixture_path", _RETRY_FIXTURES, ids=[p.stem for p in _RETRY_FIXTURES], ) def test_retry_gate_matches_fixture(fixture_path: Path, tmp_path: Path): payload = _load_yaml(fixture_path) layout_css = payload["input_layout_css"] router_decision = payload["router_decision"] expected = payload["expected_gate"] trace = _attempt_zone_ratio_retry( run_dir=tmp_path, out_path=tmp_path / "final.html", slide_title="fixture", slide_footer=None, zones_data=[], debug_zones=[], layout_preset="fixture", layout_css=layout_css, overflow={}, fit_classification={}, router_decision=router_decision, gap_px=14, ) assert trace["retry_attempted"] == expected["retry_attempted"] skip_reason = trace.get("retry_skipped_reason") for needle in expected.get("retry_skipped_reason_contains", []): assert skip_reason is not None and needle in skip_reason, ( f"expected {needle!r} in retry_skipped_reason, got {skip_reason!r}" ) for forbidden in expected.get("retry_skipped_reason_excludes", []): if skip_reason is not None: assert forbidden not in skip_reason, ( f"forbidden {forbidden!r} found in retry_skipped_reason {skip_reason!r}" )