mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
docs: SPEC_COVERAGE §9a row + slice progress table + PCDB gap-list update
Adds §9a as a first-class row (consistent with §8c/§8f sub-section precedent). The §9 row updates from "Partial — single main only, no Table 11 secondary" to "Full (single-main + Table 11 secondary)" with a deferred list naming the four remaining slices: two-main system, cooling SEER, Table 4f pumps/fans breakdown, Appendix Q. The PCDB gap-list entry (item 1) updates to flag §9a ALL_FIXTURES PDF-derived LINE_206/(211)/(215) pinning as blocked. The 88.2% figure that surfaced from a previous agent's notes cannot be verified without PCDB — corrected the narrative accordingly. Per-§9a slice progress table mirrors §8c/§8f structure with line refs (201)..(238), commit shorthands, and a Remaining work list naming six follow-ups (PCDB integration, two-main, cooling SEER, Table 4f, Appendix Q, (238) on SapResult). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
380b6781e8
commit
53c393bfba
1 changed files with 44 additions and 3 deletions
|
|
@ -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 rebuild (slices `cf28eec4`…`f3797066`) and §8f atomic slice (`43cc16bc`).
|
||||
Updated 2026-05-21 after §8c (slices `cf28eec4`…`f3797066`), §8f (`43cc16bc`), and §9a single-main slices (`2b5fc6a5`…`380b6781`).
|
||||
|
||||
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`.
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ The canonical SAP10.2 algorithm lives in [`2026-05-19-17-18 RdSap10Worksheet.xls
|
|||
| 8 | Space heating requirement | `worksheet/space_heating.py` | **Full** | Worksheet-driven (95)..(99) via `space_heating_monthly_kwh`. Includes the Table 9c step 10 spec inclusion rule (Jun..Sep zeroed) on top of the < 1 kWh value clamp. (98b) Appendix H solar space heating defaulted to 0 (no Elmhurst fixture lodges a solar space heating system). Wired into `calculator.py` + `cert_to_inputs` via `CalculatorInputs.space_heating_monthly_kwh`. Six Elmhurst fixtures conform end-to-end on (95)/(97)/(98a)/(98c)/(99)/annual @ 5e-2..1e-1 kWh (looser than §6/§7's 5e-3 because LINE_84/93/94 fixture pins are 4-d.p. display-rounded and §8's 0.024·n_m·(L−ηG) amplifies that rounding). |
|
||||
| 8c | Space cooling requirement | `worksheet/space_cooling.py` | **Full (no-AC zero-branch)** | Worksheet-driven (100)..(108) via `space_cooling_monthly_kwh`. Table 10a η_loss with 8-dp γ rounding + L=0 sentinel; Table 10b Q_cool with Jun-Aug inclusion mask + post-f_C × f_intermittent 1-kWh clamp per spec line 10321. Internal temp hardcoded 24 °C. Wired into `calculator.py` (`MonthlyEntry.space_cool_requirement_kwh` + `SapResult.space_cooling_kwh_per_yr`) + `cert_to_inputs` via `CalculatorInputs.space_cooling_monthly_kwh`. Six Elmhurst fixtures all `has_fixed_air_conditioning=False` → (107), (108) ≡ 0 — ALL_FIXTURES asserts (101)/(103)/(106)/(107)/(108) per fixture; synthetic positive test (γ=1 closed-form) covers the algebra. **Deferred**: RdSAP cooled-area defaulting rule + `cooling_gains_from_cert` (drops Table 5a items per spec 10280) + Table 10c SEER → cooling fuel kWh + fuel cost cascade (first non-zero-cooling cert triggers this slice). |
|
||||
| 8f | Fabric Energy Efficiency (line ref (109)) | `worksheet/fabric_energy_efficiency.py` | **Full (rating-conditions transparency)** | Spec line 7898: (109) = (98a) ÷ (4) + (108). `fabric_energy_efficiency_kwh_per_m2_yr(...)` is a single-scalar free function — no dataclass. Σ(98a) (pre Appendix H solar) added as `SpaceHeatingResult.space_heating_requirement_kwh_per_yr` so spec literal is honoured; for our corpus (98b)=0 so Σ(98a) = Σ(98c). `cert_to_inputs` precomputes FEE from local SpaceHeatingResult + SpaceCoolingResult; calculator passes through to `SapResult.fabric_energy_efficiency_kwh_per_m2_yr`. Six Elmhurst fixtures all (108)=0 → LINE_109 = LINE_99 exactly. **§11 compliance conditions** (different ventilation / HW / lighting / gains column) are deferred — current FEE is a rating-conditions transparency output, not a §11 compliance figure. Future §11 slice invokes the same function with §11-conditions upstream values. |
|
||||
| 9 | Energy requirements per heating system | `worksheet/space_heating.py` | Partial | Single main system only — **no Table 11 secondary heating allocation** (10% fraction on most boilers — likely big MAE) |
|
||||
| 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) |
|
||||
|
|
@ -55,7 +55,7 @@ The canonical SAP10.2 algorithm lives in [`2026-05-19-17-18 RdSap10Worksheet.xls
|
|||
|
||||
## Prioritised gap list (by likely MAE impact)
|
||||
|
||||
1. **Boiler / heat-pump efficiency Manufacturer override (PCDB integration)** — `MainHeatingDetail` lodges the PCDB pointer (`main_heating_index_number`) but no scalar efficiency. With `NoOpPcdbLookup` (ADR-0009 grill outcome #1) still in place, `cert_to_inputs` falls back to the SAP10 Table 4a category default (typically 0.80 for gas boilers, SCOP 2.30 for heat pumps) on every cert. Per [ADR-0010 §4](../adr/0010-sap10-calculator-spec-target-and-validation.md#4-pcdb-integration-is-promoted-from-session-c-to-a-prerequisite) this accounts for ~19 SAP points of MAE on heat-pump certs and most per-cert variance on the 78 % of gas-boiler certs lodging `main_heating_data_source=1` (PCDB-typical 0.88–0.94 vs 0.80 default). Directly visible on 000490 e2e: `inputs.main_heating_efficiency = 0.80` vs PDF Vaillant Ecotec Pro Manufacturer-declared 0.882 — drives +3 SAP overshoot via the `q_useful / η` cascade in both space heating and HW. Closing requires a real PCDB CSV ingest + `PcdbLookup` Protocol impl + precedence wiring in `cert_to_inputs._main_heating_efficiency` and `_water_efficiency_with_category_inherit`. Promoted to prerequisite under ADR-0010, not a section-sweep slice.
|
||||
1. **Boiler / heat-pump efficiency Manufacturer override (PCDB integration)** — `MainHeatingDetail` lodges the PCDB pointer (`main_heating_index_number`) but no scalar efficiency. With `NoOpPcdbLookup` (ADR-0009 grill outcome #1) still in place, `cert_to_inputs` falls back to the SAP10 Table 4a category default (typically 0.80 for gas boilers, SCOP 2.30 for heat pumps) on every cert. Per [ADR-0010 §4](../adr/0010-sap10-calculator-spec-target-and-validation.md#4-pcdb-integration-is-promoted-from-session-c-to-a-prerequisite) this accounts for ~19 SAP points of MAE on heat-pump certs and most per-cert variance on the 78 % of gas-boiler certs lodging `main_heating_data_source=1` (PCDB-typical 0.88–0.94 vs 0.80 default). Directly visible on 000490 e2e: `inputs.main_heating_efficiency = 0.80` vs an unverified PDF Manufacturer-declared figure that surfaced from a previous agent's notes — the actual PDF value cannot be confirmed without PCDB. Closing requires a real PCDB CSV ingest + `PcdbLookup` Protocol impl + precedence wiring in `cert_to_inputs._main_heating_efficiency` and `_water_efficiency_with_category_inherit`. Promoted to prerequisite under ADR-0010, not a section-sweep slice. **§9a ALL_FIXTURES PDF-derived LINE_206/(211)/(215) pinning is blocked on this** — until PCDB lands, §9a conformance is at the synthetic + cert-round-trip level only (no PDF cross-check).
|
||||
2. **Table 11 Secondary heating allocation** — most boiler-main certs allocate 10% of space heating to a secondary system (often a less-efficient room heater on a different fuel). We model 0%. Likely +1-2 SAP-point bias on affected certs.
|
||||
3. **Wind-shelter factor on infiltration** (§2 worksheet lines 19-21) — multiplies infiltration by `1 - 0.075 × sheltered_sides`. We have no shelter input; assume 2 sheltered sides default. Net effect on infiltration ACH probably ~10%.
|
||||
4. **Table 12a high-rate fraction for off-peak dwellings** — we currently bill 100% of E7 space heating at the low rate. Real spec says e.g. heat pumps on 7h tariff at 80% high-rate. Affects ~5% of certs.
|
||||
|
|
@ -253,3 +253,44 @@ Status now: 100-cert MAE 4.49, 300-cert MAE 5.45, bias near zero (±0.2). Worksh
|
|||
|
||||
1. **§11 FEE compliance conditions** — spec lines 2152-2164 require a separate worksheet run with: natural ventilation + 2-4 extract fans by TFA, instantaneous-electric shower + bath, 125 l/day water-use target, lighting capacity 185 lm/m² at 66.9 lm/W, column (B) of Table 5 for heating gains, column (A) for cooling gains, etc. This is a new-build compliance path; existing-dwelling ratings don't trigger it. Lands as `fabric_energy_efficiency_under_section_11_conditions(...)` when the first compliance use case emerges.
|
||||
2. **Σ(98a) ≠ Σ(98c) regression coverage** — when Appendix H solar space heating lands (currently (98b) ≡ 0), Σ(98a) will diverge from Σ(98c). The FEE function consumes Σ(98a) per spec; a new fixture with non-zero (98b) would assert that distinction holds.
|
||||
|
||||
## §9a — slice progress (xlsx rows 470–614)
|
||||
|
||||
| Line ref | Description | Status | Commit |
|
||||
|---|---|---|---|
|
||||
| — | `space_heating_fuel_monthly_kwh` orchestrator + `EnergyRequirementsResult` dataclass (16 fields, full worksheet shape) | ✅ | `2b5fc6a5` |
|
||||
| (201) | Secondary heating fraction (Table 11) | ✅ | `2b5fc6a5` |
|
||||
| (202) | Main heating total fraction = 1 − (201) | ✅ | `2b5fc6a5` |
|
||||
| (203) | Main 2 of main fraction | ⏸ zero-branch (no two-main cert yet) | — |
|
||||
| (204) | Main 1 of total fraction = (202) × (1 − (203)) | ✅ | `2b5fc6a5` |
|
||||
| (205) | Main 2 of total fraction = (202) × (203) | ⏸ zero-branch | — |
|
||||
| (206) | Main 1 efficiency % | ✅ pass-through; cert source is SAP10 Table 4a category default (PCDB-blocked) | `2b5fc6a5` |
|
||||
| (207) | Main 2 efficiency % | ⏸ zero-branch | — |
|
||||
| (208) | Secondary efficiency % | ✅ | `2b5fc6a5` |
|
||||
| (209) | Cooling SEER (Table 10c) | ⏸ deferred (see §8c remaining work) | — |
|
||||
| (211)m | Main 1 fuel kWh per month = (98c)m × (204) × 100 / (206) | ✅ | `2b5fc6a5` |
|
||||
| (211) | Σ(211)m | ✅ | `2b5fc6a5` |
|
||||
| (213)m | Main 2 fuel kWh per month | ⏸ zero-branch | — |
|
||||
| (213) | Σ(213)m | ⏸ zero-branch | — |
|
||||
| (215)m | Secondary fuel kWh per month = (98c)m × (201) × 100 / (208) | ✅ | `2b5fc6a5` |
|
||||
| (215) | Σ(215)m | ✅ | `2b5fc6a5` |
|
||||
| (221) | Cooling fuel kWh per yr = (107) ÷ (209) | ⏸ deferred (Table 10c SEER) | — |
|
||||
| — | `CalculatorInputs.energy_requirements` composite slot + `SapResult.main_2_heating_fuel_kwh_per_yr` + `SapResult.space_cooling_fuel_kwh_per_yr` + `_solve_month` refactor + cert_to_inputs wiring (atomic) | ✅ | `380b6781` |
|
||||
| — | 6-fixture ALL_FIXTURES PDF-derived pins on (206)/(211)/(215) | ⏸ **blocked on PCDB** (see Prioritised gap list item 1) | — |
|
||||
| (230a)-(230h) | Table 4f pumps/fans breakdown (warm-air fans, oil aux, gas aux, keep-hot, solar pump, WWHRS pump) | ⏸ deferred | — |
|
||||
| (231) | Σ(230a)-(230h) — Total electricity for pumps/fans/keep-hot | ⏸ deferred — currently `inputs.pumps_fans_kwh_per_yr` is an opaque scalar | — |
|
||||
| (236)/(237) | Appendix Q items energy saved/used | ⏸ deferred (no Q-item cert in corpus) | — |
|
||||
| (238) | Total delivered energy kWh/yr | Partial — computed in `intermediate["delivered_fuel_kwh_per_yr"]`; not yet promoted to SapResult field | — |
|
||||
|
||||
**Four synthetic tests on the orchestrator** cover: single-main no-secondary 80% efficiency, Table 11 secondary fraction split (211)+(215), summer-clamp zero propagation, and scope-A two-main / cooling-fuel placeholders. Cert round-trip test pins `inputs.energy_requirements.main_1_fuel_kwh_per_yr == result.main_heating_fuel_kwh_per_yr` to float equality — confirms the refactor preserves existing behaviour.
|
||||
|
||||
**E2e SAP-score impact:** zero (refactor only — `_solve_month` now reads precomputed (211)m/(215)m instead of doing q/η inline). The 000490 +3 SAP-score gap stays parked behind PCDB integration.
|
||||
|
||||
### Remaining §9a work
|
||||
|
||||
1. **PCDB integration** — see Prioritised gap list item 1. Blocks PDF-derived ALL_FIXTURES pinning + closes 000490 e2e gap. ADR-0010 §4 prerequisite.
|
||||
2. **Two-main system** (203)/(205)/(207)/(213) — populate from `epc.sap_heating.main_heating_details[1]` when a multi-main cert appears in fixtures. EnergyRequirementsResult already exposes the fields as zeros; first multi-main slice flips them from placeholders to real values.
|
||||
3. **Table 10c SEER → (209)/(221)** — cooling fuel kWh from (107) ÷ SEER. Same trigger as §8c remaining work (first fixed-AC cert); add Table 10c lookup table + wire `energy_requirements.cooling_fuel_kwh_per_yr` + SapResult.space_cooling_fuel_kwh_per_yr from zero to real value.
|
||||
4. **Table 4f pumps/fans breakdown** (230a)-(230h) → (231) — replace opaque `CalculatorInputs.pumps_fans_kwh_per_yr` scalar with per-source sub-lines. Likely a separate sweep slice once aux electricity becomes load-bearing for ranking.
|
||||
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.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue