Model/domain/sap10_calculator/docs/HANDOVER_0240_CLOSURE.md
Khalim Conn-Kowlessar 6ac67a4c6f docs: add full 0240 worksheet input spec to the closure handover
Adds a "build THIS in Elmhurst" specification — dwelling, dual condensing
oil-combi (code 130) heating, combi/no-cylinder DHW (Table 3a keep-hot
600), per-element fabric W/K targets, room-in-roof gables, the 5 vertical
+ 6 roof-of-room windows, lighting (8 LED), no PV — so a generated
worksheet reproduces cert 0240 as closely as possible. Flags the three
load-bearing differences vs case 6 (combi code 130, no cylinder, boiler
interlock PRESENT → no -5pp) that the new worksheet must capture.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 17:13:46 +00:00

12 KiB
Raw Permalink Blame History

Handover — closing golden cert 0240-0200-5706-2365-8010 to 1e-4

Point-in-time note. Start from AGENT_GUIDE.md for methodology, accuracy bar, and pipeline. This records the state of cert 0240 and the concrete path to driving its residual to zero.

  • Branch: feature/per-cert-mapper-validation
  • HEAD: 7344f600 (S0380.207). Confirm with git rev-parse HEAD.
  • Baseline: 2372 passed, 1 skipped, 0 failed (AGENT_GUIDE §4 suite command).

What the last session shipped (S0380.201207)

Closed simulated case 6 (001431_case6) to 1e-4 on the full SapResult and promoted it to an e2e fixture. It is the worksheet-backed proxy for 0240's dual-oil, different-parts archetype (Main 1 rads/2106 + Main 2 UFH/2110, 51/49, 6 "Roof of Room" rooflights, no boiler interlock). Slices:

slice spec what
S0380.201 Table 4f note c) 2nd-main circulation pump → (231)
S0380.202 Table 5a note a) 2nd-main pump gain → (70)
S0380.203 RdSAP §3.7 "Roof of Room" rooflights deduct from the §3.10.1 RR residual → (30)
S0380.204 extractor/mapper capture Main 2's §14.1 emitter + control
S0380.205 SAP 10.2 p.186 two-systems-different-parts MIT: weighted R + elsewhere two-control blend → (87)/(90)/(98c)
S0380.206 Appendix D Eq D1 Q_space = DHW boiler's own (204) share, not (202) → (219)
S0380.207 test promote case 6 to a full e2e fixture

0240 was re-pinned at each step (it shares the archetype) and its residual improved on PE/CO2 but its SAP integer dropped 73→72. The boiler-interlock 5pp the previous handover called the priority was already implemented — see project_case6_interlock_already_done.


The 0240 problem — and why case 6 did NOT close it

⚠️ Critical: 0240 is API-only and its register target is INTEGER-rounded

0240 has no worksheet. The golden test pins the cascade against the lodged EPC register:

  • energy_consumption_current = 122an integer (1 kWh/m² resolution).
  • co2_emissions_current = 6.01 d.p. (tonnes).
  • current_energy_efficiency = None — the SAP isn't even in the JSON (actual_sap=73 in the test was carried from the original lodgement).

You cannot drive 0240 to "0 residual" at 1e-4 against these. The register rounds PE to the nearest whole kWh/m², so any cascade value in [121.5, 122.5) is 122, and the true (unrounded) Elmhurst value could sit anywhere in that band — or itself carry residual vs the rounded lodgement. Matching a rounded integer to 1e-4 is not a well-posed target. The only 1e-4 ground truth is a worksheet (the per-line (1)..(286) Elmhurst output), which is exactly why case 5/6 were generated.

Current 0240 cascade vs lodged: PE 123.8687 vs 122 (resid +1.8687), CO2 6.0907 vs 6.0 (+0.0907), SAP cont 72.39 (integer 72 vs lodged 73, resid 1).

Why case 6 didn't close 0240

Case 6 validated the dual-main structure (MIT p.186, pumps, rooflights, Eq-D1 fraction). But 0240 differs in cert-specific features case 6 does not exercise:

