Captures the corpus state (36 EXACT + 5 pinned community-heating variants), the SAP 302 CHP credit cluster as the highest-leverage remaining front, the unresolved 0.8523 / 0.1994 worksheet-factor mysteries to per-line-walk before hypothesising, and — importantly — the new test layout (tests/domain/sap10_calculator/) that changes every verification command. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
9.5 KiB
Handover — post Slices S0380.177..179 (+ infra/CI work)
Branch: feature/per-cert-mapper-validation. HEAD af8e0d94
(post merge from main). Predecessor:
HANDOVER_POST_S0380_176.md.
TL;DR
The 41-variant heating-systems corpus is now 36 EXACT + 5 pinned.
The only remaining residuals are the 5 community-heating (CH) variants
— all SAP code 302/301/304 heat-network systems. Everything else
(oil, electric, solid fuel, ASHP/GSHP, PCDB, "no system") is EXACT on
all four metrics (ΔSAP/Δcost/ΔCO2/ΔPE).
Three closure slices + four infra changes landed this session:
| Slice / change | HEAD | Scope |
|---|---|---|
| S0380.177 | 5276282d |
oil 6 boiler interlock from room-thermostat absence. Control code 2101 ("no thermostatic control of room temperature") ⇒ no room thermostat ⇒ per RdSAP 10 §3 NOT interlocked despite cylinderstat=Yes (P960 "Boiler Interlock: No") ⇒ SAP 10.2 Table 4c(2) −5pp Space+DHW. New _BOILER_NO_ROOM_THERMOSTAT_CONTROL_CODES={2101,2102}; no_interlock ORs room-thermostat absence with stored-HW cylinderstat absence; Space −5pp leg now fires for Table 4b non-PCDB boilers. |
| S0380.178 | c054d712 |
oil 6 circulation pump ×1.3 for absent room thermostat. SAP 10.2 Table 4f footnote a) (PDF p.175) "Multiply by 1.3 if room thermostat is absent" ⇒ 41 × 1.3 = 53.3 kWh = ws (230c). Closes oil 6 FULLY (same root cause as .177). |
| S0380.179 | f2062a2f |
RdSAP 10 §10.7 electric-immersion default for "no system". Cert lodges water code 999 (NON) + "cylinder present: No", but §10.7 substitutes an electric immersion on a Table 28 row-1 110 L cylinder + Table 29 row-1 insulation. New _apply_rdsap_no_water_heating_system_default(epc) rebinds the epc at the top of cert_to_inputs when water_heating_code==999. One fix closed HW (−594 kWh storage loss) AND the downstream space residual (+228, a HW-gains→MIT artifact). Closes "no system" FULLY. |
| appliances+cooking | 2f039aeb |
Threaded appliances_kwh_per_yr + cooking_kwh_per_yr (Appendix L L13/L14/L16a + L20) onto SapResult/CalculatorInputs for ADR-0014 BillDerivation. Output-only, zero rating drift. |
| test fixes | 0e484aaa |
Fixed 11 pre-existing CI failures from an absorbed PR: test_appendix_u.py signature drift + mislabelled "SAP 10.3"→10.2; test_table_32.py re-pinned oil(4)=5.44 / FAME(73)=7.64 to the worksheet-canonical values the table actually uses. |
| corpus PDFs | d1c87d84 |
Committed the 82 heating-corpus PDF fixtures (sap worksheets/heating systems examples/) so CI can run the residual pins. |
| test move | d7d5084f |
Moved all 5 calculator test dirs → tests/domain/sap10_calculator/ so CI (which collects tests/) runs them. SEE "Test layout changed" below — it changes every command. |
⚠ Test layout changed this session — commands are different now
The calculator tests moved out of domain/sap10_calculator/.../tests
into tests/domain/sap10_calculator/{,worksheet,rdsap,climate,validation}.
Cross-imports were rewritten domain.sap10_calculator.worksheet.tests
→ tests.domain.sap10_calculator.worksheet. Any old handover command
that references domain/sap10_calculator/worksheet/tests/... is STALE.
New full verification command (replaces the old extended suite):
PYTHONPATH=/workspaces/model python -m pytest \
tests/domain/sap10_calculator/ \
backend/documents_parser/tests/ \
--no-cov -q -p no:cacheprovider
Expected at HEAD: ~2221 pass, 1 skipped, 0 fail (the 1 skip is the
corpus blocked-variant skipif). The cascade-pin / golden / e2e
conformance suites are all under tests/domain/sap10_calculator/.
Two gotchas:
load_cellstests (tests/domain/sap10_calculator/worksheet/test_{dimensions,ventilation,water_heating}.py) pin against the gitignored2026-05-19-17-18 RdSap10Worksheet.xlsxat repo root._xlsx_loader.load_cellspytest.skip()s when the xlsx is absent — so they run locally and skip in CI. If you're missing the xlsx locally, those skip (not fail).- Uncommitted
pytest.inichange (came in with a main pull) REMOVEStests/+domain/sap10_ml/testsfromtestpaths. HEAD has them; the working tree strips them. This is NOT a slice change — confirm with the user before committing it, because removingtests/would un-collect the moved calculator tests.
Current residual state at HEAD af8e0d94
36 variants EXACT (all four metrics < tolerance)
ashp, gshp,
electric 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14,
oil 1, oil 2, oil 3, oil 4, oil 5, oil 6, oil pcdb 1, oil pcdb 2, oil pcdb 3,
pcdb 1, pcdb 3,
solid fuel 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
no system
5 community-heating variants pinned
| Variant | SAP code | ΔSAP_c | Δcost | ΔCO2 | ΔPE | Closure driver |
|---|---|---|---|---|---|---|
| CH6 (CHP/Coal) | 302 | −7.4942 | +£172.68 | −2939.67 | +7481.57 | SAP 302 CHP credit + DLF=1.0 P960 quirk |
| CH2 (CHP/Gas) | 302 | +0.5277 | −£12.16 | −1435.09 | +1123.01 | SAP 302 CHP credit (CO2 + PE) |
| CH4 (CHP/Oil) | 302 | +0.5277 | −£12.16 | −4401.85 | +111.58 | SAP 302 CHP credit (CO2) |
| CH3 (HP/Elec) | 304 | +0.0000 | −£0.00 | −98.92 | −457.54 | (372) electrical-distribution + HP COP |
| CH1 (Boilers/Gas) | 301 | +0.0000 | −£0.00 | −23.60 | −208.23 | (372) electrical-distribution factor |
Blocked tier: empty.
Open fronts ranked by leverage
1. SAP 302 CHP CO2/PE credit cascade (3 variants — CH2/CH4/CH6) — HIGHEST
Closes the big CO2/PE residuals on CH2/CH4 AND the −7.49 SAP on CH6 simultaneously. Spec: block 13b PE (PDF p.153) + 12b CO2 — the displaced-electricity CHP credit lines (worksheet (363)-(366), (464)/(466)/(468)):
Space heating from CHP (307a) × 100 ÷ (362) = ... (363)
less credit emissions −(307a)×(361) ÷ (362) = ... (364)
Water heated by CHP (310a) × 100 ÷ (362) = ... (365)
less credit emissions −(310a)×(361) ÷ (362) = ... (366)
Heat from heat source 2 [(307b)+(310b)] × 100 ÷ (467b) (468)
RdSAP 10 §C defaults (verified vs CH2/CH4/CH6 worksheet (461)/(462)):
CHP overall eff 75%, heat-to-power 2.0 → heat_eff 50% / electric_eff
25%; boiler eff 80%. The .172 scaling helper already keys on
_HEAT_NETWORK_HEAT_SOURCE_EFFICIENCY — add code 302 there once the
split formula is in place; the .173 predicate
_is_community_heating_hw_from_main auto-activates.
⚠ UNRESOLVED per-line caveat — walk before hypothesising. The
Elmhurst worksheet (463) energy column = spec_formula × 0.8523
uniformly across non-CHP heat-network rows (the 0.8523 also shows in
CH1 (467)). It is NOT RdSAP 10 / SAP 10.2 spec-derived. Per
feedback-spec-floor-skepticism / feedback-software-no-special-handling,
DUMP the worksheet per-line and reconcile 0.8523 before baking any CHP
formula into the cascade. Likely 2-3 slices.
2. CH1/CH3 (372)/(472) electrical-distribution CO2/PE — DEFERRED
CH1/CH3 are SAP + cost EXACT; only CO2/PE remain. Worksheet (372) CO2 factor = 0.1994 (block 11a) / 0.2114 (block 11b); PE = 1.7591 / 2.1872. These don't match ANY Table 12 / 12d / 12e weighting derivable from the (307) or (307)+(310) heating-demand monthly profile. (313) annual = 0.01 × (307) ONLY (verified across 5 variants, NOT 0.01 × (307+310) as the spec text says). Don't guess — reverse-engineer the 0.1994 factor from a wider variant set or find BRE documentation first.
3. CH6 DLF=1.0 P960 quirk — architectural, likely pin-forever
P960 input lodges Distribution Loss: Two adjoining dwellings... +
Distribution Loss Value: 0.0 → ws (306) = 1.0000, but the Summary
doesn't carry anything distinguishing CH6 from CH4. Per §C3.1 the
manual-DLF override is legal but not surfaced by the Summary.
Recommendation: pin + document once the CHP credit lands.
Discipline (carried from every prior handover)
- Per-line walk worksheet → spec → fix. All 3 slices this session landed via per-line P960 dumps. Don't form a spec hypothesis without per-line data (the 0.8523 + 0.1994 factors are the live examples).
- Spec-floor skepticism cuts BOTH ways — a spec-correct fix often EXPOSES the next residual (oil 6 .177→.178; "no system" HW→space). Apply the spec uniformly; the surfaced residual is the next target.
- SAP 10.2 ONLY, never 10.3.
- Don't conflate
main_heating_categoryandsap_main_heating_code— the Elmhurst mapper leavescategory=Noneon Table 4b liquid-fuel boilers; cascade gates must check both. - Target is < 1e-4 vs worksheet — ΔSAP=0.07 is NOT closed. Re-pin smaller; never widen tolerance, never xfail.
- One slice = one commit, spec citation in the message, trailer
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>.
Memories to load (in order)
project-heating-systems-corpus # HEAD af8e0d94, 36 EXACT + 5 pinned
feedback-sap-10-2-only-never-10-3
feedback-software-no-special-handling
feedback-spec-floor-skepticism
feedback-worksheet-not-api-reference
feedback-spec-citation-in-commits
feedback-verify-handover-claims
feedback-zero-error-strict
feedback-commit-per-slice
feedback-aaa-test-convention
feedback-e2e-validation-philosophy
feedback-abs-diff-over-pytest-approx
feedback-one-e-minus-4-across-the-board
reference-unmapped-sap-code
reference-unmapped-api-code
project-oil-price-spec-divergence
Master doc
Architecture + API + validation: SAP_CALCULATOR.md
(§8 "Elmhurst-mirrored spec divergences" carries .163 HW dual-rate
annual + .164 §12.4.4 summer-immersion). If the CHP 0.8523 multiplier
resolves to an Elmhurst-vs-spec divergence, add §8.3.