docs: extend handover with Elmhurst-only path + 000565 extended test case

User clarified end-of-session: mapper is a thin enum-and-shape
translation; when residuals remain after closing mapper coverage
gaps, the gap is in the **calculator cascade**. This unlocks an
Elmhurst-only fixture path that doesn't need API JSON at all.

The fixture shape mirrors the 6 historical Elmhurst U985 fixtures
(000474, 000477, 000480, 000487, 000490, 000516) at
`domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_NNNNNN.py`
+ `test_e2e_elmhurst_sap_score.py`:

  build_epc() → cert_to_inputs → calculate_sap_from_inputs
  ↳ every SapResult field pinned at abs=1e-4 against U985 line refs

Any failing pin is definitionally a calculator bug. The user generates
certs in Elmhurst SAP and exports Summary + worksheet ZIPs — no gov.uk
EPB lodgement required.

Extended test case (000565) ready at `sap worksheets/extended test case/`:
- Summary_000565.pdf (input)
- U985-0001-000565.pdf (worksheet ground-truth)

Cert 000565 is a wacky stress-test that exercises 3-4 zero-coverage
cascade paths in one cert: Main + 4 extensions, age mix A through J,
RR on every part with mixed ages, conservatory with fixed heaters,
curtain-wall Ext2 post-2023, mixed wall types (solid brick + stone +
curtain wall), mixed party walls (CU + CF + Unable to determine).

After this cert lands, the user has agreed to generate single-feature
certs (oil only, LPG only, solid fuel only, electric direct only,
multi-main-heating, basement) to surface single-cause calculator gaps.

Handover doc now has implementation outline (mirror
_elmhurst_worksheet_000474.py shape) and a coverage-paths table
showing which targets each fuel-type/config exercises.
This commit is contained in:
Khalim Conn-Kowlessar 2026-05-28 21:03:23 +00:00 committed by Jun-te Kim
parent 33293b0942
commit dae17a6d39

View file