feature case 6 (worksheet-validated) 0240 (unvalidated)
SAP code 127 regular oil boiler 130 condensing oil combi (Table 4b 82/73)
DHW path regular boiler + 110 L cylinder → primary/storage loss combi, NO cylinder → Table 3a keep-hot 600 kWh (combi_loss), primary_loss 0
TFA (case-6 dwelling) 201.53 m² (different fabric/dimensions)
PV none none (the golden note's "+ PV" is STALE — solar_water_heating=N, no PV field)

So 0240's remaining residual lives in the parts case 6 never touched — the condensing-combi (130) + no-cylinder HW path and the cert's own fabric. The combi Eq-D1 / Table 3a keep-hot path has never been pinned against a worksheet in the dual-main context.

Partial ground truth already in the 0240 JSON

The lodged renewable_heat_incentive block gives two deemed-demand figures:

  • water_heating = 2842.82exactly equals the cascade's §4 HW output (64) (2842.82). So the HW demand is right; any HW residual is in the efficiency (Eq D1 combi blend), not the demand.
  • space_heating_existing_dwelling = 13254.52 vs cascade (98c) 12760.9 — differ ~494 kWh (~3.7%). RHI uses its own deemed methodology so this is not a clean 1e-4 check, but it's a hint the space-heat demand or the combi figures are worth scrutinising.

What to do next — generate the right example

To close 0240 properly you need a worksheet that exercises its combi-HW path. Two options, best first:

  1. Exact 0240 replica worksheet (gold standard). Re-enter 0240's lodged data into Elmhurst and export the worksheet PDF. Then build a mapper-driven fixture (mirror _elmhurst_worksheet_001431_case6.py) and pin every line (1)..(286) at 1e-4. The first diverging line localises the residual exactly. This is the only way to get a true 1e-4 target for 0240.

  2. "Case 7" — case 6 with 0240's combi swapped in. If generating an exact 0240 replica is hard, generate a 001431 variant that changes case 6's heating to 0240's:

    • Condensing oil combi, SAP code 130 (not 127 regular boiler).
    • NO hot water cylinder — combi instantaneous DHW → WHC 901, Table 3a/3b combi keep-hot loss, no primary/storage loss.
    • Keep the validated dual-main rads(2106)+UFH(2110) 51/49 + RR rooflights. This pins the combi Eq-D1 + Table 3 keep-hot path (the biggest unvalidated piece) against a worksheet. Whatever it reveals applies directly to 0240.

The single most important differentiator to change vs case 6: regular boiler + cylinder → condensing combi (130) with no cylinder. That is the one HW path 0240 uses that has never seen a worksheet in this archetype.

Reframing the goal

If a worksheet is genuinely unavailable, "0 residual vs the lodged register" is not achievable at 1e-4 (integer rounding). The realistic target then is the ±0.5 SAP fallback (AGENT_GUIDE §1) — and 0240's continuous SAP 72.39 vs lodged 73 is ~0.6 off, just outside it. Closing that last 0.6 still requires knowing the true (worksheet) value, so the worksheet is the unblocker either way.


0240 worksheet input specification (build THIS in Elmhurst)

Reproduce cert 0240-0200-5706-2365-8010 as closely as possible so the worksheet is a valid 1e-4 ground truth for the cascade. All values are from the fixture JSON (tests/.../fixtures/golden/0240-0200-5706-2365-8010.json). Match the U-values / W-per-K targets below — those are what the cascade actually consumes, so hitting them matters more than the exact construction wording.

Dwelling

  • Detached house, construction age band J, England. Postcode LE15 9LB (drives the demand/EPC climate). 1 extension. 7 habitable rooms.
  • Storey height 2.28 m. Total floor area ≈202 m² = Main ground floor 97.72 + Extension 1 ground floor 20.61 + the room-in-roof floor 83.2.

Heating — the load-bearing difference vs case 6. TWO main systems, both a condensing oil combi, SAP main heating code 130 (Table 4b winter 82 / summer 73), oil fuel, balanced flue (not fan-assisted), efficiency from the SAP table (no PCDB boiler index), central-heating pump age unknown. They heat different parts (so the p.186 MIT applies, already implemented):

  • Main 1radiators, control 2106 (programmer + room thermostat + TRVs), 51%, serves the living area.
  • Main 2underfloor heating in screed (R=0.75), control 2110 (time + temperature zone control), 49%, serves elsewhere.

Domestic hot water — the other key difference vs case 6. Heated from the main system (WHC 901), oil. It is a COMBI with NO hot-water cylinder — instantaneous DHW → SAP 10.2 Table 3a keep-hot loss 600 kWh/yr (combi_loss 600, primary_loss 0). 3 mixer showers + 1 bath; no effective WWHRS. NB the lodged RHI water_heating = 2842.82 already equals the cascade HW output exactly, so get the DHW demand inputs right and any residual is in the combi efficiency (Eq D1 winter/summer blend).

  • Boiler interlock: YES for 0240 (combi + room thermostat 2106, no cylinder) → no 5pp penalty, both systems run at base eff 82/73. (This is the OPPOSITE of case 6, which had a regular boiler + cylinder with no cylinder stat → 5pp. Get this right or the efficiencies — hence everything — will be off.)

Fabric — target W/K (cascade values to reproduce; total external area 328.97 m²):

element W/K notes
Walls (29a) 24.45 age J, uninsulated (NI), not dry-lined, not measured
Roof (30) 32.331 Main = pitched, access to loft, insulation at ceiling, 400 mm+ ; Ext1 = pitched vaulted ceiling, no insulation (NI)
Floor (28) 29.4297 solid; Main heat-loss perimeter 36.45, Ext1 13.45
Party/gable (32) 7.84 RR gables billed as party at U=0.25
Windows (27) 22.7407 see below
Roof windows (27a) 12.6374 see below
Doors (26) 11.1 2 doors, uninsulated
Thermal bridging (36) 36.1867 = 0.11 × 328.97
(33) fabric total 140.5288
(37)+vent feeds (39) total transmission 176.7155

Room-in-roof (Main only): floor area 83.2 m², two gables L = 6.40 m — one Exposed, one Party (per the case-5/6 sandstone replica convention), age J. This is the same Simplified/detailed-gable RR structure case 6 validated.

Windows (all double glazed, PVC frame, glazing "DG 2002+", U≈2.0, g=0.72):

  • 5 vertical wall windows: 1.4×1.3, 1.2×1.3 (orient N), 1.6×1.3, 2.5×2.0 (orient E), 1.4×1.3 (orient S, on Extension 1).
  • 6 "Roof of Room" rooflights (window_wall_type 4): all 1.0×1.0, at 45°, 3 orient N + 3 orient S. These bill on (27a) and deduct from the RR residual (S0380.203) — keep them as roof-of-room, not vertical glazing.

Ventilation / lighting / other

  • Natural ventilation; no mechanical ventilation, no extract fans, no chimneys/flues. 85% draught-proofed.
  • Lighting: 8 LED bulbs, 100% low-energy (no CFL/incandescent).
  • No PV, no solar thermal, no secondary heating, no air-conditioning.
  • Electricity meter type 3 (standard), smart meter present, not export-capable.

The three things that MUST differ from case 6 (or you've just rebuilt case 6)

  1. Condensing oil combi, SAP code 130 (case 6 = regular oil boiler 127).
  2. Combi, NO cylinder → Table 3a keep-hot 600 kWh (case 6 = boiler + 110 L cylinder → primary/storage loss).
  3. Boiler interlock PRESENT → no 5pp (case 6 = no interlock → 5pp). Driven automatically by "combi + room thermostat, no cylinder", but verify the worksheet shows base eff 82/73, not 77/68.

Everything else (dual-main different-parts MIT, two pumps, rooflight→RR, Eq-D1 (204) share) is already implemented and validated by case 6 — the new worksheet just confirms the combi-HW path on top of that closed structure.


Pointers

  • Golden pin + full slice history: tests/domain/sap10_calculator/rdsap/test_golden_fixtures.py (cert 0240-0200-5706-2365-8010, line ~83).
  • Case-6 fixture to mirror: tests/domain/sap10_calculator/worksheet/_elmhurst_worksheet_001431_case6.py + its e2e pins in test_e2e_elmhurst_sap_score.py::_FIXTURE_PINS["001431_case6"].
  • Memories: project_case6_mit_two_system_rootcause (the p.186 MIT, now CLOSED), project_case6_interlock_already_done, feedback-worksheet-not-api-reference (API matches the worksheet, not the lodged register), feedback-software-no-special-handling.
  • Repro 0240: EpcPropertyDataMapper.from_api_response(json.load(...0240.json))cert_to_inputs / cert_to_demand_inputscalculate_sap_from_inputs. The §2.4 section helpers are UNFAITHFUL (skip the interlock penalty + two-system MIT params) — diagnose against the real cert_to_inputs cascade.
  • Process: one slice = one commit, spec citation (page+line), Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>. SAP 10.2 only. No tolerance widening. mapper.py + cert_to_inputs.py each carry 32 pre-existing pyright errors (baseline-compare with git stash).