From 3d108a9d9e64c8b74e3e042c5ca12f706b2e9f6f Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 10 Jun 2026 08:44:37 +0000 Subject: [PATCH] feat(harness): explain gas_boiler_upgrade in the report triggers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the `gas_boiler_upgrade` branch to `report._triggers_for`, mirroring the generator's eligibility guard so a cohort report explains why the boiler upgrade fired: the wet-boiler SAP code, the mains-gas connection that makes the gas end-state installable, and the cylinder presence that shapes the bundle (combi vs regular + cylinder fixes). No golden API cert selects the boiler upgrade (it competes with — and on houses loses to — the ASHP bundle within the one heating Recommendation), so the branch is covered by a direct `_triggers_for` unit test, following the repo pattern for testing internal helpers (cert_to_inputs). Co-Authored-By: Claude Opus 4.8 --- harness/report.py | 11 +++++++++++ tests/harness/test_report.py | 26 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/harness/report.py b/harness/report.py index c93f0d02..002cbd22 100644 --- a/harness/report.py +++ b/harness/report.py @@ -153,6 +153,17 @@ def _triggers_for(epc: EpcPropertyData, measure_type: str) -> dict[str, Any]: epc.sap_heating.main_heating_details[0].main_heating_category ), } + if measure_type == "gas_boiler_upgrade": + # heating_recommendation.py offers a gas condensing boiler to a dwelling + # with an existing (non-electric) wet boiler and a mains-gas connection; + # the cylinder presence shapes it (combi vs regular + cylinder fixes). + return { + "sap_main_heating_code": ( + epc.sap_heating.main_heating_details[0].sap_main_heating_code + ), + "mains_gas": epc.sap_energy_source.mains_gas, + "has_hot_water_cylinder": epc.has_hot_water_cylinder, + } return {} diff --git a/tests/harness/test_report.py b/tests/harness/test_report.py index 4357b4f7..1dcf9123 100644 --- a/tests/harness/test_report.py +++ b/tests/harness/test_report.py @@ -15,6 +15,9 @@ from harness.report import ( format_report_markdown, parity_report_for, ) +from tests.domain.modelling._elmhurst_recommendation import ( + parse_recommendation_summary, +) _GOLDEN = ( Path(__file__).resolve().parents[1] @@ -99,6 +102,29 @@ def test_each_fired_measure_carries_the_attributes_that_triggered_it() -> None: } +def test_gas_boiler_upgrade_surfaces_its_eligibility_triggers() -> None: + # No golden API cert selects the boiler upgrade (it competes with — and on + # houses loses to — the ASHP bundle within the one heating Recommendation), + # so the trigger branch is exercised directly, like the cert_to_inputs unit + # tests of internal helpers. + from harness.report import _triggers_for # pyright: ignore[reportPrivateUsage] + + # Arrange — a mains-gas wet boiler (SAP code 114) with a hot-water cylinder: + # the boiler-upgrade eligibility attributes the report should explain. + epc = parse_recommendation_summary("boiler_cyl_gas_001431_before.pdf") + + # Act + triggers = _triggers_for(epc, "gas_boiler_upgrade") + + # Assert — the wet-boiler SAP code, the mains-gas connection that makes the + # gas end-state installable, and the cylinder that shapes the bundle. + assert triggers == { + "sap_main_heating_code": 114, + "mains_gas": True, + "has_hot_water_cylinder": True, + } + + def test_few_measure_cert_surfaces_only_its_fired_measures_triggers() -> None: # Arrange path: Path = _GOLDEN / f"{_WITHIN_TOLERANCE}.json"