mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice 5a: the promotion. Replaces StubRebaseliner in production and collapses the
shadow runner into the rebaseliner (ADR-0013 amendment).
- CalculatorRebaseliner runs Sap10Calculator on every Property:
* sap_version < 10.2 -> Effective Performance IS the calculator output
(band via Epc.from_sap_score, CO2 kg->t, PEUI rounded), reason "pre_sap10".
* sap_version >= 10.2 -> Effective = lodged (API figures on-target), and the
calculator only logs divergence (SAP>0.5, PEUI/CO2 1%) as a validation signal.
* a calculator raise propagates -> batch aborts (ADR-0012); fix the cert at once.
- Rebaseliner.rebaseline gains property_id (for the divergence log).
- LoggingCalculatorShadow / the calculator_shadow seam removed from the
orchestrator; its divergence-comparison logic now lives in the rebaseliner.
- StubRebaseliner kept (signature updated) for orchestrator/repo unit tests.
The SapResult->EnergyBreakdown adapter + BillDerivation wiring (to populate the
bill block) follow once the appliances/cooking SapResult fields land.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
92 lines
3.1 KiB
Python
92 lines
3.1 KiB
Python
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from datatypes.epc.domain.epc import Epc
|
|
from datatypes.epc.domain.epc_property_data import (
|
|
EpcPropertyData,
|
|
RenewableHeatIncentive,
|
|
)
|
|
from domain.property_baseline.property_baseline_performance import PropertyBaselinePerformance
|
|
from domain.property_baseline.performance import Performance
|
|
from domain.property_baseline.rebaseliner import RebaselineNotImplemented, StubRebaseliner
|
|
from domain.property.property import Property, PropertyIdentity
|
|
from orchestration.property_baseline_orchestrator import PropertyBaselineOrchestrator
|
|
from tests.orchestration.fakes import (
|
|
FakePropertyBaselineRepo,
|
|
FakePropertyRepo,
|
|
FakeUnitOfWork,
|
|
)
|
|
|
|
|
|
def _property(*, sap_version: float) -> Property:
|
|
epc = object.__new__(EpcPropertyData)
|
|
epc.energy_rating_current = 72
|
|
epc.current_energy_efficiency_band = Epc.C
|
|
epc.co2_emissions_current = 1.8
|
|
epc.energy_consumption_current = 180
|
|
epc.sap_version = sap_version
|
|
epc.renewable_heat_incentive = RenewableHeatIncentive(
|
|
space_heating_kwh=5000.0, water_heating_kwh=2000.0
|
|
)
|
|
return Property(
|
|
identity=PropertyIdentity(
|
|
portfolio_id=1, postcode="A0 0AA", address="1 Some Street", uprn=123
|
|
),
|
|
epc=epc,
|
|
)
|
|
|
|
|
|
def test_run_establishes_persists_and_commits_the_batch_once() -> None:
|
|
# Arrange
|
|
property_baseline_repo = FakePropertyBaselineRepo()
|
|
uow = FakeUnitOfWork(
|
|
property=FakePropertyRepo({10: _property(sap_version=10.2)}),
|
|
property_baseline=property_baseline_repo,
|
|
)
|
|
orchestrator = PropertyBaselineOrchestrator(
|
|
unit_of_work=lambda: uow,
|
|
rebaseliner=StubRebaseliner(),
|
|
)
|
|
|
|
# Act
|
|
orchestrator.run([10])
|
|
|
|
# Assert — one Baseline Performance persisted (both halves equal, kWh off the
|
|
# RHI), and the batch committed exactly once.
|
|
lodged = Performance(
|
|
sap_score=72, epc_band=Epc.C, co2_emissions=1.8, primary_energy_intensity=180
|
|
)
|
|
assert property_baseline_repo.saved == [
|
|
(
|
|
PropertyBaselinePerformance(
|
|
lodged=lodged,
|
|
effective=lodged,
|
|
rebaseline_reason="none",
|
|
space_heating_kwh=5000.0,
|
|
water_heating_kwh=2000.0,
|
|
),
|
|
10,
|
|
)
|
|
]
|
|
assert uow.commits == 1
|
|
|
|
|
|
def test_run_raises_on_a_pre_sap10_property_and_does_not_commit() -> None:
|
|
# Arrange — a pre-SAP10 cert needs ML rebaselining, which is not wired yet.
|
|
property_baseline_repo = FakePropertyBaselineRepo()
|
|
uow = FakeUnitOfWork(
|
|
property=FakePropertyRepo({10: _property(sap_version=9.94)}),
|
|
property_baseline=property_baseline_repo,
|
|
)
|
|
orchestrator = PropertyBaselineOrchestrator(
|
|
unit_of_work=lambda: uow,
|
|
rebaseliner=StubRebaseliner(),
|
|
)
|
|
|
|
# Act / Assert — the raise propagates; the batch is neither persisted nor
|
|
# committed (all-or-nothing).
|
|
with pytest.raises(RebaselineNotImplemented):
|
|
orchestrator.run([10])
|
|
assert property_baseline_repo.saved == []
|
|
assert uow.commits == 0
|