Model/tests/scripts/test_expired_prediction_pairs_harness.py
Khalim Conn-Kowlessar d9576db429 Pairs harness: score plain vs historic-conditioned prediction per attribute 🟩
Finds pre-2012 (S3 backup) x SAP-10.2 (new API) cert pairs per postcode,
predicts each from its leave-one-out cohort with and without ADR-0054
conditioning, and reports compare_prediction hit rates side by side.
Evidence for the stable-attribute whitelist, not a CI gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 08:46:16 +00:00

78 lines
2.4 KiB
Python

"""Pure pair-selection and aggregation logic of the ADR-0054 pairs harness."""
from __future__ import annotations
import dataclasses
from datatypes.epc.domain.historic_epc import HistoricEpc
from domain.epc_prediction.prediction_comparison import PredictionComparison
from scripts.expired_prediction_pairs_harness import (
aggregate,
format_report,
latest_pre_2012_by_uprn,
)
def _hist(uprn: str, lodgement_date: str) -> HistoricEpc:
fields = {f.name: "" for f in dataclasses.fields(HistoricEpc)}
fields["uprn"] = uprn
fields["lodgement_date"] = lodgement_date
return HistoricEpc(**fields)
def _comparison(hits: dict[str, bool | None]) -> PredictionComparison:
return PredictionComparison(
categorical_hits=hits,
floor_area_residual=-4.0,
building_parts_residual=0,
window_count_residual=0,
total_window_area_residual=0.0,
door_count_residual=0,
)
def test_pairs_keep_only_the_latest_pre_2012_cert_per_uprn():
# Arrange — one UPRN lodged twice pre-2012, once post-2012; one UPRN-less row.
records = [
_hist("100", "2008-05-01"),
_hist("100", "2010-11-30"),
_hist("100", "2013-01-01"),
_hist("", "2009-01-01"),
]
# Act
by_uprn = latest_pre_2012_by_uprn(records)
# Assert — the 2010 cert wins; the 2013 one can never seed an expired pair.
assert set(by_uprn) == {"100"}
assert by_uprn["100"].lodgement_date == "2010-11-30"
def test_aggregate_counts_hits_and_skips_not_applicable():
# Arrange — two comparisons; wall scored twice (1 hit), roof scored once
# (None means the actual lodged no value — out of the denominator).
comparisons = [
_comparison({"wall_construction": True, "roof_construction": None}),
_comparison({"wall_construction": False, "roof_construction": True}),
]
# Act
scores = aggregate(comparisons)
# Assert
assert scores.hits["wall_construction"] == (1, 2)
assert scores.hits["roof_construction"] == (1, 1)
assert scores.floor_area_abs_residuals == [4.0, 4.0]
def test_report_prints_both_arms_side_by_side():
# Arrange
plain = aggregate([_comparison({"wall_construction": False})])
conditioned = aggregate([_comparison({"wall_construction": True})])
# Act
report = format_report(plain, conditioned, pairs=1)
# Assert
assert "| wall_construction | 0/1 | 1/1 |" in report
assert "1 pairs" in report