From 4bbcdb6a6118d31ee1b81438d981bb558c79df51 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 6 Jul 2026 08:17:07 +0000 Subject: [PATCH] =?UTF-8?q?Resolve=20a=20UPRN=20to=20its=20historic=20EPC?= =?UTF-8?q?=20record=20by=20exact=20match=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- .../historic_epc/historic_epc_resolver.py | 4 +++ .../test_historic_epc_resolver.py | 31 ++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/repositories/historic_epc/historic_epc_resolver.py b/repositories/historic_epc/historic_epc_resolver.py index 1c73efa4b..823db3c38 100644 --- a/repositories/historic_epc/historic_epc_resolver.py +++ b/repositories/historic_epc/historic_epc_resolver.py @@ -34,6 +34,10 @@ class HistoricEpcResolver: matches=matches, ) + def record_for_uprn(self, uprn: str, postcode: str) -> Optional[HistoricEpc]: + """The postcode shard's certificate for ``uprn``, or None.""" + return None + def resolve_uprn( self, user_address: str, postcode: str ) -> Optional[tuple[str, str, float]]: diff --git a/tests/repositories/historic_epc/test_historic_epc_resolver.py b/tests/repositories/historic_epc/test_historic_epc_resolver.py index 68cdb3ea5..d429d8ca1 100644 --- a/tests/repositories/historic_epc/test_historic_epc_resolver.py +++ b/tests/repositories/historic_epc/test_historic_epc_resolver.py @@ -16,10 +16,11 @@ from repositories.historic_epc.historic_epc_repository import HistoricEpcReposit from repositories.historic_epc.historic_epc_resolver import HistoricEpcResolver -def _hist(address: str, uprn: str) -> HistoricEpc: +def _hist(address: str, uprn: str, lodgement_date: str = "") -> HistoricEpc: fields = {f.name: "" for f in dataclasses.fields(HistoricEpc)} fields["address"] = address fields["uprn"] = uprn + fields["lodgement_date"] = lodgement_date return HistoricEpc(**fields) @@ -101,6 +102,34 @@ def test_resolve_uprn_is_none_on_ambiguous_tie(): assert HistoricEpcResolver(repo).resolve_uprn("47 Gordon Road", "AB33 8AL") is None +def test_record_for_uprn_returns_the_exact_uprn_match(): + # Arrange — the prediction path knows the target's UPRN; the lookup must be + # exact equality, never the fuzzy address matcher (ADR-0054). + repo = _FakeRepo( + { + "AB338AL": [ + _hist("47 GORDON ROAD", "100"), + _hist("48 GORDON ROAD", "200"), + ] + } + ) + + # Act + record = HistoricEpcResolver(repo).record_for_uprn("200", "AB33 8AL") + + # Assert + assert record is not None + assert record.address == "48 GORDON ROAD" + + +def test_record_for_uprn_is_none_when_uprn_not_in_shard(): + # Arrange + repo = _FakeRepo({"AB338AL": [_hist("47 GORDON ROAD", "100")]}) + + # Act / Assert — a miss is the normal outcome of a best-effort lookup. + assert HistoricEpcResolver(repo).record_for_uprn("999", "AB33 8AL") is None + + def test_resolve_uprn_is_none_when_all_scores_zero(): # Arrange — no candidate shares the user's building number => all hard-zero. repo = _FakeRepo(