Keep swallowing the control gap's boundary form in the accuracy harness 🟪

The control gap surfaces as UnmappedSapCode on main and as UnmappedPasHubLabel
once the #1557 control mapper lands (unmapped community-heating control), so the
harness must swallow both; only the closed fuel-specific MissingMainFuelType is
dropped as a fuel-drop tripwire.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Daniel Roth 2026-07-14 17:40:50 +00:00
parent ccae1adfc9
commit 98aa0127a7

View file

@ -21,11 +21,11 @@ a **hybrid** gate:
calculable `EpcPropertyData`. Any *unexpected* exception is a hard fail (a
real extractor/mapper bug on that property). The one *known* remaining gap
the pashub mapper not coding a main-heating `main_heating_control` label to a
SAP code (`UnmappedSapCode`) is `xfail`ed dynamically, so these flip to
passing automatically once that mapper fix lands. The main-fuel-code gap
SAP code is `xfail`ed dynamically (see `_KNOWN_GAPS` for its two forms), so
these flip to passing once that mapper fix lands. The main-fuel-code gap
(`Bulk LPG`, and the `Fuel:`-form Mains Gas the extractor was dropping) was
closed in #1558, so those exceptions are *no longer* swallowed — a fixture
that regresses to a fuel gap now hard-fails.
closed in #1558, so `MissingMainFuelType` is *no longer* swallowed — a
fixture that regresses to a dropped fuel now hard-fails.
* `test_pashub_sap_accuracy_aggregate` over the fixtures that compute:
fraction within 0.5 SAP of `pre_sap`, and MAE. Ratcheting floor/ceiling
@ -45,17 +45,20 @@ from typing import Optional
import pytest
from backend.documents_parser.parser import parse_site_notes_pdf
from datatypes.epc.domain.mapper import UnmappedPasHubLabel
from domain.sap10_calculator.calculator import Sap10Calculator
from domain.sap10_calculator.exceptions import UnmappedSapCode
# Known in-progress pashub main-heating string→SAP-code mapper gaps, fixed
# field-by-field. The remaining gap is a raw `main_heating_control` label the
# calculator can't code (`UnmappedSapCode`) — it xfails until that mapper fix
# lands. The main-fuel-code gaps are closed: mains-gas code landed in #1554, and
# #1558 coded "Bulk LPG" and captured the `Fuel:`-form Mains Gas the extractor
# was dropping. Their exceptions (`UnmappedPasHubLabel`, `MissingMainFuelType`)
# are deliberately *not* here, so a fuel regression hard-fails instead of hiding.
_KNOWN_GAPS: tuple[type[Exception], ...] = (UnmappedSapCode,)
# field-by-field. The remaining gap is the `main_heating_control` label, which
# surfaces in one of two forms: `UnmappedSapCode` (raw label reaches the
# calculator) or, once the control mapper (#1557) lands, `UnmappedPasHubLabel`
# (strict-raised at the boundary for a control label not yet mapped — e.g. the
# cohort's community-heating charging control). Both xfail until that fix lands.
# The main-fuel-code gaps are closed (mains-gas code #1554; "Bulk LPG" + the
# `Fuel:`-form Mains Gas the extractor was dropping #1558), so `MissingMainFuelType`
# is deliberately *not* here — a fuel-drop regression hard-fails instead of hiding.
_KNOWN_GAPS: tuple[type[Exception], ...] = (UnmappedSapCode, UnmappedPasHubLabel)
_FIXTURES_DIR = Path(__file__).parent / "fixtures" / "pashub_accuracy"
_MANIFEST_PATH = _FIXTURES_DIR / "manifest.json"