S0380.235: map the remaining Elmhurst §11 glazing labels to SAP 10.2 Table 6b

The double_glazing recommendation fixture (Summary_001431) exercises every
RdSAP-21 §11 glazing lodging in one cert; five labels were missing from
`_ELMHURST_GLAZING_LABEL_TO_SAP10` and strict-raised `UnmappedElmhurstLabel`:

  "Secondary glazing"                     -> 7   (Table 6b "secondary glazing", g_L 0.80)
  "Secondary glazing - Normal emissivity" -> 11  (RdSAP-21 secondary normal-E, g_L 0.80)
  "Triple pre 2002"                       -> 10  (triple pre-2002, g_L 0.70)
  "Triple with unknown install date"      -> 6   (generic triple glazed, g_L 0.70)
  "Single glazing, known data"            -> 15  (single known-data, g_L 0.90)

The glazing code's only cascade effect is the §5 (66)..(67) daylight factor
g_L in `_G_LIGHT_BY_GLAZING_CODE` (single 0.90 / double+secondary 0.80 /
triple 0.70); the lodged manufacturer U-value and solar_transmittance drive
§3 / §6 directly (`_g_perpendicular` prefers the lodged value). Codes are the
semantically-exact RdSAP-21 rows within the correct g_L bucket, kept distinct
for the strict-raise audit trail. Adds a full-coverage test over all 13
distinct labels. Suite 2413 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-06-05 08:15:11 +00:00
parent 6d4fa5dd3b
commit 3e45b7fa3b
2 changed files with 55 additions and 0 deletions

View file

@ -42,6 +42,7 @@ from datatypes.epc.domain.mapper import (
EpcPropertyDataMapper,
UnmappedApiCode,
UnmappedElmhurstLabel,
_elmhurst_glazing_type_code, # pyright: ignore[reportPrivateUsage]
)
from domain.sap10_calculator.calculator import calculate_sap_from_inputs
from domain.sap10_calculator.rdsap.cert_to_inputs import SAP_10_2_SPEC_PRICES, cert_to_inputs
@ -1471,6 +1472,36 @@ def test_summary_000474_double_glazed_windows_route_to_code_3() -> None:
)
def test_elmhurst_glazing_label_full_coverage_per_sap10_table_6b() -> None:
# Arrange — the double_glazing recommendation fixture (Summary_001431)
# exercises every RdSAP-21 §11 glazing-type lodging in one cert. Each
# label must resolve to the SAP 10.2 Table 6b cascade code whose
# `_G_LIGHT_BY_GLAZING_CODE` daylight factor g_L is correct for the
# glazing family: single 0.90, double / secondary 0.80, triple 0.70
# (the lodged manufacturer U/g drive §3/§6; the code only sets g_L).
expected: dict[str, int] = {
"Single glazing": 1,
"Single glazing, known data": 15,
"Double pre 2002": 2,
"Double between 2002 and 2021": 3,
"Double with unknown install date": 3,
"Double glazing, known data": 3,
"Double post or during 2022": 5,
"Secondary glazing": 7,
"Secondary glazing - Normal emissivity": 11,
"Triple pre 2002": 10,
"Triple between 2002 and 2021": 9,
"Triple post or during 2022": 6,
"Triple with unknown install date": 6,
}
# Act / Assert
for label, code in expected.items():
assert _elmhurst_glazing_type_code(label) == code, (
f"{label!r} should map to SAP 10.2 Table 6b code {code}"
)
def test_summary_mapper_raises_on_unmapped_glazing_type_label() -> None:
# Arrange — same strict-coverage gate as the cylinder-size helper
# (Slice S0380.15 + S0380.16): silently routing an unknown glazing

View file

@ -5073,6 +5073,30 @@ _ELMHURST_GLAZING_LABEL_TO_SAP10: Dict[str, int] = {
# solar_transmittance=0.72 overrides per worksheet-pinned value.
"Triple between 2002 and 2021": 9,
"Secondary": 7,
# Elmhurst §11 lodges the full "Secondary glazing" phrase as well as
# the bare "Secondary" form — both are SAP 10.2 Table 6b "window with
# secondary glazing" (cascade code 7, g_L=0.80, g⊥=0.76). The
# RdSAP-21 schema splits secondary glazing by pane emissivity; the
# "Normal emissivity" variant is its own code 11 (g_L=0.80, identical
# cascade output to 7, kept distinct for the strict-raise audit
# trail). Surfaced on the double_glazing/before recommendation
# fixture (Summary_001431 §11 Window 9).
"Secondary glazing": 7,
"Secondary glazing - Normal emissivity": 11,
# RdSAP-21 row "triple glazing, installed pre-2002" (cascade code 10,
# g_L=0.70, g⊥=0.68 — same triple-glazed daylight/solar bucket as the
# other triple variants {6, 8, 9, 14}). The lodged manufacturer
# U-value / solar_transmittance drive §6; the code only sets g_L.
"Triple pre 2002": 10,
# Triple glazing of unknown install date → the generic SAP 10.2
# Table 6b "triple glazed" row (cascade code 6, g_L=0.70). No
# dedicated "triple, unknown date" enum exists; 6 is the correct
# triple-glazed bucket.
"Triple with unknown install date": 6,
# RdSAP-21 row "single glazing, known data" (cascade code 15,
# g_L=0.90, g⊥=0.85 — same as plain single glazing). Manufacturer
# U/g lodged on WindowTransmissionDetails drive §6.
"Single glazing, known data": 15,
}
_ELMHURST_GLAZING_LABEL_NOISE_PREFIX_RE: Final[re.Pattern[str]] = re.compile(