Model/tests/domain/modelling
Khalim Conn-Kowlessar 80d617aa5b modelling: glazing overlay models draught-proofing + frame-factor re-lodge
Fitting sealed glazing units changes two things beyond the pane's U/g
that the cascade reads, which the overlay didn't model — leaving the
double/secondary before→after pins ~0.7 SAP short (xfail):

1. Draught-proofing (RdSAP 10 §8.1). Sealed units draught-proof the panes
   they replace, re-lodging the dwelling-level `percent_draughtproofed`
   (cert 001431: 84 → 100). The §2 cascade reads that dwelling-level
   value, so the overlay now carries it. `_recompute_percent_draughtproofed`
   anchors on the lodged before-% — `after = round((round(before%/100 × N)
   + flips) / N × 100)`, N = openable windows (vertical + roof) + doors,
   flips = upgraded panes that were not draught-proofed — so it's robust
   to incomplete window extraction (unchanged openings are already in the
   aggregate). ~0.3 SAP.

2. Frame factor (§6 solar gains). A replacement unit re-lodges its own
   FF=0.70, overriding the pane it replaced — the two "single glazing,
   known data" panes lodge FF 1.00 / 0.50 (one is 6.6 m²), so leaving them
   unchanged understated solar gains by ~+150 kWh space heating. `WindowOverlay`
   now carries `frame_factor`, written flat onto the window. ~0.4 SAP.

Wiring: `EpcSimulation.percent_draughtproofed` + `WindowOverlay.frame_factor`
new fields; `apply_simulations` / `_fold_window` write them; the glazing
generator computes both from the upgraded set and cert 001431's after.

Un-xfails `test_{double,secondary}_glazing_overlay_reproduces_the_relodged_after`
— both now pin SAP/CO2/PE to the relodged after within tolerance. Updates
the two `test_glazing_recommendation` overlay expectations for the new
`frame_factor`. 96 modelling tests pass; zero new pyright errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 08:25:08 +00:00
..
fixtures feat(modelling): system tune-up options (standard + zone controls) 2026-06-10 10:20:46 +00:00
__init__.py feat(modelling): Overlay Applicator folds EpcSimulation onto EpcPropertyData 2026-06-02 22:13:51 +00:00
_elmhurst_recommendation.py test(modelling): Elmhurst before/after cascade pin for cavity wall (#1154) 2026-06-03 09:36:53 +00:00
test_ashp_cost_inputs.py feat(modelling): classify ASHP existing system by fuel code 2026-06-06 21:10:45 +00:00
test_considered_measures.py feat(modelling): drive measure scoping from the Scenario's exclusions 2026-06-16 15:26:25 +00:00
test_elmhurst_cascade_pins.py modelling: glazing overlay models draught-proofing + frame-factor re-lodge 2026-06-24 08:25:08 +00:00
test_floor_recommendation.py refactor(modelling): group domain/modelling into generators/scoring/optimisation 2026-06-03 13:48:36 +00:00
test_glazing_recommendation.py modelling: glazing overlay models draught-proofing + frame-factor re-lodge 2026-06-24 08:25:08 +00:00
test_heating_cost_inputs.py feat(modelling): composite per-dwelling boiler + tune-up costing (ADR-0027) 2026-06-10 19:41:06 +00:00
test_heating_recommendation.py fix(modelling): offer ASHP when the catalogue has no ASHP row 2026-06-16 14:55:41 +00:00
test_lighting_recommendation.py feat(modelling): recommend_lighting upgrades all non-LED bulbs to LED 2026-06-05 12:23:27 +00:00
test_measure_dependency.py refactor(modelling): ventilation_dependency delegates to the generator + wraps 2026-06-03 14:04:17 +00:00
test_measure_type.py feat(modelling): secondary-heating-removal generator + MeasureType (ADR-0028) 2026-06-11 13:35:14 +00:00
test_optimiser.py refactor(modelling): type measure_type fields as MeasureType 2026-06-08 20:13:31 +00:00
test_overlay_applicator.py Land an override on the EPC's part at its position when the label is absent 🟩 2026-06-23 17:09:11 +00:00
test_package_scorer.py feat(modelling): Score carries the scored SapResult for billing 2026-06-03 17:20:45 +00:00
test_plan.py refactor(modelling): type measure_type fields as MeasureType 2026-06-08 20:13:31 +00:00
test_plan_valuation.py feat(modelling): wire Valuation Uplift onto the Plan 2026-06-04 08:59:04 +00:00
test_products.py feat(modelling): composite per-dwelling boiler + tune-up costing (ADR-0027) 2026-06-10 19:41:06 +00:00
test_roof_recommendation.py feat(modelling): room-in-roof safety guard defers the roof generator 2026-06-05 10:06:08 +00:00
test_scenario.py feat(modelling): drive measure scoping from the Scenario's exclusions 2026-06-16 15:26:25 +00:00
test_scoring.py refactor(modelling): type measure_type fields as MeasureType 2026-06-08 20:13:31 +00:00
test_secondary_heating_recommendation.py feat(modelling): secondary-heating-removal generator + MeasureType (ADR-0028) 2026-06-11 13:35:14 +00:00
test_solar_config_selection.py feat(modelling): conservative PV config selection (5-config spread) 2026-06-08 10:02:15 +00:00
test_solar_overshading.py feat(modelling): generation-calibrated PV overshading derivation 2026-06-08 09:59:48 +00:00
test_solar_potential.py feat(modelling): typed SolarPotential projection over Google buildingInsights 2026-06-08 09:55:55 +00:00
test_solar_products.py feat(modelling): Products.solar_bundle_cost + committed solar rate sheet 2026-06-08 12:10:27 +00:00
test_solar_recommendation.py feat(modelling): recommend_solar — eligibility + competing array Options 2026-06-08 12:14:24 +00:00
test_valuation.py feat(modelling): ValuationUplift domain class (percentage-primary) 2026-06-04 08:33:19 +00:00
test_ventilation_recommendation.py feat(modelling): ventilation Recommendation Generator (detect + price) 2026-06-03 14:01:14 +00:00
test_wall_recommendation.py feat(modelling): explicit park-home guard in the solid-wall generator 2026-06-05 10:49:50 +00:00
test_window_extraction_001431.py fix(extractor): capture all 17 openable §11 windows on cert 001431 2026-06-05 14:33:25 +00:00