From 00af7b5a54b972d868802b59e03746e67ca44722 Mon Sep 17 00:00:00 2001 From: Jun-te Kim Date: Tue, 23 Jun 2026 12:42:53 +0000 Subject: [PATCH] data types --- .../expand-sap-accuracy-corpus/worklist.md | 90 +++++ applications/modelling_e2e/handler.py | 37 +- .../uprn_100061905751/elmhurst_summary.pdf | Bin 0 -> 67142 bytes .../uprn_100061905751/elmhurst_worksheet.pdf | Bin 0 -> 44569 bytes .../uprn_100061905751/epc.json | 335 ++++++++++++++++++ datatypes/epc/domain/mapper.py | 21 +- .../epc/domain/tests/test_from_sap_schema.py | 30 ++ .../lambda/modelling_e2e/variables.tf | 2 +- .../epc_comparable_properties_repository.py | 55 ++- scripts/hyde/elmhurst_download.py | 2 +- .../modelling_e2e/test_handler.py | 93 +++++ ...st_epc_comparable_properties_repository.py | 63 ++++ 12 files changed, 715 insertions(+), 13 deletions(-) create mode 100644 backend/epc_api/json_samples/real_life_examples/SAP-Schema-16.3/uprn_100061905751/elmhurst_summary.pdf create mode 100644 backend/epc_api/json_samples/real_life_examples/SAP-Schema-16.3/uprn_100061905751/elmhurst_worksheet.pdf create mode 100644 backend/epc_api/json_samples/real_life_examples/SAP-Schema-16.3/uprn_100061905751/epc.json diff --git a/.claude/skills/expand-sap-accuracy-corpus/worklist.md b/.claude/skills/expand-sap-accuracy-corpus/worklist.md index 3825927b..e5c6b8fa 100644 --- a/.claude/skills/expand-sap-accuracy-corpus/worklist.md +++ b/.claude/skills/expand-sap-accuracy-corpus/worklist.md @@ -11,12 +11,102 @@ large, or a new/complex build pattern needed; NEEDS INVESTIGATION. 2020 new-build flat) β€” full loop proven: eng 77 / elm 78, engine-on-Elmhurst- inputs 79 (calculator faithful within ~1). Use it to sanity-check the pipeline. +# Files saving instructions +I've noticed we arn't saving the epc.json (from epc api), input summary and worksheets from elmhurst. We shuold be doing that so we can reproduce behaviours quicker and verify. This is important as other memebers of team can help improve the verification. Files should be saved on backend/epc_api/json_samples/real_life_examples//uprn_/ + + ## Do next β€” new schemas (need a mapper) These two were flagged NOT MAPPABLE in the UI (red βœ—). Mapper coverage now ADDED (dedicated per-schema methods in `EpcPropertyDataMapper`; corpus gauge green, 0 new pyright errors). Elmhurst build + pin still pending β€” run the normal loop. +### πŸ”§πŸ” FOR KHALIM β€” 100061905751 (cert 2628-3046-6233-4584-2970, SAP-16.3) β€” mapper fix landed, Elmhurst +5 to review +Surfaced as a PRODUCTION crash (NOT in The 100): `modelling_e2e` property 730259 +`predict_epc` β†’ `EpcComparablePropertiesRepository.candidates_for(postcode)` maps +EVERY cohort cert in one list comprehension, and THIS cert raised +`ValueError: RdSapSchema17_1: missing required field 'insulated_door_count'`, +aborting the whole prediction. πŸ”§ FIXED generically in `_normalize_sap_schema_16_x` +(`mapper.py`): `setdefault("insulated_door_count", 0)` β€” door refinement, absent β†’ +"no insulated doors recorded" β†’ 0 (conservative RdSAP). +regression test +`test_16_x_missing_insulated_door_count_defaults_to_zero` (test_from_sap_schema.py); +0 new pyright errors; real-cert accuracy + 16.x suites green. +Cert: END-TERRACE HOUSE 2-storey, band A pre-1900, cavity wall AS-BUILT **no +insulation** (U0.70), pitched 100mm loft, suspended uninsulated floor, mains-gas +COMBI (PCDB 16366 Glow-worm Ultracom 2 35cxi), control 2106 CBE, double glazed, +**2 OPEN FIREPLACES** (chimneys), lodged **secondary** open-fire smokeless fuel +(SAP 631 = Elmhurst RKJ), 3.84mΒ² band-B extension, natural vent, 17% LED, TFA 139. +**eng 57 = lodged 57 EXACTLY** / elm worksheet 52 (+5). Built in Elmhurst end-to-end +(boiler 16366, CBE/2106, 2 open chimneys, secondary RKJ open-fire-in-grate, window +20.57mΒ², party wall geometry GF 6.31/1F 5.14 CF). engine-on-Elmhurst-inputs 53 β‰ˆ +worksheet 52 β†’ **calculator faithful**. The +5 decomposes as: ~2 SAP = the documented +16.x reduced-field **party-wall gap** (lodges no party_wall_length β†’ engine models +NONE; Elmhurst forces `Party walls Main 31.02mΒ² Γ— U0.250 = 7.76 W/K`), SCALED UP by +2-storey geometry (party wall area ~31mΒ² vs ~16mΒ² on the single-storey 16.2 pins +100021985993/100090182288 which showed only +2); remainder ~2-3 = reduced-field +build choices (3.84mΒ² extension folded into GF, wall thickness 250 vs lodged 300, +draughtproofing default). build_100061905751.py complete. **NOT yet pinned** β€” to +review with Khalim (his call per CONTEXT.md): pin engine=lodged 57 like other 16.x, +and/or whether 16.x end-terrace should model a party wall to close the reduced-field +gap. Sample saved under SAP-Schema-16.3/uprn_100061905751 (epc.json + both PDFs). + +### πŸ”§πŸ” modelling_e2e production failure sweep (2026-06-23) β€” cohort resilience + mapper gaps +Investigated the 45 FAILED `modelling_e2e` subtasks (DevAssessmentModelDB, portfolio +796) β€” 36 property rows, ~25 unique UPRNs. Root cause for most: `predict_epc` β†’ +`EpcComparablePropertiesRepository.candidates_for(postcode)` mapped EVERY cohort cert +in one comprehension, so ONE unmappable cohort cert aborted the whole prediction. + +**βœ… DONE β€” cohort resilience (skip + report)** so a single bad cert can't sink a +prediction, and the skipped certs surface for follow-up: +- `candidates_for` now skips certs that raise `ValueError` (mapper failures: + missing-field + `UnmappedApiCode`/`UnmappedElmhurstLabel`, both `ValueError`), + recording `SkippedCohortCert(certificate_number, error)` on `repo.skipped` + a + `logger.warning`. Transient API errors (not `ValueError`) still propagate. +- handler surfaces them in the subtask **outputs** (success β†’ `outputs.result. + skipped_unmappable_cohort_certs`; failure β†’ appended to the error message), with + cert numbers, so the gaps can be closed deliberately. +3 tests; 0 new pyright. + Live-verified on BN11 4EP: cohort now builds 35 + records the 1 skip. + +**βœ… DONE β€” 2 safe generic mapper fixes (+regression tests, 0 new pyright):** +- `_normalize_sap_schema_16_x`: `setdefault("insulated_door_count", 0)` (the + original prod crash) AND `setdefault("multiple_glazed_proportion", 100)` (16.3 + cert 0418-3986-7250-2884-7970; ML-only field the SAP calc ignores; modal 100). +- `_with_recorded_performance` co2/consumption/rating: `float(co2)` β†’ crashed on + certs lodging `co2_emissions_current` as a Measurement dict `{'value':3.5, + 'quantity':'tonnes per year'}` (16.x cert 2308-4997-7262-0137-9930, surfaced as + `TypeError: float() argument must be ... not 'dict'`). Now coerced via + `_measurement_value` (handles Measurement/dict/number). Verified maps β†’ 3.5. + +**βš–οΈ FOR KHALIM β€” uncovered mapper gaps (mapper is your domain per CONTEXT.md):** +- **`built_form` missing (SAP-16.0)** β€” cert 8742-6624-9300-2780-4926 (uprn + 10070004512); has `property_type` but no `built_form`. Defaulting it drives + party-wall/exposed-perimeter modelling β†’ a real modelling decision, not a neutral + default. Blocks props 710339, 723589. +- **`window` missing + genuinely sparse (SAP-16.2)** β€” cert 8257-7539-1649-0633-4992 + (uprn 10070009758); `windows` is a DICT not list, AND it omits `door_count`, + `habitable_room_count`, `glazed_area` β€” fail-loud is likely correct (data + insufficient). Blocks props 733315, 730259. +- **πŸ” RdSAP-21.0.0 systematically lacks the ADR-0028 Optional widenings 21.0.1 got.** + Cert 3135-3223-5500-0919-2206 (uprn 100021919725) omits 13 top-level fields + (`wet_rooms_count`, `open_chimneys_count`, `mechanical_ventilation_index_number`, + `led/cfl_fixed_lighting_bulbs_count`, the `mechanical_vent_duct_*`, + `insulated_door_u_value`, `pressure_test_certificate_number`, + `windows_transmission_details`) + `SapWindow` (`pvc_frame`/`glazing_gap`/ + `frame_factor`/`window_transmission_details`) β€” ALL required in 21.0.0 but + `Optional[...] = None` in 21.0.1. NOT applied: widening risks pushing `None` into + `from_rdsap_schema_21_0_0` which may assume non-None (needs mapper-coalescing + review). Recommend aligning RdSapSchema21_0_0 to 21.0.1 (incl. the same Optionals + on insulated_door_count etc.) + reviewing the 21.0.0 mapper. Blocks prop 719897. + (The resilience change already stops all of these from crashing prod.) + +Caveat: ~13 other failed props showed no mapper gap on replay β€” genuinely +not-predictable (empty/insufficient cohort) or already fixed by the +`insulated_door_count` default; cohort replay only checked the first 60 certs/postcode +and skipped rate-limited fetches, so a deeper gap could be missed. + +**Also done:** `deployment/terraform/lambda/modelling_e2e/variables.tf` +`maximum_concurrency` default 2 β†’ 4 (per request). + - [x] πŸ”§ 10096028301 β€” SAP-Schema-19.1.0 (full-SAP g/f FLAT, band M, combi PCDB 17929, MEV, AP50 3.5) Β· eng 82 / elm 82 (lodged 85) Β· PINNED engine 82. πŸ”§ mapper added: `from_sap_schema_19_1_0`. Built in Elmhurst (boiler 17929 via search, control CBE/2106, water from primary, MEV on, AP50 Blower Door 3.5+cert). Engine EXACTLY matches Elmhurst worksheet (82.11 vs 82); engine-on-Elmhurst-inputs 82.16 β‰ˆ 82 β†’ calculator faithful. βˆ’3 vs lodged = measured-U-vs-RdSAP-default + MEV extract-not-recovery (documented). No mapper change beyond coverage. - [x] πŸ”§ 100021943298 β€” SAP-Schema-16.1 (g/f FLAT, band B, solid-brick internal, combi PCDB 10328) Β· eng 76 / elm 75 (lodged 72) Β· PINNED engine 76. πŸ”§ mapper added: `from_sap_schema_16_1`. Built in Elmhurst (boiler 10328 via search, control CBE/2106, water from primary, wall insulation thickness Unknown); worksheet 75 β†’ engine within ~1 (tightest agreement, reduced-field). Boiler-select + water-heating + control dialogs all driven via automation (two-step rowβ†’Select / cascade + coordinate-OK). No mapper change beyond coverage. diff --git a/applications/modelling_e2e/handler.py b/applications/modelling_e2e/handler.py index de7b5542..86b5ad5f 100644 --- a/applications/modelling_e2e/handler.py +++ b/applications/modelling_e2e/handler.py @@ -61,6 +61,7 @@ from applications.modelling_e2e.modelling_e2e_trigger_body import ( ) from repositories.comparable_properties.epc_comparable_properties_repository import ( EpcComparablePropertiesRepository, + SkippedCohortCert, ) from repositories.geospatial.geospatial_s3_repository import ( GeospatialS3Repository, @@ -131,6 +132,20 @@ def _solar_insights_for( return None +def _dedupe_skipped( + skipped: list[SkippedCohortCert], +) -> list[SkippedCohortCert]: + """First occurrence of each skipped cert number (the same cert can appear in + more than one postcode cohort across a batch).""" + seen: set[str] = set() + unique: list[SkippedCohortCert] = [] + for cert in skipped: + if cert.certificate_number not in seen: + seen.add(cert.certificate_number) + unique.append(cert) + return unique + + def _predict_epc( *, property_id: int, @@ -168,7 +183,7 @@ def _predict_epc( @task_handler(task_source="modelling_e2e", source=Source.PROPERTY) -def handler(body: dict[str, Any], context: Any) -> None: +def handler(body: dict[str, Any], context: Any) -> Optional[dict[str, Any]]: trigger = ModellingE2ETriggerBody.model_validate(body) property_ids = trigger.property_ids portfolio_id = trigger.portfolio_id @@ -349,7 +364,25 @@ def handler(body: dict[str, Any], context: Any) -> None: ) errors.append(property_id) + # Cohort certs the mapper could not consume were skipped (not aborted on) + # so prediction could proceed; surface them β€” with cert numbers β€” in the + # subtask outputs so the mapper gaps can be closed later. + skipped_certs: list[dict[str, str]] = [ + {"certificate_number": s.certificate_number, "error": s.error} + for s in _dedupe_skipped(comparables_repo.skipped) + ] + if skipped_certs: + logger.info( + f"skipped {len(skipped_certs)} unmappable cohort cert(s): " + f"{[s['certificate_number'] for s in skipped_certs]}" + ) + if errors: - raise RuntimeError(f"failed property_ids: {errors}") + message = f"failed property_ids: {errors}" + if skipped_certs: + message += f"; skipped_unmappable_cohort_certs: {skipped_certs}" + raise RuntimeError(message) + + return {"skipped_unmappable_cohort_certs": skipped_certs} if skipped_certs else None finally: read_session.close() diff --git a/backend/epc_api/json_samples/real_life_examples/SAP-Schema-16.3/uprn_100061905751/elmhurst_summary.pdf b/backend/epc_api/json_samples/real_life_examples/SAP-Schema-16.3/uprn_100061905751/elmhurst_summary.pdf new file mode 100644 index 0000000000000000000000000000000000000000..805c6c25357c9b3d73764a9877e59b43f14c34ef GIT binary patch literal 67142 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 Dict[str, Any]: # still fail loud β€” that is correct, the fabric data is insufficient. d.setdefault("insulated_door_count", 0) + # Some 16.x certs (e.g. 16.3 cert 0418-3986-7250-2884-7970) omit + # `multiple_glazed_proportion` while still lodging `multiple_glazing_type` β€” + # RdSapSchema17_1 requires it. It is an ML-feature field the SAP-10 calculator + # never reads (only `sap10_ml/transform`), so the value is non-load-bearing for + # the score; default the modal 100 ("fully" the lodged glazing type) to keep the + # cert mappable. Mirrors the `insulated_door_count` default above. + d.setdefault("multiple_glazed_proportion", 100) + # 16.2 lodges glazing in BOTH `multiple_glazing_type` (frequently the "ND" # not-defined sentinel) AND the windows[].description. When the numeric field # is undefined, honour an explicit "Single glazed" description so it is not diff --git a/datatypes/epc/domain/tests/test_from_sap_schema.py b/datatypes/epc/domain/tests/test_from_sap_schema.py index 7b75b84c..85f8566e 100644 --- a/datatypes/epc/domain/tests/test_from_sap_schema.py +++ b/datatypes/epc/domain/tests/test_from_sap_schema.py @@ -538,6 +538,36 @@ class TestFromSapSchema16_2: assert isinstance(epc, EpcPropertyData) assert epc.insulated_door_count == 0 + def test_16_x_missing_multiple_glazed_proportion_still_maps(self) -> None: + # Some 16.x certs (e.g. 16.3 cert 0418-3986-7250-2884-7970) lodge + # `multiple_glazing_type` but omit `multiple_glazed_proportion`, which + # RdSapSchema17_1 requires β€” previously raised "missing required field + # 'multiple_glazed_proportion'", aborting the prediction cohort. The + # normaliser defaults the modal 100 so the cert maps. (The field is an + # ML-only feature the SAP calculator never reads, and from_rdsap_schema_17_1 + # does not carry it onto EpcPropertyData β€” the point here is mappability.) + data = load("sap_16_3.json") + del data["multiple_glazed_proportion"] + assert "multiple_glazed_proportion" not in data + + epc = EpcPropertyDataMapper.from_api_response(data) + + assert isinstance(epc, EpcPropertyData) + + def test_recorded_co2_as_measurement_dict_is_coerced_not_crashed(self) -> None: + # Some certs (e.g. 16.x cert 2308-4997-7262-0137-9930) lodge + # `co2_emissions_current` as a Measurement dict {'value': 3.5, 'quantity': + # 'tonnes per year'} rather than a plain number. `_with_recorded_performance` + # previously did `float(co2)` β†’ "float() argument must be ... not 'dict'", + # crashing the whole prediction cohort. It now coerces via _measurement_value. + data = load("sap_16_3.json") + data["co2_emissions_current"] = {"value": 3.5, "quantity": "tonnes per year"} + + epc = EpcPropertyDataMapper.from_api_response(data) + + assert isinstance(epc, EpcPropertyData) + assert epc.co2_emissions_current == 3.5 + def test_16_2_normalizer_does_not_mutate_caller_dict(self) -> None: # Mirror _normalize_shower_outlets' contract: the caller's dict is # untouched (deep copy), so a re-dispatch sees the original shape. diff --git a/deployment/terraform/lambda/modelling_e2e/variables.tf b/deployment/terraform/lambda/modelling_e2e/variables.tf index 417f2780..27063494 100644 --- a/deployment/terraform/lambda/modelling_e2e/variables.tf +++ b/deployment/terraform/lambda/modelling_e2e/variables.tf @@ -26,7 +26,7 @@ variable "reserved_concurrent_executions" { variable "maximum_concurrency" { type = number - default = 2 + default = 4 description = "Maximum concurrent Lambda invocations from the SQS trigger." } diff --git a/repositories/comparable_properties/epc_comparable_properties_repository.py b/repositories/comparable_properties/epc_comparable_properties_repository.py index 3bfd92b9..e0d09e0a 100644 --- a/repositories/comparable_properties/epc_comparable_properties_repository.py +++ b/repositories/comparable_properties/epc_comparable_properties_repository.py @@ -9,6 +9,8 @@ UPRNs share a partition). Register metadata the cert itself doesn't carry from __future__ import annotations +import logging +from dataclasses import dataclass from datetime import date from typing import Optional, Protocol @@ -38,12 +40,30 @@ class CohortGeospatial(Protocol): ) -> dict[int, Coordinates]: ... +logger = logging.getLogger(__name__) + + +@dataclass(frozen=True) +class SkippedCohortCert: + """A postcode-cohort cert the mapper could not consume, so it was excluded + from the cohort rather than sinking the whole prediction. The certificate + number + error are captured so the gap surfaces (subtask outputs + logs) and + can be closed by extending the mapper later (ADR-0031).""" + + certificate_number: str + error: str + + class EpcComparablePropertiesRepository(ComparablePropertiesRepository): def __init__( self, epc_client: CohortEpcClient, geospatial: CohortGeospatial ) -> None: self._epc_client = epc_client self._geospatial = geospatial + # Cohort certs skipped because they are not yet mappable. Accumulates + # across every postcode the instance serves; the caller reads it after + # the run to report the mapper gaps (see modelling_e2e handler). + self.skipped: list[SkippedCohortCert] = [] def candidates_for(self, postcode: str) -> list[ComparableProperty]: results: list[EpcSearchResult] = self._epc_client.search_by_postcode( @@ -53,14 +73,37 @@ class EpcComparablePropertiesRepository(ComparablePropertiesRepository): coordinates: dict[int, Coordinates] = self._geospatial.coordinates_for_uprns( uprns ) - return [self._comparable(result, coordinates) for result in results] + cohort: list[ComparableProperty] = [] + for result in results: + comparable = self._comparable_or_skip(result, coordinates) + if comparable is not None: + cohort.append(comparable) + return cohort - def _comparable( + def _comparable_or_skip( self, result: EpcSearchResult, coordinates: dict[int, Coordinates] - ) -> ComparableProperty: - epc: EpcPropertyData = self._epc_client.get_by_certificate_number( - result.certificate_number - ) + ) -> Optional[ComparableProperty]: + """Map one cohort cert, or record + skip it when the mapper raises a + ``ValueError`` (missing required field / unmapped code β€” see + ``UnmappedApiCode``). One unmappable cert must NOT abort the whole cohort; + transient API errors are NOT ``ValueError`` and still propagate.""" + try: + epc: EpcPropertyData = self._epc_client.get_by_certificate_number( + result.certificate_number + ) + except ValueError as exc: + self.skipped.append( + SkippedCohortCert( + certificate_number=result.certificate_number, + error=f"{type(exc).__name__}: {exc}", + ) + ) + logger.warning( + "skipping unmappable cohort cert %s: %s", + result.certificate_number, + exc, + ) + return None resolved: Optional[Coordinates] = ( coordinates.get(result.uprn) if result.uprn is not None else None ) diff --git a/scripts/hyde/elmhurst_download.py b/scripts/hyde/elmhurst_download.py index 7688a30f..f148ba28 100644 --- a/scripts/hyde/elmhurst_download.py +++ b/scripts/hyde/elmhurst_download.py @@ -28,7 +28,7 @@ SESSION_DIR = HERE / ".elmhurst-session" SAMPLE_DIR = ( HERE.parent.parent / "backend/epc_api/json_samples/real_life_examples" - / "RdSAP-Schema-17.1/uprn_10010215568" + / "SAP-Schema-16.3/uprn_100061905751" ) ASSESSMENT_GUID = "B44A0DB4-4C08-4241-B818-86F060172105" diff --git a/tests/applications/modelling_e2e/test_handler.py b/tests/applications/modelling_e2e/test_handler.py index 762cea60..e7ac4ced 100644 --- a/tests/applications/modelling_e2e/test_handler.py +++ b/tests/applications/modelling_e2e/test_handler.py @@ -198,6 +198,99 @@ def test_lodged_epc_path_saves_epc_plan_and_marks_modelled() -> None: mock_uow.commit.assert_called_once() +def test_skipped_cohort_certs_are_surfaced_in_the_outputs() -> None: + """Cohort certs the mapper can't consume are skipped (so prediction is not + aborted) and surfaced β€” with cert numbers β€” in the subtask outputs, so the + mapper gaps can be reported and closed.""" + from repositories.comparable_properties.epc_comparable_properties_repository import ( + SkippedCohortCert, + ) + + mock_engine = _engine_mock([PROPERTY_ID], [UPRN], [POSTCODE]) + mock_plan = _plan_mock() + skipped = [ + SkippedCohortCert( + certificate_number="8257-7539-1649-0633-4992", + error="ValueError: RdSapSchema17_1: missing required field 'window'", + ) + ] + + with ExitStack() as stack: + stack.enter_context( + patch("applications.modelling_e2e.handler.os.environ", _ENV) + ) + stack.enter_context( + patch( + "applications.modelling_e2e.handler._get_engine", + return_value=mock_engine, + ) + ) + stack.enter_context( + patch("applications.modelling_e2e.handler.EpcClientService") + ).return_value.get_by_uprn.return_value = MagicMock() + stack.enter_context( + patch("applications.modelling_e2e.handler.GeospatialS3Repository") + ) + stack.enter_context( + patch("applications.modelling_e2e.handler.GoogleSolarApiClient") + ) + stack.enter_context( + patch("applications.modelling_e2e.handler._spatial_for", return_value=None) + ) + stack.enter_context( + patch( + "applications.modelling_e2e.handler._solar_insights_for", + return_value=None, + ) + ) + stack.enter_context( + patch("applications.modelling_e2e.handler.overlays_from", return_value=[]) + ) + stack.enter_context( + patch("applications.modelling_e2e.handler.PropertyOverridesPostgresReader") + ) + stack.enter_context( + patch("applications.modelling_e2e.handler.ScenarioPostgresRepository") + ).return_value.get_many.return_value = [MagicMock()] + stack.enter_context( + patch( + "applications.modelling_e2e.handler.catalogue_with_off_catalogue_overrides" + ) + ) + stack.enter_context(patch("applications.modelling_e2e.handler.Session")) + stack.enter_context( + patch( + "applications.modelling_e2e.handler.run_modelling", + return_value=mock_plan, + ) + ) + # The repo accumulated a skipped (unmappable) cohort cert during the run. + stack.enter_context( + patch("applications.modelling_e2e.handler.EpcComparablePropertiesRepository") + ).return_value.skipped = skipped + MockUoW = stack.enter_context( + patch("applications.modelling_e2e.handler.PostgresUnitOfWork") + ) + MockUoW.return_value.__enter__.return_value = MagicMock() + MockUoW.return_value.__exit__.return_value = False + + # Act + result = _call_handler(_BODY) + + # Assert β€” the handler's return (β†’ subtask outputs.result) carries the cert + # numbers + errors of every skipped cohort cert. + assert result == { + "skipped_unmappable_cohort_certs": [ + { + "certificate_number": "8257-7539-1649-0633-4992", + "error": ( + "ValueError: RdSapSchema17_1: missing required field 'window'" + ), + } + ] + } + + # --------------------------------------------------------------------------- # EPC Prediction path # --------------------------------------------------------------------------- diff --git a/tests/repositories/comparable_properties/test_epc_comparable_properties_repository.py b/tests/repositories/comparable_properties/test_epc_comparable_properties_repository.py index 662d5b75..8f71be30 100644 --- a/tests/repositories/comparable_properties/test_epc_comparable_properties_repository.py +++ b/tests/repositories/comparable_properties/test_epc_comparable_properties_repository.py @@ -9,6 +9,8 @@ from datetime import date from pathlib import Path from typing import Any, Optional +import pytest + from datatypes.epc.domain.epc_property_data import EpcPropertyData from datatypes.epc.domain.mapper import EpcPropertyDataMapper from datatypes.epc.search.epc_search_result import EpcSearchResult @@ -126,3 +128,64 @@ def test_no_certs_in_the_postcode_yields_no_candidates() -> None: # Assert β€” no candidates, and the postcode was searched (normalisation/IO ran). assert candidates == [] assert client.searched_postcode == "LS6 1AA" + + +class _FakeEpcClientRaising: + """Serves the cohort, but raises the given exception for specific certs.""" + + def __init__( + self, results: list[EpcSearchResult], failures: dict[str, Exception] + ) -> None: + self._results = results + self._failures = failures + + def search_by_postcode(self, postcode: str) -> list[EpcSearchResult]: + return self._results + + def get_by_certificate_number(self, cert_num: str) -> EpcPropertyData: + if cert_num in self._failures: + raise self._failures[cert_num] + return _epc() + + +def test_unmappable_cohort_cert_is_skipped_and_recorded() -> None: + # Arrange β€” two certs share the postcode; one can't be mapped (the mapper + # raises ValueError for a missing required field, as the gov-API 16.x / sparse + # certs do). + here = Coordinates(longitude=-1.55, latitude=53.81) + client = _FakeEpcClientRaising( + [_result("CERT-OK", uprn=12345), _result("CERT-BAD", uprn=67890)], + failures={ + "CERT-BAD": ValueError( + "RdSapSchema17_1: missing required field 'window'" + ) + }, + ) + geospatial = _FakeGeospatial({12345: here}) + repo = EpcComparablePropertiesRepository(client, geospatial) + + # Act + candidates = repo.candidates_for("LS6 1AA") + + # Assert β€” the unmappable cert is excluded (does NOT sink the cohort) and the + # good one survives; the skip is recorded with the cert number + error so the + # mapper gap can be reported and closed later. + assert [c.certificate_number for c in candidates] == ["CERT-OK"] + assert len(repo.skipped) == 1 + assert repo.skipped[0].certificate_number == "CERT-BAD" + assert "missing required field 'window'" in repo.skipped[0].error + + +def test_transient_fetch_error_is_not_swallowed_as_unmappable() -> None: + # Arrange β€” a non-ValueError (e.g. a transient API failure) must NOT be + # silently skipped as "unmappable"; it propagates so the run fails loudly. + client = _FakeEpcClientRaising( + [_result("CERT-1", uprn=12345)], + failures={"CERT-1": RuntimeError("EPC API error 503")}, + ) + repo = EpcComparablePropertiesRepository(client, _FakeGeospatial({})) + + # Act / Assert + with pytest.raises(RuntimeError, match="503"): + repo.candidates_for("LS6 1AA") + assert repo.skipped == []