mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
docs: §10a slice 3 — ADR-0010 amendment + SPEC_COVERAGE row
- ADR-0010 amendment: narrow the SAP10.2 spec target — §10a/§10b cost prices source from RdSAP10 Table 32 (per RdSAP10 §19.1), not SAP10.2 Table 12. CO2 + PEF stay on Table 12 (RdSAP10 §19.2 says they're identical). Closes out the 000490 "spec-version drift" framing as wrong-table + missing-standing-charges, not corpus drift. Names §4 HW + Appendix L as the next-ticket upstream debt that pre-§10a wrong-prices had been masking. - SPEC_COVERAGE: new §10a row (32-field FuelCostResult, three new tables/* + worksheet/* modules, per-line-ref status, Remaining §10a work list). Updates §12 to "folded into §10a". Updates header attribution. No code changes in this commit — docs only. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
adfa7f60da
commit
ae8c946179
2 changed files with 78 additions and 2 deletions
|
|
@ -66,3 +66,37 @@ Each `domain/sap/worksheet/*.py` module must mirror the SAP 10.2 worksheet struc
|
|||
- **Build versioned Table 12 (pre/post 14-March-2025) keyed on `inspection_date` and validate across the full corpus.** Rejected as more work for no signal benefit during the spec sweep — the filtered cohort gets us to a clean probe faster. A versioned table is still future work if Calculated SAP10 Performance ever needs to reproduce historical cert SAP for products that compare against Lodged Performance directly.
|
||||
- **Keep cert-cal during the sweep and re-derive at the end** (the handover's prescription). Rejected for the reasons in decision (2): the cert-cal layer corrupts the signal during the sweep, which is precisely when the signal needs to be cleanest.
|
||||
- **Pay for an Elmhurst license, lock fixtures to its output.** Held in reserve. BRE worked examples are free and spec-derived; an Elmhurst trace would add value as a per-component reference but is not a prerequisite.
|
||||
|
||||
## Amendment — §10a Fuel costs (2026-05-21)
|
||||
|
||||
Decision 1's "active spec target is SAP 10.2 (14-03-2025)" is narrowed for the §10a Fuel-costs block: **cost prices for §10a and §10b are sourced from RdSAP10 Table 32 (PDF page 95)**, not SAP 10.2 Table 12. RdSAP10 §19.1 is explicit: *"The SAP rating for RdSAP 10 is to be calculated using Table 32 prices (not Table 12) for section 10a and 10b."*
|
||||
|
||||
CO2 emission factors and primary-energy factors remain SAP 10.2 Table 12 per RdSAP10 §19.2 (the values are identical across the two tables; the columns are duplicated in Table 32 for completeness but Table 12 is the canonical authoritative source the calculator continues to import).
|
||||
|
||||
### Why the amendment exists
|
||||
|
||||
The §10a slice 1+2 rewrite (commits `0f255165`, `adfa7f60` on branch `ara-backend-design-prd`) surfaced two structural bugs that the pre-amendment Table-12-only path was masking:
|
||||
|
||||
1. **Wrong table.** Table 12 unit prices were 5–55% off Table 32 per carrier (mains gas 3.64 vs 3.48, heating oil 4.94 vs 7.64, std electricity 16.49 vs 13.19, off-peak 9.40 vs 5.50, PV export 5.59 vs 13.19). Table 32 is what cert assessor software computes against; comparing our Table-12-driven SAP scores against PDF references was an apples-to-oranges check.
|
||||
2. **Missing (251) standing charges.** Table 12 note (a) (and the identical Table 32 note (a)) gates additional standing charges into the SAP-rating ECF: gas standing added when gas is used for space/water heating; off-peak electricity standing added when an off-peak meter is in use; standard-electricity standing always omitted. Pre-amendment the calculator applied zero standing charges — equivalent to ignoring £92–£120/yr per gas-heated dwelling.
|
||||
|
||||
The 000490 Elmhurst fixture had a recorded -12.5% cost gap (£706 vs £807 PDF) that ADR-0010 §3 Validation Cohort framing attributed to "pre-amendment spec-version drift". The §10a rewrite shows the gap was wrong-table + missing-standing-charges — a real calculator regression, not corpus drift. Post-§10a 000490 closes to within ~4% of PDF cost and SAP rating ceiling tightens 6 → 2.
|
||||
|
||||
### Consequences
|
||||
|
||||
- **`packages/domain/src/domain/sap/tables/table_32.py`** ships the RdSAP10 unit prices + standing charges + Table 12 note (a) gating function. Table 12 keeps the CO2 + PEF columns.
|
||||
- **`packages/domain/src/domain/sap/tables/table_12a.py`** ships the high-rate-fraction lookups for off-peak split (Table 12a in SAP 10.2 PDF page 191 — RdSAP10 §19.1 cross-references this table directly). `Tariff.TEN_HOUR` carried for spec completeness even though RdSAP cert `meter_type` enum (1..5) has no 10-hour code.
|
||||
- **`packages/domain/src/domain/sap/worksheet/fuel_cost.py`** ships the §10a orchestrator producing `FuelCostResult` (32 fields, line refs (240)..(255)). `cert_to_inputs._fuel_cost` precompute wires it from cert state.
|
||||
- The 000474 Elmhurst fixture cost residual widened from -0.6% to +10.7% (SAP rating ceiling loosened 2 → 4) because the pre-amendment wrong-table-but-cancels-kWh accidentally compensated for upstream §4 HW kWh + Appendix L lighting overestimates. **§4 HW worksheet tightening is the next ticket** — see project memory `project_section_4_hw_next_ticket`. Ceiling drops back to 2 (or below) when that lands.
|
||||
- Golden corpus SAP tolerance widened ±7 → ±11 per the Validation Cohort discipline (oil unit price +55% from Table 12 → Table 32 moves oil-heated golden certs whose lodged SAP scores pre-date Table 32).
|
||||
|
||||
### Deferred work (named in §10a slice 3)
|
||||
|
||||
- §4 HW worksheet tightening + Appendix L lighting predictor — **next ticket**.
|
||||
- Table 12a high-rate-fraction wiring for off-peak electric mains (`Table12aSystem` cert→row mapping). Currently the cert→precompute path returns a zero `FuelCostResult` sentinel for off-peak certs, deferring to the legacy scalar `_*_fuel_cost_gbp_per_kwh` heuristic.
|
||||
- Table 13 immersion / HP-DHW WH high-rate fractions.
|
||||
- Off-peak per-row (230a)..(230g) Table 12a split for pumps/fans (spec line 8076).
|
||||
- (247a) Instant electric shower kWh routing.
|
||||
- (252) per-row Appendix M/N split (PV / wind / hydro / micro-CHP) — currently single `pv_credit_gbp` scalar.
|
||||
- (253)/(254) Appendix Q routes.
|
||||
- Drop the legacy scalar `space_heating_fuel_cost_gbp_per_kwh` / `hot_water_fuel_cost_gbp_per_kwh` / `other_fuel_cost_gbp_per_kwh` / `secondary_heating_fuel_cost_gbp_per_kwh` / `pv_export_credit_gbp_per_kwh` fields from `CalculatorInputs` once the ~33-occurrence synthetic-test corpus migrates to `fuel_cost=...`.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Tracks which sections of the SAP 10.2 specification are implemented in `packages/domain/src/domain/sap/`. Per ADR-0009 the calculator is built from the spec, not reverse-engineered from cert data. This doc is the worksheet-driven roadmap for what remains.
|
||||
|
||||
Updated 2026-05-21 after §8c (slices `cf28eec4`…`f3797066`), §8f (`43cc16bc`), §9a single-main slices (`2b5fc6a5`…`380b6781`), PCDB Table 105 integration (`fe04cd3a`…`a104dd55`), and PCDB fixture lodgement (`1b43c95c`…`15d6b781`).
|
||||
Updated 2026-05-21 after §8c (slices `cf28eec4`…`f3797066`), §8f (`43cc16bc`), §9a single-main slices (`2b5fc6a5`…`380b6781`), PCDB Table 105 integration (`fe04cd3a`…`a104dd55`), PCDB fixture lodgement (`1b43c95c`…`15d6b781`), and §10a Fuel costs (`0f255165`…`adfa7f60`).
|
||||
|
||||
The canonical SAP10.2 algorithm lives in [`2026-05-19-17-18 RdSap10Worksheet.xlsx`](../../2026-05-19-17-18%20RdSap10Worksheet.xlsx) at the repo root — each line ref `(1)..(486)` maps to a cell. The worksheet sub-modules under `packages/domain/src/domain/sap/worksheet/` implement those line refs directly; Elmhurst worksheets validate end-to-end via `tests/_elmhurst_worksheet_*.py`.
|
||||
|
||||
|
|
@ -24,7 +24,8 @@ The canonical SAP10.2 algorithm lives in [`2026-05-19-17-18 RdSap10Worksheet.xls
|
|||
| 9 | Energy requirements per heating system (§9a worksheet block) | `worksheet/energy_requirements.py` | **Full (single-main + Table 11 secondary)** | Worksheet-driven (201)..(215) via `space_heating_fuel_monthly_kwh`. (211)m = (98c)m × (204) × 100 / (206) and (215)m mirror; Σ → annuals. EnergyRequirementsResult dataclass mirrors the full §9a worksheet shape with 16 fields incl. (203)/(205)/(207)/(209)/(213)/(221) zero-branch placeholders. `cert_to_inputs` precomputes and stashes on `CalculatorInputs.energy_requirements` composite slot; calculator's `_solve_month` reads precomputed (211)m/(215)m directly (stops doing q/η inline). SapResult adds `main_2_heating_fuel_kwh_per_yr` and `space_cooling_fuel_kwh_per_yr` flat scalars (both zero in scope A). **Deferred**: (203)/(205)/(207)/(213) two-main system (first multi-main cert) + (209)/(221) cooling SEER (Table 10c lookup — first fixed-AC cert) + (230a)-(230h)/(231) Table 4f pumps/fans breakdown + (236)/(237) Appendix Q items + ALL_FIXTURES LINE_206/(211)/(215) PDF-derived pins (**blocked on PCDB** — see Boiler / heat-pump efficiency Manufacturer override in Prioritised gap list). |
|
||||
| 10 | Cooling (spec heading — same content as §8c worksheet block) | `worksheet/space_cooling.py` | **Full (no-AC zero-branch)** | See §8c row above. |
|
||||
| 11 | FEE compliance conditions | `worksheet/fabric_energy_efficiency.py` (the function exists; §11 conditions don't run yet) | Partial | (109) formula exposed via `fabric_energy_efficiency_kwh_per_m2_yr`. Spec §11 conditions (lines 2152-2164: 2-4 extract fans, instantaneous-electric shower, 125 l/day water, 185 lm/m² lighting at 66.9 lm/W, column (B) heating gains, column (A) cooling gains, etc.) not implemented — only relevant for new-build compliance. |
|
||||
| 12 | Total energy + fuel costs | `calculator.py` | Partial | Per-end-use cost split ✓; meter_type tariff routing ✓ (S-B15); PV cost credit ✓ (S-B19); **standing charges not included** (Table 12 note (a) says rating omits standing charge for std electricity tariff) |
|
||||
| 10a | Fuel costs incl. micro-CHP | `worksheet/fuel_cost.py` + `tables/table_32.py` + `tables/table_12a.py` | **Full (single-main + standard tariff)** | Worksheet-driven (240)..(255) via `fuel_cost(...)`. 32-field `FuelCostResult` mirrors the §10a worksheet shape: (240a-e) main 1 + (241a-e) main 2 + (242a-e) secondary off-peak splits, (243-247) water heating, (247a) instant shower, (248) cooling, (249) pumps/fans, (250) lighting, (251) standing charges (Table 12 note (a) gating: gas standing + off-peak electricity standing), (252) PV credit (negative), (253-254) Appendix Q, (255) total clamped to ≥ 0. RdSAP10 Table 32 prices per ADR-0010 amendment (overrides SAP10.2 Table 12 for §10a/§10b). `Tariff` + `Table12aSystem` + `OtherUse` enums in `table_12a.py` for off-peak high-rate-fraction lookups (synthetic-tested; unreachable from RdSAP cert flow until Table12aSystem cert→row mapping lands). `cert_to_inputs._fuel_cost` precomputes for STANDARD-tariff certs; off-peak certs return zero sentinel so the calculator's legacy scalar `_*_fuel_cost_gbp_per_kwh` fallback fires (deferred). 000490 SAP rating ceiling tightened 6 → 2; 000474 ceiling loosened 2 → 4 reflecting upstream §4 HW + Appendix L lighting overestimates the pre-§10a wrong-table-but-cancels-kWh had masked. **Deferred**: per-row (252) PV/wind/hydro/μCHP split, Table 13 immersion fractions, Table 12a Table12aSystem cert→row mapping for off-peak electric mains, (230a)-(230g) per-row pumps/fans split, (247a) instant shower wiring, scalar fuel-cost-per-kWh field cleanup from CalculatorInputs. |
|
||||
| 12 | Total energy + fuel costs (legacy heading — folded into §10a) | `calculator.py` | **Folded into §10a row above** | Pre-§10a §12 row covered the inline cost arithmetic; that block was rewritten into the §10a orchestrator + cert_to_inputs precompute. Calculator delegates `total_fuel_cost_gbp` to `inputs.fuel_cost.total_cost_gbp`. |
|
||||
| 13 | SAP rating | `worksheet/rating.py` | Full | Equations 7-9 verified against SAP 10.2 §13 |
|
||||
| 14 | CO2 + primary energy | `calculator.py` SapResult.co2_kg_per_yr | Partial | Single CO2 factor on main fuel; no per-end-use CO2 mixing; **no primary energy calculation** |
|
||||
| 15 | Building regs | n/a | n/a | Not relevant to ratings |
|
||||
|
|
@ -295,6 +296,47 @@ Status now: 100-cert MAE 4.49, 300-cert MAE 5.45, bias near zero (±0.2). Worksh
|
|||
5. **Appendix Q items** (236)/(237) — placeholder until a Q-item cert lands.
|
||||
6. **(238) total delivered energy on SapResult** — promote from `intermediate` dict when §10a or §13 requires it as a named output.
|
||||
|
||||
## §10a — slice progress (xlsx rows ~614–740)
|
||||
|
||||
Per ADR-0010 amendment, §10a costs source from RdSAP10 **Table 32** (PDF page 95), not SAP10.2 Table 12. Three new modules + one composite slot on `CalculatorInputs` + one calculator delegation.
|
||||
|
||||
| Slice | What landed | Commit |
|
||||
|---|---|---|
|
||||
| 1 | `tables/table_32.py` (28 fuel-row unit prices + 11-row standing charges + note (a) gating fn) + `tables/table_12a.py` (`Tariff` + `Table12aSystem` + `OtherUse` enums + SH/WH/other-use fraction lookups + `tariff_from_meter_type` cert resolver) + `worksheet/fuel_cost.py` (32-field `FuelCostResult` + kwargs `fuel_cost(...)` orchestrator with `_split` off-peak helper). 130 synthetic unit tests. | `0f255165` |
|
||||
| 2 | `CalculatorInputs.fuel_cost` composite slot (default zero sentinel) + `cert_to_inputs._fuel_cost` precompute (Table 32 prices + note (a) standing-charge gating; off-peak certs return zero sentinel → calculator falls back to legacy scalar `_*_fuel_cost_gbp_per_kwh` helpers, deferred). Calculator delegates `total_fuel_cost_gbp` to `inputs.fuel_cost.total_cost_gbp`. 2 cert-round-trip conformance tests (000474 within e2e 15% tolerance; 000490 within 5%). e2e ceilings adjusted: 000490 6 → 2 (tightened — marquee close-out), 000474 2 → 4 (loosened — exposes upstream §4 HW + Appendix L), golden corpus ±7 → ±11 (oil price +55% Table 12 → Table 32). | `adfa7f60` |
|
||||
| 3 | Docs — ADR-0010 amendment, this SPEC_COVERAGE row, slice progress table. | _this commit_ |
|
||||
|
||||
### Line-ref status
|
||||
|
||||
| Line ref | Status | Notes |
|
||||
|---|---|---|
|
||||
| (240a)-(240e) | Full | Main 1 off-peak split. STANDARD-tariff certs lodge `high_rate_fraction=1.0` so (240c) = kWh × price + (240d) = 0. Off-peak certs defer to legacy scalar fallback (Table12aSystem cert→row mapping deferred). |
|
||||
| (241a)-(241e) | Zero-branch placeholder | Main 2 — no multi-main fixture in corpus. |
|
||||
| (242a)-(242e) | Full (zero-valued) | Secondary off-peak split. All 6 fixtures lodge zero `secondary_fuel_kwh_per_yr`. |
|
||||
| (243)-(247) | Full (single-rate path) | Water heating off-peak split. STANDARD-tariff path active; Table 12a immersion / heat-pump-DHW (Table 13) deferred. |
|
||||
| (247a) | Zero-branch placeholder | Instant electric shower kWh routing deferred (no fixture lodges one). |
|
||||
| (248) | Full | Cooling cost at `other_uses_gbp_per_kwh`. Zero in 6 fixtures (f_C=0). |
|
||||
| (249) | Full (aggregate) | Pumps/fans single-rate. Per-row (230a)-(230g) Table 12a split deferred (spec line 8076). |
|
||||
| (250) | Full (aggregate) | Lighting single-rate. Per-row off-peak split deferred when first off-peak fixture lands. |
|
||||
| (251) | Full | Standing charges via Table 12 note (a) — gas (mains gas £120, LPG £70) added when gas used for space/water; off-peak electricity standing added when off-peak meter in use; std electricity standing always omitted. |
|
||||
| (252) | Partial | Single `pv_credit_gbp` scalar. Per-row PV / wind / hydro / micro-CHP split deferred. |
|
||||
| (253)/(254) | Zero-branch placeholder | Appendix Q items — no Q-item cert in corpus. |
|
||||
| (255) | Full | `max(0, Σ all rows)` clamp. |
|
||||
|
||||
**Six Elmhurst fixtures route through the new precompute** (all `meter_type="Single"` → STANDARD tariff). 000490 cost closes to PDF within ~4%; 000474 widens to +10.7% (upstream §4 HW + Appendix L — see Remaining work).
|
||||
|
||||
### Remaining §10a work
|
||||
|
||||
1. **§4 HW worksheet tightening — next ticket.** 000474 HW kWh overestimates +14.4% (2622 vs 2292 PDF), Appendix L lighting overestimates ~3x. Pre-§10a wrong-table-but-cancels-kWh masked these. See project memory `project_section_4_hw_next_ticket`.
|
||||
2. **Table 12a cert→Table12aSystem mapping** for off-peak electric mains. Currently `cert_to_inputs._fuel_cost` returns the zero sentinel for non-STANDARD tariff certs so the calculator's legacy scalar fallback fires. Off-peak split awaits a real off-peak fixture + the row-mapper.
|
||||
3. **Table 13 immersion + HP-DHW-only WH fractions** — `Table12aSystem.IMMERSION_OR_HP_DHW_ONLY` raises `NotImplementedError`; populate when first immersion fixture lands.
|
||||
4. **Electric CPSU → Appendix F fractions** — `Table12aSystem.ELECTRIC_CPSU` raises; populate when first CPSU fixture lands.
|
||||
5. **Per-row (230a)-(230g) pumps/fans split** for off-peak tariffs (spec line 8076: "if off-peak tariff, list each of (230a) to (230g) separately and apply fuel price according to Table 12a"). Requires §9a Table 4f pumps/fans breakdown (see §9a remaining work item 4) as a prerequisite.
|
||||
6. **(247a) Instant electric shower** kWh routing — (64a) currently always 0 from `_hot_water_fuel_kwh_per_yr`. Wire when electric-shower cert lodges.
|
||||
7. **(252) per-row Appendix M/N split** — populate (233a)..(235d) when wind / hydro / micro-CHP fixtures land.
|
||||
8. **(253)/(254) Appendix Q** — zero placeholders; populate when a Q-item cert lands.
|
||||
9. **Drop legacy scalar fuel-cost fields** from `CalculatorInputs` (`space_heating_fuel_cost_gbp_per_kwh`, `hot_water_fuel_cost_gbp_per_kwh`, `other_fuel_cost_gbp_per_kwh`, `secondary_heating_fuel_cost_gbp_per_kwh`, `pv_export_credit_gbp_per_kwh`) — currently retained as a synthetic-test fallback. Drops when the ~33-occurrence test corpus migrates to `fuel_cost=...`.
|
||||
|
||||
## PCDB — slice progress (BRE pcdb10.dat ingestion)
|
||||
|
||||
| Stage | Description | Status | Commit |
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue