docs: handover post S0380.177..179 + CI/test-move infra

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>
This commit is contained in:
Khalim Conn-Kowlessar 2026-06-02 17:21:50 +00:00
parent af8e0d9485
commit ba2d6e1cbb

View file

@ -0,0 +1,172 @@
# 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`](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):
```bash
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:**
1. `load_cells` tests (`tests/domain/sap10_calculator/worksheet/test_{dimensions,ventilation,water_heating}.py`) pin against the gitignored `2026-05-19-17-18 RdSap10Worksheet.xlsx` at repo root. `_xlsx_loader.load_cells` `pytest.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).
2. **Uncommitted `pytest.ini` change** (came in with a main pull) REMOVES `tests/` + `domain/sap10_ml/tests` from `testpaths`. HEAD has them; the working tree strips them. This is NOT a slice change — confirm with the user before committing it, because removing `tests/` 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_category` and `sap_main_heating_code`**
— the Elmhurst mapper leaves `category=None` on 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`](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.
## Good luck.