Persist no Lodged Performance for a predicted Property 🟥

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-06-30 22:07:27 +00:00
parent 7ecb7eebd1
commit 5d63118d5a

View file

@ -1,6 +1,6 @@
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING from typing import Optional, TYPE_CHECKING
import pytest import pytest
@ -244,6 +244,80 @@ def test_run_raises_when_no_rhi_and_no_scored_result() -> None:
assert uow.commits == 0 assert uow.commits == 0
class _PredictedRebaseliner(Rebaseliner):
"""Scores a predicted picture into a fixed Effective Performance, ignoring the
(absent) lodged half a predicted Property always has ``physical_state_changed``,
so the calculator output IS the Effective Performance (ADR-0039)."""
def __init__(self, effective: Performance, result: SapResult) -> None:
self._effective = effective
self._result = result
def rebaseline(
self,
property_id: int,
effective_epc: EpcPropertyData,
lodged: Optional[Performance],
*,
physical_state_changed: bool = False,
) -> RebaselineResult:
return RebaselineResult(
effective=self._effective,
reason="physical_state_changed",
sap_result=self._result,
)
def _predicted_property() -> Property:
"""A predicted Property (ADR-0031): no lodged EPC, only a neighbour-synthesised
predicted EPC whose recorded performance fields are a *different dwelling's* —
the phantom Lodged Performance this fix must not propagate. Mirrors the #1361
exemplar (uprn 34003067 / property 742072), predicted-only."""
predicted = object.__new__(EpcPropertyData)
predicted.energy_rating_current = 14 # phantom: copied from a neighbour template
predicted.current_energy_efficiency_band = Epc.G
predicted.co2_emissions_current = 5.0
predicted.energy_consumption_current = 400
predicted.sap_version = 10.2
predicted.renewable_heat_incentive = None
return Property(
identity=PropertyIdentity(
portfolio_id=1, postcode="A0 0AA", address="1 Some Street", uprn=34003067
),
epc=None,
predicted_epc=predicted,
)
def test_run_persists_no_lodged_performance_for_a_predicted_property() -> None:
# Arrange — a predicted Property (no lodged cert); the rebaseliner scores its
# predicted picture into a known Effective Performance.
property_baseline_repo = FakePropertyBaselineRepo()
uow = FakeUnitOfWork(
property=FakePropertyRepo({742072: _predicted_property()}),
property_baseline=property_baseline_repo,
)
effective = Performance(
sap_score=57, epc_band=Epc.D, co2_emissions=1.5, primary_energy_intensity=160
)
orchestrator = PropertyBaselineOrchestrator(
unit_of_work=lambda: uow,
rebaseliner=_PredictedRebaseliner(
effective, _sap_result_with_heating(space_kwh=4200.0, water_kwh=1600.0)
),
fuel_rates=FuelRatesStaticFileRepository(),
)
# Act
orchestrator.run([742072])
# Assert — no lodged comparator was manufactured from the neighbour-synthesised
# EPC's recorded fields; the Effective half is still persisted.
(baseline, _) = property_baseline_repo.saved[0]
assert baseline.lodged is None
assert baseline.effective == effective
def test_run_derives_and_persists_a_bill_when_the_rebaseliner_scores() -> None: def test_run_derives_and_persists_a_bill_when_the_rebaseliner_scores() -> None:
# Arrange — a rebaseliner that hands back a SapResult with lighting energy, # Arrange — a rebaseliner that hands back a SapResult with lighting energy,
# so the orchestrator prices it into a Bill at the committed snapshot. # so the orchestrator prices it into a Bill at the committed snapshot.