Slice 80: 1:1 windows expansion in cohort 000487 (2 → 5 entries)

Closes the final `sap_windows: LEN 5 vs 2` divergence by replacing
the cohort 000487 hand-built's 2-window collapsed encoding with 5
SapWindow entries mirroring the Summary §11 1:1. All South-facing
(orient=5) / PVC frame; two glazing-type groups; per-bp totals
preserved (cascade-equivalent):

  g=0.76/U=2.8: 0.77 m² (Ext1) — unchanged
  g=0.72/U=1.4: 6.69 m² total split per-bp
    Main: 1.65 m² (1 row)
    Ext1: 5.04 m² split 2.16 + 1.53 + 1.35 (3 rows)

Mapper places the Main window between two Ext1 rows in the §11 table;
the hand-built mirrors that order so list-position diffs are zero.

Cascade output unchanged: all 11 `_FIXTURE_PINS["000487"]` SapResult
pins remain GREEN at 1e-4 against worksheet `SAP value 61.6431`.

**Cohort 000487 is now fully Layer-2 GREEN** —
`test_from_elmhurst_site_notes_matches_hand_built_000487` passes with
zero load-bearing divergences between the mapped EpcPropertyData and
the hand-built fixture.

Full sweep: 105 passed (was 104 pre-Slice-77; +1 new diff test), 10
failed (same 10 001479-related). Pyright net-zero.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-05-25 18:06:24 +00:00
parent 4d9586bd56
commit 1f271ca891

View file

@ -423,17 +423,30 @@ LINE_73_M_TOTAL_INTERNAL_GAINS_W: tuple[float, ...] = (
# ============================================================================
# §6 Solar gains — cert-derived inputs + expected outputs
# ============================================================================
# 2 wall windows, both South-facing, 2 glazing types (Manufacturer g⊥):
# "Double with unknown" g=0.76: S 0.77
# "Double between 2002" g=0.72: S 6.69
# All PVC frame. No roof windows, no rooflights.
# 5 wall windows mirroring the Summary §11 1:1, matching the Elmhurst
# mapper's per-row extraction (mapper-vs-hand-built field-parity test).
# All South-facing (orient=5) / PVC frame. Two glazing-type groups; per-
# bp totals preserved (cascade-equivalent):
# g=0.76/U=2.8 (pre-2002): 0.77 m² (Ext1) — unchanged
# g=0.72/U=1.4 (post-2022): 6.69 m² total
# Main: 1.65 m² (1 row)
# Ext1: 5.04 m² split 2.16 + 1.53 + 1.35 (3 rows)
# No roof windows, no rooflights.
SECTION_6_VERTICAL_WINDOWS: tuple[SapWindow, ...] = (
# Windows 1 (PDF (27) U_eff=2.5180, raw U=2.8 pre-2002; g_⊥=0.76):
# area 0.77 m². make_window default u_value=2.8 matches.
make_window(orientation=5, width=0.77, height=1.0, solar_transmittance=0.76),
# Windows 2 (PDF (27) U_eff=1.3258, raw U=1.4 post-2022; g_⊥=0.72):
# area 6.69 m² (1.65 + 5.04). Replaced post-2022 → tighter U.
make_window(orientation=5, width=6.69, height=1.0, solar_transmittance=0.72, u_value=1.4),
# Window 1 on Ext1 (smaller pre-2002 window)
make_window(orientation=5, width=0.77, height=1.0, solar_transmittance=0.76,
u_value=2.8, window_location="1st Extension"),
# Windows 2 on Ext1 (post-2022 replacements)
make_window(orientation=5, width=2.16, height=1.0, solar_transmittance=0.72,
u_value=1.4, window_location="1st Extension"),
# Window 2 on Main (the only Main window — mapper places it between Ext1 rows)
make_window(orientation=5, width=1.65, height=1.0, solar_transmittance=0.72,
u_value=1.4, window_location="Main"),
# Two more post-2022 Ext1 windows
make_window(orientation=5, width=1.53, height=1.0, solar_transmittance=0.72,
u_value=1.4, window_location="1st Extension"),
make_window(orientation=5, width=1.35, height=1.0, solar_transmittance=0.72,
u_value=1.4, window_location="1st Extension"),
)
SECTION_6_ROOF_WINDOWS: tuple[RoofWindowInput, ...] = ()
SECTION_6_ROOFLIGHTS: tuple[RooflightInput, ...] = ()