"""Bygg-energi mikro-eksempel — fixture-konsumerbarhet (shared/examples/bygg-energi-mikro). The energi micro-fixture is a *dev fixture* exercised through the whole build. These tests prove it is actually consumable, not merely present: 1. the IR projection (``validator-input.json``) drives the EXISTING deterministic validator to a ``ValidatedProposal`` (not a ``Rejection``) — energi mapped into the cost-IR unchanged; 2. that validator output is frozen against ``golden.json`` (seeded ``_MC_SEED=20260624``); 3. the OKF bundle is well-formed (every file declares ``type``; index cross-links resolve); 4. the seed verdict encodes a realization gap (RR < 1) consistent with the golden — the anchor the later step-1 ExpeL wiring becomes load-bearing against. No ``yaml`` dependency: frontmatter is parsed with a minimal key:value reader. """ from __future__ import annotations import json import re from pathlib import Path import pytest from portfolio_optimiser.ir import AffectedItem, SavingsProposal from portfolio_optimiser.validator import Rejection, ValidatedProposal, validate_proposal BUNDLE_DIR = Path(__file__).resolve().parents[1] / "shared" / "examples" / "bygg-energi-mikro" _EXPECTED_TYPES = { "index.md": "index", "bygg-kontor-nord.md": "project", "tiltak-led-retrofit.md": "hypothesis", "metode-ipmvp-a.md": "methodology", "kilder-realiseringsgap.md": "reference", "verdict-led-fro.md": "verdict", } def _parse_frontmatter(path: Path) -> dict[str, str]: """Minimal YAML-frontmatter reader: the ``---``-delimited leading block as key:value strings. Enough for ``type`` and the verdict's scalar fields; list values (``tags: [...]``) are kept verbatim and unused.""" lines = path.read_text(encoding="utf-8").splitlines() if not lines or lines[0].strip() != "---": return {} fm: dict[str, str] = {} for line in lines[1:]: if line.strip() == "---": break key, sep, val = line.partition(":") if sep: fm[key.strip()] = val.strip() return fm def _proposal_from_input() -> SavingsProposal: raw = json.loads((BUNDLE_DIR / "validator-input.json").read_text(encoding="utf-8")) return SavingsProposal( project_id=raw["project_id"], measure=raw["measure"], affected_items=[AffectedItem(**a) for a in raw["affected_items"]], claimed_saving_nok=raw["claimed_saving_nok"], assumptions={k: tuple(v) for k, v in raw["assumptions"].items()}, ) def _golden() -> dict: return json.loads((BUNDLE_DIR / "golden.json").read_text(encoding="utf-8")) def test_validator_input_validates() -> None: """The core: the energi tiltak, mapped into the cost-IR, passes the blocking validator — a ``ValidatedProposal``, never a ``Rejection`` (claimed 30k < P90 feasible).""" result = validate_proposal(_proposal_from_input()) assert isinstance(result, ValidatedProposal) assert not isinstance(result, Rejection) assert result.proposal.claimed_saving_nok < result.p90 assert result.p10 <= result.p50 <= result.p90 def test_validator_output_matches_golden() -> None: """Regression: the deterministic (seeded) percentiles match the frozen golden.""" result = validate_proposal(_proposal_from_input()) assert isinstance(result, ValidatedProposal) g = _golden()["validator"] assert g["validates"] is True assert result.nominal_feasible == pytest.approx(g["nominal_feasible"]) assert result.p10 == pytest.approx(g["p10"]) assert result.p50 == pytest.approx(g["p50"]) assert result.p90 == pytest.approx(g["p90"]) def test_bundle_files_declare_type() -> None: """Every OKF bundle file carries the one required field (``type``) with the expected value.""" for name, expected_type in _EXPECTED_TYPES.items(): fm = _parse_frontmatter(BUNDLE_DIR / name) assert fm.get("type") == expected_type, f"{name}: type={fm.get('type')!r}" def test_index_crosslinks_resolve() -> None: """Intra-bundle cross-links in ``index.md`` resolve to existing files (our own example must have no broken links, even though OKF consumers must tolerate them).""" index = (BUNDLE_DIR / "index.md").read_text(encoding="utf-8") targets = re.findall(r"\]\(([^)]+\.md)\)", index) internal = [t for t in targets if "/" not in t] assert internal, "expected intra-bundle .md links in index.md" for target in internal: assert (BUNDLE_DIR / target).exists(), f"index links to missing {target}" def test_verdict_seed_encodes_realization_gap() -> None: """The seed verdict encodes a realization gap (RR < 1), and the golden learning-surface is internally consistent (expected_actual = RR x modelled). This is the anchor the later step-1 ExpeL wiring is made load-bearing against.""" fm = _parse_frontmatter(BUNDLE_DIR / "verdict-led-fro.md") rr = float(fm["realization_rate"]) assert 0.0 < rr < 1.0, "a realization gap means RR strictly below 1" ls = _golden()["learning_surface"] assert ls["realization_rate"] == pytest.approx(rr) assert ls["expected_actual_saving_nok"] == pytest.approx( ls["realization_rate"] * ls["modelled_saving_nok"] )