Slice 101a: API glazing_type=14 → DG/TG 2022+ (RdSAP 10 Table 24)

Cert 0380 (ASHP semi-detached bungalow, worksheet SAP 88.5104)
lodges glazing_type=14 on all windows. The worksheet uses U=1.3258
(post-curtain) for line (27), back-calculating to a raw U=1.40 —
the SAP10.2 Table 24 row for "Double or triple glazed, 2022 or
later" (England/Wales 2022+ / Scotland 2023+ / NI 2022+). Without
code 14 in `_API_GLAZING_TYPE_TO_TRANSMISSION` the cascade falls
back to `u_window`'s default (~U=2.50 post-curtain), inflating
windows HLC by 5 W/K on cert 0380 (6.80 → 11.68).

Added `14: (1.4, 0.72, 0.70)` — same U/g/frame as code 13. Codes
13 and 14 are schema siblings within the post-2022 product family
(the cert lodgement integer differentiates between DG and TG
sealed-unit variants but Table 24 collapses them to the same row).

Effect on cert 0380 API path:
- windows HLC 11.68 → 6.80 (= worksheet 6.80 exact)
- (37) total HLC 104.22 → 99.34 (worksheet 96.09; Δ +3.25 left
  on walls — next slice closes it)
- sap_continuous 86.82 → 87.62 (Δ -1.69 → -0.89; closer to
  worksheet 88.51)

No golden cert residuals shifted (cohort + 9501 don't lodge
glazing_type=14).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-05-26 22:25:04 +00:00 committed by Jun-te Kim
parent 04d6e8b868
commit 7874374bcf
2 changed files with 37 additions and 0 deletions

View file

@ -557,6 +557,35 @@ def test_api_9501_photovoltaic_array_surfaced() -> None:
assert arrays[0].overshading == 1 # RdSAP: None or very little
_API_0380_JSON = (
Path(__file__).parents[3]
/ "domain/sap10_calculator/rdsap/tests/fixtures/golden"
/ "0380-2471-3250-2596-8761.json"
)
def test_api_0380_glazing_type_14_resolves_to_post_2022_dg_u_value() -> None:
# Arrange — cert 0380 (ASHP semi-detached bungalow, worksheet SAP
# 88.5104) lodges glazing_type=14 on all windows. The worksheet
# uses U=1.3258 (post-curtain) for line (27), which back-calculates
# to a raw U=1.40 — the SAP10.2 Table 24 row for "Double or triple
# glazed, 2022 or later". Code 13 in our existing dict carries the
# same U/g values; code 14 is the schema sibling for the same
# post-2022 product family (DG sealed-unit variants differ in
# the cert lodgement but agree on the spec U-value).
doc = json.loads(_API_0380_JSON.read_text())
epc = EpcPropertyDataMapper.from_api_response(doc)
# Act — pick any window (cert 0380 lodges only glazing_type=14).
w = epc.sap_windows[0]
td = w.window_transmission_details
# Assert
assert td is not None
assert abs(td.u_value - 1.40) <= 1e-4
assert abs(td.solar_transmittance - 0.72) <= 1e-4
def test_api_9501_room_in_roof_surfaces_populated() -> None:
# Arrange — cert 9501's API JSON lodges measured RR detail under
# `sap_room_in_roof.room_in_roof_details`: two gable walls

View file

@ -2286,6 +2286,14 @@ _API_GLAZING_TYPE_TO_TRANSMISSION: Dict[int, tuple[float, float, float]] = {
2: (2.0, 0.72, 0.70), # Double glazed, England/Wales 2002+ (pre-2022)
3: (2.8, 0.76, 0.70), # Double glazed, pre-2002 (12mm gap default)
13: (1.4, 0.72, 0.70), # Double glazed, Argon-filled post-2022
14: (1.4, 0.72, 0.70), # Double or triple glazed, post-2022
# (Table 24 last row: 2022+ E/W / 2023+ Sc
# / 2022+ NI — same U/g as code 13 per
# spec; the integer codes 13/14 are
# schema siblings within the post-2022
# product family. Cert 0380 lodges code
# 14 on all windows; worksheet uses U=1.4
# = post-curtain 1.3258.)
}