mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
docs: handover + next-agent prompt post S0380.77..80 (cert 000565 §4 HW EXACT)
Documents the full §4 HW cascade closure for cert 000565 across the S0380.77 → S0380.80 series: - S0380.77 primary loss WHC 914 routing - S0380.78 §1x.0 shower extractor + (247a) fallback cost - S0380.79 (57)m solar storage + separately-timed-DHW cylinder default - S0380.80 Table 4c −5% DHW for missing boiler interlock Cumulative cert 000565 closure: hot_water_kwh: +1399 → ✓ 0 EXACT (100%) continuous SAP: +0.78 → -0.041 (95% closed) total cost: -69 → +3.62 (95% closed) All §4 line refs (45)/(46)/(57)/(59)/(62)/(64)/(217)/(219) EXACT Open #1 priority for the next agent: deferred ADR-0010 mains-gas tariff Table 32 vs Table 12 cohort closure. The remaining sap_score=28 vs worksheet 29 flip is entirely due to this £0.16/100 gas-price delta over 3755 HW kWh = +£6 → +0.041 continuous SAP → flips integer at the 28.5 boundary. Cohort-wide change; would land sap_score=29 EXACT for cert 000565 AND likely tighten several other worksheet certs in the same coordinated pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
afa8d9451d
commit
8608ea0d8e
2 changed files with 601 additions and 0 deletions
403
domain/sap10_calculator/docs/HANDOVER_POST_S0380_80.md
Normal file
403
domain/sap10_calculator/docs/HANDOVER_POST_S0380_80.md
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
# Handover — post S0380.77..80 + cert 000565 §4 HW cascade fully spec-correct
|
||||
|
||||
Branch: `feature/per-cert-mapper-validation`. **HEAD `760a893c`**.
|
||||
Predecessor: [`HANDOVER_POST_S0380_76.md`](HANDOVER_POST_S0380_76.md).
|
||||
|
||||
## Slices committed this session (S0380.77..80)
|
||||
|
||||
Four spec-cited slices closed the entire §4 HW cascade for cert 000565 from
|
||||
+1399 kWh HW pin to **EXACT**.
|
||||
|
||||
| Slice | Commit | Spec | Cert 000565 closure |
|
||||
|---|---|---|---|
|
||||
| **S0380.77** | `a33904c5` | SAP 10.2 §4 line 7700 + Table 3 (p.159) — primary loss applies to the heat generator that feeds the cylinder, not the space-heating main. WHC 914 routes the gate to the DHW main. | (59)m EXACT |
|
||||
| **S0380.78** | `509ef4fb` | SAP 10.2 Appendix J §J2 step 2a (p.81) bath formula + §10a line (247a) (p.145) electric-shower cost. Coupled fixes: §1x.0 section-bounded shower extractor + (247a) added to fallback `total_cost`. | (45)m EXACT |
|
||||
| **S0380.79** | `f9551355` | SAP 10.2 §4 line 7693 (p.137) `(57)m = (56)m × (V−Vs)/V` solar adjustment + Table 2b note b) + RdSAP §3 (p.57) `_separately_timed_dhw=True` when cylinder lodged. | (57)m EXACT, (62)m EXACT |
|
||||
| **S0380.80** | `760a893c` | SAP 10.2 Table 4c (p.169) "No boiler interlock — regular boiler: DHW −5%" + RdSAP §3 (p.57) boiler interlock definition. Combi-fed cylinder + cyl-stat absent → −5pp DHW efficiency. | **hot_water_kwh EXACT** |
|
||||
|
||||
**Test baseline at HEAD `760a893c`:** 551 pass + 9 expected
|
||||
`test_sap_result_pin[000565-*]` cascade-gap fails. Pyright net-zero on every
|
||||
touched file.
|
||||
|
||||
## Cert 000565 state (HEAD `760a893c`)
|
||||
|
||||
| Pin | Cascade | Worksheet | Δ | Cause |
|
||||
|---|---:|---:|---:|---|
|
||||
| **sap_score (int)** | **28** | **29** | **−1** | Rounding boundary; continuous SAP 28.4680 lands 0.041 below 28.5 cutoff |
|
||||
| sap_score_continuous | 28.4680 | 28.5087 | −0.041 | Downstream of total_cost +£3.62 (deferred ADR-0010 gas tariff) |
|
||||
| ecf | 5.3910 | 5.3866 | +0.004 | Downstream of total_cost |
|
||||
| total_fuel_cost_gbp | 4683.88 | 4680.26 | +3.62 | **Deferred ADR-0010 gas tariff** (Table 12 £0.0364 vs Table 32 £0.0348) |
|
||||
| co2_kg_per_yr | 6438.71 | 6447.63 | −8.92 | Lighting + Main-1 small CO2 factor residual |
|
||||
| **space_heating_kwh** | **58936.06** | **59008.35** | **−72.29** | **RR fold-in (RdSAP §3.10 detailed-RR geometry)** |
|
||||
| main_heating_fuel | 34668.27 | 34710.79 | −42.52 | Follows space_heating via 1/COP |
|
||||
| **hot_water_kwh** | **3755.03** | **3755.03** | **✓ 0 EXACT** | §4 cascade fully closed |
|
||||
| lighting | 1387.02 | 1384.84 | +2.19 | Sub-spec |
|
||||
| pumps_fans | 255.00 | 252.52 | +2.48 | MEV PCDB record missing |
|
||||
|
||||
### §4 HW cascade line refs all EXACT
|
||||
|
||||
| Line | Cascade | Worksheet | Δ |
|
||||
|---|---:|---:|---:|
|
||||
| (45)m sum energy_content | 1286.3266 | 1286.3266 | ✓ 0 |
|
||||
| (46)m sum distribution_loss | 192.9490 | 192.95 | ✓ <1e-3 |
|
||||
| (57)m sum solar_storage | 596.9725 | 596.9725 | ✓ <1e-4 |
|
||||
| (59)m sum primary_loss | 1176.77 | 1174.79 | +1.98 (sub-2 kWh rounding) |
|
||||
| (61)m combi_loss | 0.00 | 0.00 | ✓ 0 |
|
||||
| (62)m sum total_demand | 3060.07 | 3060.07 | ✓ <1e-3 |
|
||||
| (64)m sum (after solar) | 2778.72 | 2778.7213 | ✓ <1e-4 |
|
||||
| (64a)m electric shower | 702.94 | 702.94 | ✓ <1e-4 |
|
||||
| (217)m water-heater eff | 0.74 | 0.74 | ✓ EXACT |
|
||||
| (219) HW fuel kWh | 3755.03 | 3755.0288 | ✓ <1e-3 |
|
||||
|
||||
The §4 line-by-line trace is the most diagnostically transparent state cert
|
||||
000565 has been in. Any future cascade refactor should be validated by
|
||||
checking each line stays EXACT, not just the SapResult-level pins.
|
||||
|
||||
## Slice S0380.77 — primary loss WHC 914 routing
|
||||
|
||||
**Bug:** `_primary_loss_override(epc, main, primary_age)` was called with
|
||||
`main = _first_main_heating(epc)` (Main 1 = HP for cert 000565). The
|
||||
`_primary_loss_applies` gate then keyed off the HP's category = None,
|
||||
returned False, and (59)m was zeroed despite the cert having an external
|
||||
cylinder fed by Main 2 (gas combi).
|
||||
|
||||
**Spec:** SAP 10.2 §4 line 7700 + Table 3 (PDF p.159):
|
||||
|
||||
> Primary circuit loss applies when hot water is heated by a heat generator
|
||||
> (e.g. boiler) connected to a hot water storage vessel via insulated or
|
||||
> uninsulated pipes (the primary pipework).
|
||||
|
||||
The eligibility is determined by the heat generator that feeds the
|
||||
cylinder — for cert 000565 that's Main 2 (gas combi via WHC 914), not
|
||||
Main 1 (HP).
|
||||
|
||||
**Fix:** `_primary_loss_override` resolves its `main` via
|
||||
`_water_heating_main(epc)` (the WHC-914 resolver) rather than
|
||||
`_first_main_heating`. Signature drops the `main` parameter.
|
||||
|
||||
Test: `test_whc_914_dhw_routes_primary_loss_gate_to_second_main_heating_per_sap_table_3`.
|
||||
|
||||
## Slice S0380.78 — §1x.0 shower extractor + (247a) fallback cost
|
||||
|
||||
**Bug A (extractor):** `_extract_baths_and_showers` used
|
||||
`self._lines.index("Connected")` (global search) to anchor the shower
|
||||
roster. Cert 000565 lodges 4 extensions whose §3 building-parts list
|
||||
contains "Connected" / "Exposed" / "Sheltered" wall elevation flags
|
||||
earlier in the document. The global match landed on a wall row; the
|
||||
digit-check `num_line.isdigit()` failed on "0.00" and the shower list
|
||||
came back empty.
|
||||
|
||||
**Bug B (calculator fallback):** `calculator.py` STANDARD-tariff path
|
||||
already plumbed `instant_shower_cost_gbp` via `fuel_cost(...)`. The
|
||||
fallback scalar path for TEN_HOUR / `_ZERO_FUEL_COST_RESULT` certs was
|
||||
silently dropping `electric_shower_kwh × other_fuel_cost` from total
|
||||
cost. Cert 000565 (Dual-meter TEN_HOUR + 1 electric shower) trips this
|
||||
branch — fix A surfaced the £93/yr under-count.
|
||||
|
||||
**Spec:**
|
||||
- SAP 10.2 Appendix J §J2 step 2a (p.81): `N_bath = 0.13 N + 0.19` when
|
||||
shower also present; `0.35 N + 0.50` when no shower. 2.7× swing.
|
||||
- SAP 10.2 §10a (p.145): `Energy for instantaneous electric shower(s)
|
||||
(64a) × 0.01 = (247a)` — feeds (255) total cost.
|
||||
|
||||
**Fixes:**
|
||||
- `_extract_baths_and_showers` routes the "Connected" lookup through
|
||||
`_section_lines("1x.0 Baths and Showers", "18.0 Flue Gas Heat Recovery
|
||||
System")`. Both anchors are single-occurrence in the Elmhurst Summary
|
||||
PDF schema.
|
||||
- `calculator.py` fallback `total_cost` adds
|
||||
`inputs.electric_shower_kwh_per_yr × inputs.other_fuel_cost_gbp_per_kwh`.
|
||||
|
||||
Tests:
|
||||
- `test_summary_000565_extractor_finds_electric_shower_in_section_1x_0`
|
||||
- `test_total_fuel_cost_includes_247a_electric_shower_in_fallback_path`
|
||||
|
||||
### Why coupled
|
||||
|
||||
Splitting the fixes would flip sap_score from 29 → 30 mid-state: the
|
||||
extractor fix corrects (45)m to EXACT but exposes (64a) electric-shower
|
||||
kWh, which without (247a) cost flow makes total_cost too low → ECF too
|
||||
low → SAP rating too high. Bundling keeps sap_score within rounding.
|
||||
|
||||
## Slice S0380.79 — (57)m solar storage + separately_timed_dhw cylinder default
|
||||
|
||||
**Bug A:** `_cylinder_storage_loss_override` returned raw (56)m as
|
||||
`solar_storage_monthly_kwh_override`. SAP 10.2 §4 (62)m formula uses
|
||||
(57)m (the solar-adjusted storage loss), not (56)m. For cert 000565 with
|
||||
solar HW + combined cylinder, (62)m was over-counting by
|
||||
(56)m × Vs/V ≈ 395 kWh/yr.
|
||||
|
||||
**Bug B:** `_separately_timed_dhw` gated only on
|
||||
`main.main_heating_category == 4` (heat pumps), returning False for
|
||||
boiler-family + cylinder configs. Cert 000565 (gas combi + cylinder +
|
||||
no cyl-stat) fell through to TF = 0.78; worksheet uses 0.702 (with the
|
||||
0.9 multiplier for separately-timed DHW). 10% TF over-count drove
|
||||
+98 kWh into (56)m.
|
||||
|
||||
**Spec:**
|
||||
- SAP 10.2 §4 line 7693 (p.137):
|
||||
```
|
||||
If the vessel contains dedicated solar storage or dedicated WWHRS
|
||||
storage, (57)m = (56)m × [(47) - Vs] ÷ (47), else (57)m = (56)m
|
||||
where Vs is Vww from Appendix G3 or (H12) from Appendix H.
|
||||
```
|
||||
- SAP 10.2 Table 2b note b) (p.159): "Multiply Temperature Factor by 0.9
|
||||
if there is separate time control of domestic hot water (boiler
|
||||
systems, warm air systems and heat pump systems)".
|
||||
- RdSAP 10 §3 (p.57) default table "Hot water separately timed":
|
||||
```
|
||||
No programmer, pre-1998 boiler: - No
|
||||
Programmer, pre-1998 boiler: - Yes
|
||||
Post-1998 boiler: - Yes
|
||||
```
|
||||
|
||||
**Fixes:**
|
||||
- `_cylinder_storage_loss_override`: when `epc.solar_water_heating`,
|
||||
return `(56)m × (V−Vs)/V`. Vs = `round(volume_l × ⅓)` per S0380.76's
|
||||
combined-cylinder convention.
|
||||
- `_separately_timed_dhw(epc, main)`: signature gains `epc`; returns
|
||||
True when a cylinder is lodged in addition to the existing HP branch.
|
||||
|
||||
Tests:
|
||||
- `test_cylinder_storage_loss_applies_57m_solar_adjustment_per_sap_4_line_7693`
|
||||
|
||||
### Cross-cohort impact — cert 0390 pin update
|
||||
|
||||
Golden cert `0390-2954-3640-2196-4175` (Firebird oil combi PCDF 9005 +
|
||||
160 L cylinder + cyl-stat=Y) was previously flagged at SAP residual −7
|
||||
with the comment "traces to fabric heat-loss / oil-fuel cost cascade
|
||||
rather than the §4 HW path". That diagnosis was wrong: cert 0390's §4
|
||||
HW cascade WAS applying TF = 0.60 instead of TF = 0.54 — `cyl-stat=Y`
|
||||
+ programmer-present default → separately_timed=True per RdSAP §3,
|
||||
which the cohort heuristic was missing. Pin updated −7 → −6 per
|
||||
[[feedback-golden-residuals-near-zero]].
|
||||
|
||||
## Slice S0380.80 — Table 4c −5% DHW for missing boiler interlock
|
||||
|
||||
**Bug:** Cascade water-efficiency for cert 000565 used PCDB summer η =
|
||||
79% directly. Worksheet uses (217)m = 74%. Investigation in this
|
||||
session resolved the −5pp gap to SAP 10.2 Table 4c.
|
||||
|
||||
**Spec:** SAP 10.2 Table 4c (p.169-170):
|
||||
```
|
||||
(2) Efficiency adjustment due to control system Space DHW
|
||||
No boiler interlock - regular boiler (...) −5 −5
|
||||
No boiler interlock - combi −5 0
|
||||
Note c): These do not accumulate as no thermostatic control or
|
||||
presence of a bypass means that there is no boiler interlock.
|
||||
```
|
||||
|
||||
RdSAP 10 §3 (p.57) "Boiler interlock" definition:
|
||||
> Assumed present if there is a room thermostat and (for stored hot
|
||||
> water systems heated by the boiler) a cylinder thermostat. Otherwise
|
||||
> not interlocked.
|
||||
|
||||
A PCDB-listed boiler feeding a cylinder without a cylinder thermostat
|
||||
has no boiler interlock → −5pp DHW. A combi-fed cylinder routes the
|
||||
boiler as a regular boiler for the DHW circuit (instantaneous-DHW
|
||||
capability is bypassed), so the regular-boiler row (DHW −5%) applies.
|
||||
|
||||
**Fix:** `cert_to_inputs.py` water-efficiency branch:
|
||||
```python
|
||||
if (
|
||||
epc.has_hot_water_cylinder
|
||||
and epc.sap_heating.cylinder_thermostat != "Y"
|
||||
and water_pcdb_main is not None
|
||||
):
|
||||
water_eff -= 0.05
|
||||
```
|
||||
|
||||
Test:
|
||||
`test_table_4c_no_boiler_interlock_applies_minus_5_dhw_adjustment_when_cylinder_lodged_without_thermostat`.
|
||||
|
||||
**Effect on other certs:**
|
||||
- Combi-only certs (no cylinder): condition fails → no change.
|
||||
- ASHP cohort certs: water_pcdb_main is None (HP not in Table 105) →
|
||||
no change.
|
||||
- Boiler + cylinder + cyl-stat=Y certs (e.g. cert 0390): cyl-stat
|
||||
present → condition fails → no change.
|
||||
- Boiler + cylinder + cyl-stat=N + PCDB Table 105 record: −5% applies.
|
||||
Only cert 000565 in the current test suite has this shape.
|
||||
|
||||
## Why sap_score=28 (not 29) at HEAD `760a893c`
|
||||
|
||||
S0380.80 closes the cascade to spec-correct values. The remaining
|
||||
deviation is a documented **deferred** gap:
|
||||
|
||||
```
|
||||
worksheet HW cost = 3755.0288 × £0.0348/kWh = £130.6750 (RdSAP Table 32)
|
||||
cascade HW cost = 3755.0288 × £0.0364/kWh = £136.6831 (SAP 10.2 Table 12)
|
||||
----------
|
||||
Δ = +£6.01
|
||||
```
|
||||
|
||||
The £0.16/100 gas-price delta inflates HW cost by ~£6, exactly the
|
||||
total_fuel_cost residual (+£3.62 net after smaller offsets) AND the
|
||||
continuous SAP deviation (+0.041). ECF = cost / (TFA + 45) is the
|
||||
forcing function: lower cost → higher SAP rating; higher cost → lower
|
||||
SAP rating. The cascade is pricing UP, so SAP rating drops below the
|
||||
28.5 integer boundary.
|
||||
|
||||
**Fix is the deferred ADR-0010 cohort-wide repricing**, not a single-
|
||||
cert patch (see Open thread #6 below).
|
||||
|
||||
After ADR-0010 lands, projected cert 000565 sap_score = **29 ✓ EXACT**
|
||||
(continuous projected at ≈ 28.51, well within rounding of worksheet
|
||||
28.5087).
|
||||
|
||||
## Open work — prioritised next slices
|
||||
|
||||
### #1 (largest) — ADR-0010 mains gas tariff Table 32 vs Table 12
|
||||
|
||||
**Magnitude:** Cohort-wide. For cert 000565: +£3.62 cost → +0.041
|
||||
continuous SAP → flips sap_score 29→28. For other gas-DHW certs: similar
|
||||
order-of-magnitude.
|
||||
|
||||
**Cascade:** Uses SAP 10.2 Table 12 prices (£0.0364/kWh mains gas).
|
||||
Worksheet uses RdSAP 10 Table 32 (£0.0348/kWh).
|
||||
|
||||
**Tractability:** Requires ADR-0010 amendment + coordinated cohort re-
|
||||
pin (every golden + Elmhurst worksheet cert's pinned cost shifts). NOT
|
||||
a single-cert slice.
|
||||
|
||||
**Suggested approach:**
|
||||
1. Read ADR-0010 to understand the current price-table decision and
|
||||
what's blocking the switch to Table 32.
|
||||
2. Identify which Elmhurst worksheets in the cohort actually use
|
||||
Table 32 (the U985 ones definitely do).
|
||||
3. Stand up a parallel `RDSAP10_TABLE_32_PRICES` constant alongside
|
||||
`SAP_10_2_SPEC_PRICES`.
|
||||
4. Re-pin all golden + Elmhurst e2e expectations under Table 32.
|
||||
5. ADR-0010 amendment commit that frames the policy decision.
|
||||
|
||||
This is the highest-leverage single change for the Elmhurst worksheet
|
||||
cohort. After this lands, cert 000565 → sap_score 29 EXACT, plus
|
||||
likely several other open-residual certs close.
|
||||
|
||||
### #2 — RR (room-in-roof) fold-in for cert 000565 space_heating −72
|
||||
|
||||
**Magnitude:** −72 kWh space_heating (cert 000565) → −42 kWh
|
||||
main_heating_fuel via 1/COP.
|
||||
|
||||
**Cascade:** Doesn't fully implement RdSAP §3.10 detailed-RR geometry
|
||||
+ area formula. Cert 000565 has RR on every part (5 BPs) with detailed
|
||||
gable wall lengths, slopes, common walls.
|
||||
|
||||
**Tractability:** Single-cert slice, but needs spec-citation work in
|
||||
the heat_transmission cascade. The detailed-RR area formula is in
|
||||
RdSAP §3.10 (PDF p.30-35, "Room in roof").
|
||||
|
||||
### #3 — Lighting CO2 factor Δ−0.0025 (tariff-blended Table 12d)
|
||||
|
||||
**Magnitude:** −3.16 kg CO2 (lighting) and similar Δ−0.0025 on
|
||||
pumps_fans CO2 factor. Same cause: cascade uses code 30 (standard
|
||||
electricity) Table 12d factors; worksheet uses TEN_HOUR Grid 1 blend
|
||||
of codes 33 (10h low) + 34 (10h high).
|
||||
|
||||
**Cascade:** `lighting_co2_factor_kg_per_kwh=_effective_monthly_co2_factor(
|
||||
lighting_monthly_kwh, _STANDARD_ELECTRICITY_FUEL_CODE)` at
|
||||
`cert_to_inputs.py:4054`. Same shape for pumps_fans at line 4050.
|
||||
|
||||
**Tractability:** Clean spec citation. Mirror what S0380.65 did for
|
||||
main_heating_co2_factor (Table 12a Grid 1 high/low blend) for lighting
|
||||
and pumps_fans. Only affects off-peak tariff certs (cert 000565 is the
|
||||
only Elmhurst worksheet fixture on Dual-meter; cohort-2 has some).
|
||||
|
||||
### #4 — MEV pumps_fans +2.48 (PCDB MEV table missing)
|
||||
|
||||
**Magnitude:** +2.48 kWh pumps_fans (cert 000565). PCDB MEV record
|
||||
table not in the repo (cert lodges PCDF 500755). External-data
|
||||
acquisition gates this; not solvable in code.
|
||||
|
||||
### #5 — HP SAP code → main_heating_category=4 in mapper
|
||||
|
||||
Cert 000565 Main 1 has sap_main_heating_code=224 but no PCDB Table 362
|
||||
ref → mapper sets category=None. The TODO in
|
||||
`mapper.py:_elmhurst_main_heating_category` says this is deferred
|
||||
because of HP-on-E7 cost cascade + Table 4f MEV component coupling.
|
||||
Now that S0380.80 has surfaced the cleaner cascade, the coupling cost
|
||||
analysis can be redone. Couples with #4 (MEV).
|
||||
|
||||
### #6 — 12 gas-combi PV certs at +0.5..+1.6 PE
|
||||
|
||||
Unchanged from prior handover. No worksheets available; re-pinned at
|
||||
current residuals.
|
||||
|
||||
### #7 — 5 SAP-integer-residual certs
|
||||
|
||||
Unchanged. All API-only (no worksheets). User has agreed not to chase
|
||||
these without worksheet ground truth.
|
||||
|
||||
## How to run the baseline
|
||||
|
||||
```bash
|
||||
PYTHONPATH=/workspaces/model python -m pytest \
|
||||
backend/documents_parser/tests/test_summary_pdf_mapper_chain.py \
|
||||
backend/documents_parser/tests/test_elmhurst_extractor.py \
|
||||
backend/documents_parser/tests/test_elmhurst_end_to_end.py \
|
||||
domain/sap10_calculator/worksheet/tests/test_e2e_elmhurst_sap_score.py \
|
||||
domain/sap10_calculator/worksheet/tests/test_appendix_h_solar.py \
|
||||
domain/sap10_calculator/rdsap/tests/test_cert_to_inputs.py \
|
||||
domain/sap10_calculator/rdsap/tests/test_golden_fixtures.py \
|
||||
--no-cov -q
|
||||
```
|
||||
|
||||
Expected: **551 pass + 9 expected `test_sap_result_pin[000565-*]` fails**
|
||||
at HEAD `760a893c`.
|
||||
|
||||
The 9 expected fails (verbatim from the latest run):
|
||||
```
|
||||
sap_score
|
||||
sap_score_continuous
|
||||
ecf
|
||||
total_fuel_cost_gbp
|
||||
co2_kg_per_yr
|
||||
space_heating_kwh_per_yr
|
||||
main_heating_fuel_kwh_per_yr
|
||||
lighting_kwh_per_yr
|
||||
pumps_fans_kwh_per_yr
|
||||
```
|
||||
|
||||
`hot_water_kwh_per_yr` was the 10th fail in baselines `a532f75d` through
|
||||
`f9551355`; now passes at HEAD `760a893c`.
|
||||
|
||||
## Files touched this session
|
||||
|
||||
| File | Slices | Change |
|
||||
|---|---|---|
|
||||
| `backend/documents_parser/elmhurst_extractor.py` | S0380.78 | `_extract_baths_and_showers` uses `_section_lines("1x.0 Baths and Showers", "18.0 Flue Gas Heat Recovery System")` instead of `self._lines.index("Connected")` |
|
||||
| `backend/documents_parser/tests/test_summary_pdf_mapper_chain.py` | S0380.78 | New test `test_summary_000565_extractor_finds_electric_shower_in_section_1x_0` |
|
||||
| `domain/sap10_calculator/calculator.py` | S0380.78 | Fallback scalar `total_cost` adds `electric_shower_kwh × other_fuel_cost` |
|
||||
| `domain/sap10_calculator/tests/test_calculator.py` | S0380.78 | New test `test_total_fuel_cost_includes_247a_electric_shower_in_fallback_path` |
|
||||
| `domain/sap10_calculator/rdsap/cert_to_inputs.py` | S0380.77, S0380.79, S0380.80 | `_primary_loss_override` resolves DHW main internally; `_separately_timed_dhw(epc, main)` cylinder-default; `_cylinder_storage_loss_override` applies (57)m solar adjustment; water_eff `−= 0.05` for Table 4c boiler-interlock |
|
||||
| `domain/sap10_calculator/rdsap/tests/test_cert_to_inputs.py` | S0380.77, S0380.79, S0380.80 | 3 new tests pinning the spec rules above |
|
||||
| `domain/sap10_calculator/rdsap/tests/test_golden_fixtures.py` | S0380.79 | Cert 0390 pin updated −7 → −6 with revised notes citing S0380.79 |
|
||||
|
||||
## Spec source quick-reference
|
||||
|
||||
- **SAP 10.2 full specification**: `domain/sap10_calculator/docs/specs/sap-10-2-full-specification-2025-03-14.pdf`
|
||||
- Appendix J §J2 step 2a (bath formula): p.81
|
||||
- §4 (45)..(65) HW worksheet: p.135-137
|
||||
- §4 line 7693 (57)m solar adjustment: p.137
|
||||
- §4 line 7700 + Table 3 (primary loss): p.159
|
||||
- §10a (245)..(255) cost worksheet: p.145
|
||||
- Table 2 (HW storage loss factor): p.158
|
||||
- Table 2b (HW storage loss temperature factor + notes a/b): p.159
|
||||
- Table 3 (primary circuit loss): p.159
|
||||
- Table 3a (combi loss): p.160
|
||||
- Table 4b (gas/oil boiler seasonal efficiency): p.168
|
||||
- Table 4c (efficiency adjustments — boiler interlock, etc.): p.169-170
|
||||
- Appendix D2.1 (using PCDB efficiency values): p.57
|
||||
- Appendix D2.2 (condensing boiler corrections): p.58
|
||||
- **RdSAP 10 specification**: `domain/sap10_calculator/docs/specs/RdSAP 10 Specification 10-06-2025.pdf`
|
||||
- §3 default table (boiler interlock, separately timed DHW, pipework insulation): p.57
|
||||
- §10.11 Table 29 (solar panel defaults): p.58
|
||||
- **S10TP-12** (BRE seasonal efficiency of condensing boilers): `domain/sap10_calculator/docs/specs/sap10 technical papers/S10TP-12 - Seasonal efficiency of condensing boilers - V1.2.pdf`
|
||||
- **SAP 10.3** at `domain/sap10_calculator/docs/specs/sap-10-3-full-specification-2026-01-13.pdf`: **DO NOT reference** (project tracks 10.2 only per [[feedback-sap-10-2-only-never-10-3]])
|
||||
|
||||
## Memory updated this session
|
||||
|
||||
- `project_cert_000565_recovery_state` — full S0380.77/78/79/80 history,
|
||||
cumulative closure table, attribution of remaining residuals to
|
||||
deferred ADR-0010 gas tariff
|
||||
- `MEMORY.md` — index entry refreshed
|
||||
198
domain/sap10_calculator/docs/NEXT_AGENT_PROMPT_POST_S0380_80.md
Normal file
198
domain/sap10_calculator/docs/NEXT_AGENT_PROMPT_POST_S0380_80.md
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
# Next-agent prompt — post S0380.80
|
||||
|
||||
Branch: `feature/per-cert-mapper-validation`.
|
||||
HEAD: `760a893c`.
|
||||
|
||||
Read these in order before any tool call:
|
||||
|
||||
1. [`HANDOVER_POST_S0380_80.md`](HANDOVER_POST_S0380_80.md) — full state
|
||||
2. [`HANDOVER_POST_S0380_76.md`](HANDOVER_POST_S0380_76.md) — Appendix H closure history (background reading; do not re-investigate)
|
||||
|
||||
Also load these memories before starting:
|
||||
|
||||
- `project_cert_000565_recovery_state` — cert 000565 slice history + current pin state
|
||||
- `project_golden_coverage_state` — cohort state
|
||||
- `feedback_sap_10_2_only_never_10_3` — **CRITICAL** — never reference SAP 10.3 spec
|
||||
- `feedback_verify_handover_claims` — verify spec citations before implementing
|
||||
- `feedback_spec_floor_skepticism` — "spec-precision floor" framing usually hides a real spec bug (S0380.80 confirmed this: the 79→74 mystery WAS a clean Table 4c spec rule, not a precision floor)
|
||||
- `feedback_zero_error_strict` — pyright net-zero per touched file
|
||||
- `feedback_commit_per_slice` — one slice = one commit
|
||||
- `feedback_spec_citation_in_commits` — quote spec text + page in commit messages
|
||||
- `feedback_aaa_test_convention` — every new test uses `# Arrange / # Act / # Assert`
|
||||
- `feedback_e2e_validation_philosophy` — component pins at <1e-3; SAP integer delta=0; no adaptive ceilings
|
||||
- `feedback_golden_residuals_near_zero` — pin updates on golden certs are the documented protocol when cascade closure surfaces real spec bugs
|
||||
|
||||
## State summary
|
||||
|
||||
**Cumulative session result:** Cert 000565's entire **§4 HW cascade is
|
||||
fully spec-correct**. `hot_water_kwh_per_yr` pin closed +1399 → **EXACT
|
||||
0** across S0380.77 / .78 / .79 / .80. Every §4 line ref (45)/(46)/(57)/
|
||||
(59)/(61)/(62)/(64)/(64a)/(217)/(219) matches the U985 worksheet at
|
||||
<1e-3.
|
||||
|
||||
The remaining cert 000565 deviation is **sap_score 28 vs worksheet 29**.
|
||||
This is **NOT a cascade bug** — it traces directly to the deferred
|
||||
ADR-0010 gas tariff (cascade uses SAP 10.2 Table 12 £0.0364/kWh; cohort
|
||||
worksheet uses RdSAP 10 Table 32 £0.0348/kWh). The +£3.62 cost residual
|
||||
× ECF arithmetic produces +0.041 continuous SAP, just enough to flip the
|
||||
integer at the 28.5 boundary.
|
||||
|
||||
| Pin | Δ kWh/yr | Root cause | Tractability |
|
||||
|---|---:|---|---|
|
||||
| sap_score | −1 (int) | Boundary artifact of total_cost +£3.62 | **Closes when ADR-0010 lands** |
|
||||
| sap_score_continuous | −0.041 | Downstream of total_cost | Closes when ADR-0010 lands |
|
||||
| ecf | +0.004 | Downstream | Closes when ADR-0010 lands |
|
||||
| total_fuel_cost_gbp | +£3.62 | **Deferred ADR-0010 gas tariff** | **#1 priority next slice** |
|
||||
| co2_kg | −8.92 | Lighting + main-1 small CO2 factor residual | #3 (clean spec) |
|
||||
| space_heating_kwh | −72.29 | RR fold-in (RdSAP §3.10 detailed-RR geometry) | #2 (single-cert, spec work) |
|
||||
| main_heating_fuel | −42.52 | Follows space_heating via 1/COP | Downstream of #2 |
|
||||
| **hot_water_kwh** | **✓ 0 EXACT** | §4 cascade fully closed | done |
|
||||
| lighting | +2.19 | Sub-spec | low priority |
|
||||
| pumps_fans | +2.48 | MEV PCDB record missing (external data) | blocked on data |
|
||||
|
||||
## Recommended next slice — ADR-0010 mains-gas tariff cohort closure
|
||||
|
||||
**This is the highest-leverage single change available.** Closes cert
|
||||
000565's last residual (sap_score 28 → 29 EXACT) AND likely tightens
|
||||
several other Elmhurst worksheet certs' pins in one coordinated pass.
|
||||
|
||||
### Audit steps
|
||||
|
||||
1. Read ADR-0010 to understand the current price-table decision and what
|
||||
blocked the original switch to Table 32. Look for any "we want to
|
||||
move to Table 32 once X" notes.
|
||||
2. Read RdSAP 10 Table 32 (PDF p.95) and SAP 10.2 Table 12 (PDF
|
||||
p.191-194). They differ in: mains gas price (Table 32: £0.0348/kWh;
|
||||
Table 12: £0.0364/kWh), oil prices, electricity prices.
|
||||
3. Verify worksheet-cohort certs use Table 32 prices by spot-checking
|
||||
3-5 worksheet (255) total cost lines.
|
||||
4. Identify the scope of the cascade change (search `SAP_10_2_SPEC_PRICES`
|
||||
usage; understand the PriceTable abstraction).
|
||||
|
||||
### Suggested implementation
|
||||
|
||||
1. Define `RDSAP_10_TABLE_32_PRICES` constant alongside
|
||||
`SAP_10_2_SPEC_PRICES` (file: `domain/sap10_calculator/tables/table_32.py`
|
||||
or similar — search for the existing definition).
|
||||
2. Switch the default `prices` argument on `cert_to_inputs` to the new
|
||||
Table 32 prices (per ADR-0010 amendment).
|
||||
3. Re-pin every golden cert in `test_golden_fixtures.py` and every
|
||||
Elmhurst U985 e2e expectation in `test_e2e_elmhurst_sap_score.py`.
|
||||
4. Write the ADR-0010 amendment commit with verbatim Table 32 prices
|
||||
+ the worksheet evidence.
|
||||
|
||||
### Expected outcome
|
||||
|
||||
Cert 000565 cost residual: +£3.62 → ≈ −£0.0 (or small offset)
|
||||
→ continuous SAP 28.4680 → ≈ 28.51
|
||||
→ **sap_score = 29 ✓ EXACT**
|
||||
→ 9 expected fails → 0 expected fails for cert 000565 except RR-related
|
||||
(space_heating_kwh, main_heating_fuel, downstream co2)
|
||||
|
||||
### Coordination
|
||||
|
||||
This is a cohort-wide change. ALL pins shift. Treat as one focused
|
||||
session: prep, single coordinated commit, audit cohort pins for
|
||||
unexpected regressions, ship.
|
||||
|
||||
If the user prefers smaller scope, an alternative ordering is:
|
||||
|
||||
1. Slice #3 first (lighting/pumps_fans Table 12d tariff blend — small
|
||||
isolated spec citation, no cohort coordination needed).
|
||||
2. Then ADR-0010 amendment as the bigger cohort closure.
|
||||
|
||||
## Alternative next slices (smaller scope)
|
||||
|
||||
### Slice option — lighting + pumps_fans tariff-blended CO2 factor
|
||||
|
||||
**Spec citation candidate:** SAP 10.2 Table 12a Grid 1 + Table 12d
|
||||
monthly factors. Mirror S0380.65's main_heating dual-rate blend for
|
||||
lighting + pumps_fans.
|
||||
|
||||
**Cascade gap:** At
|
||||
[`cert_to_inputs.py:4050-4056`](../rdsap/cert_to_inputs.py) the
|
||||
lighting + pumps_fans CO2 factors use `_STANDARD_ELECTRICITY_FUEL_CODE = 30`
|
||||
unconditionally. For TEN_HOUR / 7H_HEATING / off-peak certs these
|
||||
should blend Table 12d code 33 (low) + code 34 (high) by the Grid 1
|
||||
lighting/all-other fractions.
|
||||
|
||||
**Magnitude on cert 000565:** Δ−0.0025 factor → −3.16 kg CO2 (lighting)
|
||||
+ similar pumps_fans. Total CO2 closes from −8.92 → ≈ 0 (combined with
|
||||
small remaining lighting kWh residual).
|
||||
|
||||
**Tractability:** Single-slice, single-helper change. Doesn't touch
|
||||
cohort pins beyond CO2 (which moves toward worksheet).
|
||||
|
||||
### Slice option — RR fold-in for cert 000565 space_heating
|
||||
|
||||
**Magnitude:** −72 kWh space_heating → −42 kWh main_heating_fuel. Largest
|
||||
non-cost single residual on cert 000565.
|
||||
|
||||
**Spec:** RdSAP 10 §3.10 (PDF p.30-35, "Room in roof"). Cert 000565
|
||||
lodges 5 BPs (Main + 4 extensions) with RR detail on each. The cascade
|
||||
either doesn't fold every BP's RR or uses a simplified area formula.
|
||||
|
||||
**Tractability:** Spec work in `heat_transmission_section_from_cert` /
|
||||
related helpers. Probe cert 000565's per-BP RR area + heat-loss values
|
||||
vs worksheet line refs (8a) to (8d) per extension.
|
||||
|
||||
## What NOT to do
|
||||
|
||||
- **Don't re-investigate the Appendix H 1.81× over-count.** CLOSED in
|
||||
S0380.74. The U3.3 unit-convention fix is the correct answer.
|
||||
- **Don't re-investigate the (217)m 79→74 mystery.** CLOSED in S0380.80
|
||||
via SAP 10.2 Table 4c −5% DHW boiler-interlock rule. Spec citation is
|
||||
in the commit message + recovery memory.
|
||||
- **Don't widen pin tolerances or xfail residual gaps**
|
||||
([[feedback-zero-error-strict]]). The 9 cert 000565 fails are the
|
||||
work queue.
|
||||
- **Don't reference SAP 10.3** ([[feedback-sap-10-2-only-never-10-3]]).
|
||||
- **Don't chase the 12 gas-combi PV certs or the 5 SAP-residual certs
|
||||
without worksheets** — user has explicitly de-prioritised.
|
||||
- **Don't apply Table 4c −5% to certs without a PCDB Table 105 record.**
|
||||
The S0380.80 fix specifically gates on `water_pcdb_main is not None`.
|
||||
Table 4b fall-through certs already include the typical penalty in
|
||||
the table value.
|
||||
|
||||
## Standard workflow per slice
|
||||
|
||||
1. Read SAP 10.2 spec page for the change — quote it in commit
|
||||
2. Probe current cascade output, identify exact spec-vs-cascade gap
|
||||
3. Write failing test FIRST (AAA structure)
|
||||
4. Implement helper / change
|
||||
5. Verify test passes
|
||||
6. Run full handover suite (command below)
|
||||
7. Check pyright on touched files — net-zero from baseline
|
||||
8. Commit with spec citation
|
||||
9. Update relevant memory if state changed
|
||||
|
||||
## How to run the baseline
|
||||
|
||||
```bash
|
||||
PYTHONPATH=/workspaces/model python -m pytest \
|
||||
backend/documents_parser/tests/test_summary_pdf_mapper_chain.py \
|
||||
backend/documents_parser/tests/test_elmhurst_extractor.py \
|
||||
backend/documents_parser/tests/test_elmhurst_end_to_end.py \
|
||||
domain/sap10_calculator/worksheet/tests/test_e2e_elmhurst_sap_score.py \
|
||||
domain/sap10_calculator/worksheet/tests/test_appendix_h_solar.py \
|
||||
domain/sap10_calculator/rdsap/tests/test_cert_to_inputs.py \
|
||||
domain/sap10_calculator/rdsap/tests/test_golden_fixtures.py \
|
||||
--no-cov -q
|
||||
```
|
||||
|
||||
Expected: **551 pass + 9 expected `test_sap_result_pin[000565-*]` fails**.
|
||||
|
||||
If you take the ADR-0010 slice, the expected fail count drops to 4 or
|
||||
5 on cert 000565 (only the RR-related residuals and the small CO2/
|
||||
lighting deltas remain). Update this prompt's expected-fail count if
|
||||
that lands.
|
||||
|
||||
## Memory hygiene
|
||||
|
||||
After the next slice, update:
|
||||
- `project_cert_000565_recovery_state` — final cumulative closure table
|
||||
(especially if ADR-0010 lands → sap_score 29 EXACT).
|
||||
- If you ship the lighting/pumps_fans Table 12d blend: add a memory
|
||||
entry referencing S0380.65's pattern.
|
||||
|
||||
Good luck.
|
||||
Loading…
Add table
Reference in a new issue