fix(mapper): handle 'ND' multiple_glazing_type on RdSAP-Schema-20.0.0

`_synthesise_20_0_0_sap_windows` passed `schema.multiple_glazing_type`
straight into `_api_cascade_glazing_type`, which raised UnmappedApiCode on
the "ND" (Not Defined) string that the 20.0.0 corpus lodges alongside the
1-8 integer codes — failing the mapper-coverage guard on every ND-glazed
20.0.0 cert. Mirror the existing 18.0/19.0/17.x seams: route integer codes
through the cascade, fall the "ND" string back to the DG-modal default
(cascade code 2 → daylight g_L 0.80). Also corrects the 20.0.0 schema
field type `int` → `Union[int, str]` to match the data (as 18.0 already
does), which keeps the isinstance guard pyright-clean.

Pre-existing failure (present before this branch's recent commits), not in
the handover regression gate. Fixes all 15 RdSAP-Schema-20.0.0 ND certs;
test_mapper_corpus 6002/6002 pass. pyright net-zero.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-06-15 06:43:55 +00:00
parent 0fae84d2b6
commit 361abc1202
2 changed files with 19 additions and 3 deletions

View file

@ -3319,14 +3319,28 @@ def _synthesise_reduced_field_windows(
]
# ADR-0028: multiple_glazing_type "ND" (Not Defined) → the DG-modal
# default (cascade code 2 → daylight g_L 0.80), as for 18.0/19.0/17.x.
_RDSAP20_ND_GLAZING_TYPE: int = 2
def _synthesise_20_0_0_sap_windows(schema: RdSapSchema20_0_0) -> List[SapWindow]:
"""ADR-0027/0028 seam: 20.0.0 glazed_type codes 1-8+ND are identical to
21.0.1's, so route multiple_glazing_type through the verified cascade (fixes
code 1 "DG pre-2002" read as single), then call the shared core."""
code 1 "DG pre-2002" read as single), then call the shared core. The "ND"
string (no cascade mapping) falls back to the DG-modal default, mirroring
`_synthesise_18_0_sap_windows` without this the cascade raised
UnmappedApiCode on every ND-glazed 20.0.0 cert."""
mgt = schema.multiple_glazing_type
glazing_type = (
_api_cascade_glazing_type(mgt)
if isinstance(mgt, int)
else _RDSAP20_ND_GLAZING_TYPE
)
return _synthesise_reduced_field_windows(
schema.glazed_area,
schema.total_floor_area,
_api_cascade_glazing_type(schema.multiple_glazing_type),
glazing_type,
)

View file

@ -267,7 +267,9 @@ class RdSapSchema20_0_0:
energy_rating_current: int
lighting_cost_current: float
main_heating_controls: List[EnergyElement]
multiple_glazing_type: int
# "ND" (Not Defined) appears in the corpus alongside the 1-8 integer
# codes — type as Union to match the data (mirrors RdSAP-Schema-18.0).
multiple_glazing_type: Union[int, str]
open_fireplaces_count: int
heating_cost_potential: float
hot_water_cost_current: float