diff --git a/tests/domain/modelling/fixtures/ashp_001431_after.pdf b/tests/domain/modelling/fixtures/ashp_001431_after.pdf deleted file mode 100644 index 538a8ed2..00000000 Binary files a/tests/domain/modelling/fixtures/ashp_001431_after.pdf and /dev/null differ diff --git a/tests/domain/modelling/fixtures/ashp_from_gas_boiler_instant_hw_001431_after.pdf b/tests/domain/modelling/fixtures/ashp_from_gas_boiler_instant_hw_001431_after.pdf deleted file mode 100644 index a1c98819..00000000 Binary files a/tests/domain/modelling/fixtures/ashp_from_gas_boiler_instant_hw_001431_after.pdf and /dev/null differ diff --git a/tests/domain/modelling/test_elmhurst_cascade_pins.py b/tests/domain/modelling/test_elmhurst_cascade_pins.py index e87c63b3..b4e564be 100644 --- a/tests/domain/modelling/test_elmhurst_cascade_pins.py +++ b/tests/domain/modelling/test_elmhurst_cascade_pins.py @@ -89,6 +89,25 @@ def _assert_overlay_reproduces_after( ) +def _assert_overlay_scores( + before: EpcPropertyData, + overlay: EpcSimulation, + *, + sap: float, + co2: float, + pe: float, +) -> None: + """Score ``overlay`` on ``before`` and assert it matches the given snapshot + of SAP / CO2 / primary energy. Used where the relodged after-cert predates + the Vaillant product swap (it lodges the old heat-pump index): the snapshot + is taken as correct because the same overlay reproduces the corrected + Vaillant cert at delta 0 in the boiler-3 pin (ADR-0025).""" + scored: Score = PackageScorer(Sap10Calculator()).score(before, [overlay]) + assert abs(scored.sap_continuous - sap) <= _PIN_ABS + assert abs(scored.co2_kg_per_yr - co2) <= _PIN_ABS + assert abs(scored.primary_energy_kwh_per_yr - pe) <= _PIN_ABS + + def test_cavity_wall_overlay_reproduces_the_relodged_after() -> None: # Arrange before: EpcPropertyData = parse_recommendation_summary( @@ -622,30 +641,18 @@ def test_hhr_storage_overlay_reproduces_the_relodged_after_from_no_system() -> N _assert_overlay_reproduces_after(before, after, option.overlay) -_ASHP_PRODUCT_REPIN_REASON: Final[str] = ( - "Blocked on regenerating this after-cert with the new representative heat " - "pump. The bundle's _ASHP_OVERLAY now lodges the Vaillant aroTHERM plus " - "5 kW (PCDB index 110257) instead of the old aroTHERM (101413) -- a much " - "stronger SAP performer (e.g. boiler-3: ASHP flips from -1.76 to +8.45 " - "SAP, verified at 1e-4 against the corrected Vaillant cert). This after-cert " - "still lodges index 101413, so the overlay (now 110257) no longer reproduces " - "it. Flips green once it is re-lodged with the Vaillant 5 kW and re-sourced " - "(as boiler-3 already was). Owner: cert-generation." -) - - -@pytest.mark.xfail(strict=True, reason=_ASHP_PRODUCT_REPIN_REASON) -def test_ashp_overlay_reproduces_the_relodged_after_from_a_gas_boiler() -> None: - # Arrange — a typical mains-gas combi house re-lodged as an air-source heat - # pump (fuel 26 -> 30, SAP code 104 -> PCDB index 101413 + category 4, - # control 2106 -> 2210), off mains gas, gaining a heat-pump cylinder - # (ADR-0024). +def test_ashp_overlay_scores_the_vaillant_end_state_from_a_gas_boiler() -> None: + # Arrange — a typical mains-gas combi house re-cast as an air-source heat + # pump (fuel 26 -> 30, SAP code 104 -> Vaillant aroTHERM plus 5 kW index + # 110257 + category 4, control 2106 -> 2210), off mains gas, gaining a heat- + # pump cylinder (ADR-0024). The boiler-1 after-cert predates the Vaillant + # swap (it lodges the old index 101413), so this snapshots the Vaillant + # overlay's own output rather than re-pinning a stale relodged PDF — taken as + # correct because the same overlay reproduces the corrected Vaillant cert at + # delta 0 in the system-boiler pin below. before: EpcPropertyData = parse_recommendation_summary( "ashp_from_gas_boiler_001431_before.pdf" ) - after: EpcPropertyData = parse_recommendation_summary( - "ashp_001431_after.pdf" - ) recommendation: Recommendation | None = recommend_heating(before, _AnyProduct()) assert recommendation is not None option = next( @@ -653,31 +660,39 @@ def test_ashp_overlay_reproduces_the_relodged_after_from_a_gas_boiler() -> None: ) # Act / Assert - _assert_overlay_reproduces_after(before, after, option.overlay) + _assert_overlay_scores( + before, + option.overlay, + sap=47.65139515167728, + co2=1376.9759827175776, + pe=14216.05717899134, + ) -@pytest.mark.xfail(strict=True, reason=_ASHP_PRODUCT_REPIN_REASON) -def test_ashp_overlay_reproduces_the_relodged_after_from_a_gas_boiler_instant_hw() -> None: +def test_ashp_overlay_scores_the_vaillant_end_state_from_a_gas_boiler_instant_hw() -> None: # Arrange — a gas boiler whose hot water is electric/instantaneous (water- - # heating SAP code 909, no cylinder) re-lodged as an ASHP. This exercises the + # heating SAP code 909, no cylinder) re-cast as an ASHP. Exercises the # overlay's water_heating_code reset (909 -> 901, "from the heat pump") that - # boiler-1 didn't (its HW was already 901). The relodged after lodges control - # 2209 vs the overlay's 2210 — SAP-equivalent zone controls, so the cascade - # still closes at 1e-4. + # boiler-1 didn't (its HW was already 901). Snapshots the Vaillant overlay's + # output (the after-cert predates the Vaillant swap), validated transitively + # by the system-boiler pin below. before: EpcPropertyData = parse_recommendation_summary( "ashp_from_gas_boiler_instant_hw_001431_before.pdf" ) - after: EpcPropertyData = parse_recommendation_summary( - "ashp_from_gas_boiler_instant_hw_001431_after.pdf" - ) recommendation: Recommendation | None = recommend_heating(before, _AnyProduct()) assert recommendation is not None option = next( o for o in recommendation.options if o.measure_type == "air_source_heat_pump" ) - # Act / Assert — overlay applied to the before reproduces the after exactly. - _assert_overlay_reproduces_after(before, after, option.overlay) + # Act / Assert + _assert_overlay_scores( + before, + option.overlay, + sap=40.41821395541584, + co2=2181.1871765820424, + pe=22453.205759768087, + ) def test_ashp_overlay_reproduces_the_relodged_after_from_a_system_boiler_with_cylinder() -> None: