From 4c0a907a54828606bea414264f12e0bd0b5c013d Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 3 Jun 2026 09:36:53 +0000 Subject: [PATCH] test(modelling): Elmhurst before/after cascade pin for cavity wall (#1154) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #1154 — the Package Scorer's Elmhurst cascade pin. Drives recommend_cavity_wall on the parsed `before` Summary, scores its Option's overlay through PackageScorer, and asserts delta 0 (abs<=1e-4 on SAP/CO2/PE) vs the calculator's score on the re-lodged `after` Summary. Key finding: the handover's stated parser gate (parse_site_notes_pdf throwing 'Manufacturer' on cert 001431) does NOT block these pins. The Elmhurst recommendation Summaries route cleanly through the same ElmhurstSiteNotesExtractor + EpcPropertyDataMapper chain the worksheet e2e fixtures use (_elmhurst_worksheet_001431.build_epc). The Textract path's window bug is unrelated and unused here. The before→after field change is exactly wall_insulation_type 4 (uninsulated) → 2 (filled cavity), which is precisely the overlay recommend_cavity_wall emits; the cascade closes at delta 0.000000 on all three metrics. Before/after Summaries mirrored into tests/domain/modelling/fixtures/ so the pin does not depend on the unstaged workspace. Co-Authored-By: Claude Opus 4.8 --- .../modelling/_elmhurst_recommendation.py | 76 ++++++++++++++++ .../fixtures/cavity_wall_001431_after.pdf | Bin 0 -> 66031 bytes .../fixtures/cavity_wall_001431_before.pdf | Bin 0 -> 66966 bytes .../modelling/test_elmhurst_cascade_pins.py | 81 ++++++++++++++++++ 4 files changed, 157 insertions(+) create mode 100644 tests/domain/modelling/_elmhurst_recommendation.py create mode 100644 tests/domain/modelling/fixtures/cavity_wall_001431_after.pdf create mode 100644 tests/domain/modelling/fixtures/cavity_wall_001431_before.pdf create mode 100644 tests/domain/modelling/test_elmhurst_cascade_pins.py diff --git a/tests/domain/modelling/_elmhurst_recommendation.py b/tests/domain/modelling/_elmhurst_recommendation.py new file mode 100644 index 00000000..9797f144 --- /dev/null +++ b/tests/domain/modelling/_elmhurst_recommendation.py @@ -0,0 +1,76 @@ +"""Parse an Elmhurst *recommendation* Summary PDF into an EpcPropertyData. + +The Modelling cascade pins use Elmhurst's own before/after measure +re-lodgements as deterministic test vectors: each measure folder under +`sap worksheets/Recommendations Elmhurst Files/` holds a `before` Summary +(the baseline cert) and an `after` Summary (the same cert re-lodged with the +measure applied). Applying the matching Recommendation Generator's overlay to +the parsed `before` must reproduce the calculator's score on the parsed +`after` at delta 0 — proving the overlay is the exact field change Elmhurst +made. + +This routes the Summary PDF through the same extractor + mapper chain the +worksheet e2e fixtures use (`_elmhurst_worksheet_001431.build_epc`), NOT the +Textract `parse_site_notes_pdf` path — that path has an unrelated window +extraction bug on cert 001431. The before/after Summaries are mirrored into +`tests/domain/modelling/fixtures/` so the pins do not depend on the unstaged +workspace. +""" + +from __future__ import annotations + +import re +import subprocess +from pathlib import Path +from typing import Final + +from backend.documents_parser.elmhurst_extractor import ElmhurstSiteNotesExtractor +from datatypes.epc.domain.epc_property_data import EpcPropertyData +from datatypes.epc.domain.mapper import EpcPropertyDataMapper + +_FIXTURES_DIR: Final[Path] = Path(__file__).resolve().parent / "fixtures" + + +def _summary_pdf_to_textract_style_pages(pdf_path: Path) -> list[str]: + """Convert a Summary PDF into the per-page text format the + `ElmhurstSiteNotesExtractor` expects (label\\nvalue sequences). + + Mirror of the helper in `_elmhurst_worksheet_001431.py`: `pdftotext + -layout` preserves the spatial label/value pairing on each line; we split + on 2+ spaces to surface the tokens, then rejoin newline-delimited. + """ + info: str = subprocess.run( + ["pdfinfo", str(pdf_path)], capture_output=True, text=True, check=True, + ).stdout + match = re.search(r"Pages:\s+(\d+)", info) + if match is None: + raise RuntimeError(f"Could not parse page count from {pdf_path}") + page_count = int(match.group(1)) + + pages: list[str] = [] + for i in range(1, page_count + 1): + layout: str = subprocess.run( + [ + "pdftotext", "-layout", "-f", str(i), "-l", str(i), + str(pdf_path), "-", + ], + capture_output=True, text=True, check=True, + ).stdout + tokens: list[str] = [] + for line in layout.splitlines(): + if not line.strip(): + tokens.append("") + continue + parts = [p for p in re.split(r"\s{2,}", line.strip()) if p] + tokens.extend(parts) + pages.append("\n".join(tokens)) + return pages + + +def parse_recommendation_summary(fixture_name: str) -> EpcPropertyData: + """Parse a before/after recommendation Summary fixture (by file name in + `tests/domain/modelling/fixtures/`) into an EpcPropertyData.""" + pdf_path: Path = _FIXTURES_DIR / fixture_name + pages: list[str] = _summary_pdf_to_textract_style_pages(pdf_path) + site_notes = ElmhurstSiteNotesExtractor(pages).extract() + return EpcPropertyDataMapper.from_elmhurst_site_notes(site_notes) diff --git a/tests/domain/modelling/fixtures/cavity_wall_001431_after.pdf b/tests/domain/modelling/fixtures/cavity_wall_001431_after.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e42637453085f0569ab288ff699016cb7e3a5060 GIT binary patch literal 66031 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%0DSk7(8S5Z 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�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 Product: + return Product( + measure_type=measure_type, unit_cost_per_m2=1.0, contingency_rate=0.0 + ) + + +def _assert_overlay_reproduces_after( + before: EpcPropertyData, after: EpcPropertyData, overlay: EpcSimulation +) -> None: + """Score ``overlay`` on ``before`` and assert it matches the calculator's + score on the re-lodged ``after`` across all three metrics.""" + calculator = Sap10Calculator() + relodged: SapResult = calculator.calculate(after) + scored: Score = PackageScorer(calculator).score(before, [overlay]) + + assert abs(scored.sap_continuous - relodged.sap_score_continuous) <= _PIN_ABS + assert abs(scored.co2_kg_per_yr - relodged.co2_kg_per_yr) <= _PIN_ABS + assert ( + abs(scored.primary_energy_kwh_per_yr - relodged.primary_energy_kwh_per_yr) + <= _PIN_ABS + ) + + +def test_cavity_wall_overlay_reproduces_the_relodged_after() -> None: + # Arrange + before: EpcPropertyData = parse_recommendation_summary( + "cavity_wall_001431_before.pdf" + ) + after: EpcPropertyData = parse_recommendation_summary( + "cavity_wall_001431_after.pdf" + ) + recommendation: Recommendation | None = recommend_cavity_wall( + before, _AnyProduct() + ) + assert recommendation is not None + + # Act / Assert + _assert_overlay_reproduces_after( + before, after, recommendation.options[0].overlay + )