@ -150,6 +150,102 @@ When grabbing certs from the data dump, filter by `main_heating[0].description`
- `Electric storage heaters` / `Direct-acting electric heaters`
- `Community scheme`
## ★★ Elmhurst-only path (calculator gap closure WITHOUT API JSON)
**User insight from end of session:** the mapper is a thin pass-through;
when residuals remain after closing mapper gaps (cohort-2 → golden),
the gap is in the **calculator cascade**, not the mapper. For
calculator gaps, the API JSON is not load-bearing — only the Elmhurst
Summary PDF (input) and the worksheet PDF (ground-truth line refs) are
needed.
This is a different fixture shape from the cohort-2 + ASHP path. It
mirrors the **6 original Elmhurst U985 fixtures** (000474, 000477,
000480, 000487, 000490, 000516) — the historical worksheet-pinned test
vectors at `domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_NNNNNN.py`
+ `test_e2e_elmhurst_sap_score.py`. No API JSON in the loop.
### Concrete next-target: the extended test case at `sap worksheets/extended test case/`
```
sap worksheets/extended test case/
Summary_000565.pdf ← input lodgement (Elmhurst RdSAP10 PDF)
U985-0001-000565.pdf ← worksheet output (line refs ground-truth)
```
Cert 000565 is a **wacky stress-test cert** (user-supplied) that exercises
many cascade paths absent from the cohort-2 + ASHP corpus:
- **5 building parts**: Main + 4 extensions (vs cohort max 2 extensions)
- **Age mix**: Main A (pre-1900), Ext1 E (1967-75), Ext2 H (1991-95),
Ext3 I (1996-2002), Ext4 J (2003-06) — spans 100+ years of construction
- **Room-in-roof on every part** at different ages (H, I, J, I, M)
- **Conservatory** thermally separated WITH fixed heaters (zero coverage
elsewhere)
- **Wall variety**:
- Main: Solid Brick + 75mm External insulation + Alt Wall Stone granite (23 m² with 120mm As Built + dry-lining)
- Ext1: Stone granite, U Unknown, **Cavity filled** party wall
- Ext2: **Curtain Wall Post 2023** (zero coverage)
- …
- **Party walls**: CU Cavity unfilled (Main), CF Cavity filled (Ext1), U Unable to determine (Ext2)
- **Multi-storey extensions** with floor 0/1 having varying room heights
(1.0 m to 4.0 m) and party_wall_length (0 to 23 m)
Every uncommon cascade path the cohort-2 + ASHP fixtures don't exercise
will light up against this cert.
### Implementation outline (mirror the existing pattern)
1. **Hand-build a `_elmhurst_worksheet_000565.py` module** under
`domain/sap10_calculator/worksheet/tests/`. Pattern is exactly the
shape of `_elmhurst_worksheet_000474.py`:
- `build_epc() -> EpcPropertyData` — hand-construct the EpcPropertyData
from the Summary_000565.pdf §1-19 lodgings. Use the existing
`make_minimal_sap10_epc`, `SapBuildingPart`, `SapFloorDimension`
etc. constructors.
- Module-level `LINE_NN_FOO: type = value` constants for every U985
line ref the test pins. Extract values from U985-0001-000565.pdf.
2. **Register the fixture in `test_e2e_elmhurst_sap_score.py`**:
- Add `from . import _elmhurst_worksheet_000565 as _w000565` import.
- Add `"000565": FixtureCascadePins(sap_score=..., sap_score_continuous=..., ...)` entry to `_FIXTURE_PINS`.
- Add `"000565": _w000565` entry to `_FIXTURE_MODULES`.
- The parametrized `test_sap_result_pin[000565-FIELD]` test cases fire automatically.
3. **Per [[feedback-e2e-validation-philosophy]] + [[feedback-zero-error-strict]]**:
- Tolerances are `abs=1e-4` on every field. No widening, no xfail.
- Failing pins are **named calculator bugs to fix**, not tolerances
to relax. Each failing pin is its own slice.
### Why this path is more powerful than API-route closure for calculator gaps
| API-route closure | Elmhurst-only path |
|---|---|
| Cert needs both API JSON AND worksheet | Cert needs only Summary + worksheet PDFs |
| Tests run via `from_api_response → cert_to_inputs → calculator` — failure could be mapper OR calculator | Tests run via `build_epc() → cert_to_inputs → calculator` — failure is **definitionally** a calculator bug |
| Cohort acquisition: gov.uk EPB JSON + assessor's worksheet ZIP | Cohort acquisition: assessor's tool export only (Elmhurst SAP) |
| Cross-mapper parity is a 2nd-order check on top of cascade correctness | Direct cascade correctness check |
For diverse fuel-type / property-type calculator coverage, the user can
generate test certs in Elmhurst SAP without needing to lodge them at
gov.uk first. **Targets to generate** for closure on currently-zero-
coverage paths:
| Fuel / config | Why critical | Cascade paths exercised |
|---|---|---|
| Oil boiler PCDB-listed (Firebird etc.) | Closes cert 0240 + 0390 oil residuals; no current oil worksheet | Table 105 oil + oil-tariff fuel cost + oil CO2/PE factors |
| Solid fuel (anthracite, wood pellets, biomass) | Zero coverage | Table 32 solid-fuel branch + solid-fuel CO2/PE factors |
| LPG | Zero coverage | Table 32 LPG branch + LPG-specific tariff lookup |
| Electric direct-acting / storage heaters | Zero coverage; off-peak meter path raises in cert_to_inputs | `_RDSAP_DEFINITELY_OFF_PEAK` dispatch (codes 1/4/5) + Table 12a high/low-rate split |
| Multi-main-heating (main 1 + main 2) | Currently un-exercised — `main_2_fuel_kwh_per_yr` cascade is dormant | Per-main efficiency + per-main fuel cost + summed PE |
| Basement | Minimal coverage | `u_basement_wall` + `u_basement_floor` Table 23 dispatch |
| Conservatory with fixed heaters | Zero coverage | Conservatory exclusion / inclusion rule + heated-conservatory fuel routing |
The wacky 000565 cert exercises 3-4 of these in one shot (multi-
extension + multi-age + conservatory + curtain wall). After it lands,
the user can generate single-feature certs (one oil cert, one LPG cert,
etc.) to isolate single-cause calculator gaps.
## Strict-raise pattern (S0380.51) — extension queue
The `UnmappedApiCode` strict-raise pattern is established in