Model/packages
Khalim Conn-Kowlessar 02fc9e4d47 §4 HW slice 2: Equation D1 monthly water-eff cascade
Closes the residual ~1.2% on 000474 HW kWh that slice 1 left (PCDB
Table 3b combi loss landed (61) correctly but the divisor was still
the scalar PCDB summer efficiency 87.0%). Slice 2 promotes that
scalar to the SAP10.2 Appendix D §D2.1 (2) Equation D1 monthly
cascade — η_water,monthly = (Q_space + Q_water) / (Q_space/η_winter
+ Q_water/η_summer) — and folds it into the cert_to_inputs flow:

- worksheet/water_heating.py: water_efficiency_monthly_via_equation_
  d1(...) — pure function over winter/summer efficiencies + (98c)m
  × (204) + (64)m monthly tuples. Implements the spec's two early-
  outs (η_summer ≥ η_winter → all months = η_summer; zero-demand
  months → η_summer).
- rdsap/cert_to_inputs.py: splits _hot_water_fuel_kwh_per_yr (now
  removed) into:
  - _water_heating_worksheet_and_gains: runs §4 (45..65) early so
    §5/§7/§8 can consume (65)m heat gains.
  - _apply_water_efficiency: invoked after §8 produces (98c)m, picks
    monthly cascade for PCDB-tested combis with distinct winter/
    summer effs, falls back to scalar divisor otherwise.
  Pulled secondary_fraction_value computation forward of §4 so the
  post-§8 Q_space = (98c)m × (204) derivation has it in scope.

Outcomes (closes the §10a slice-2 deferred §4 HW debt):
- 000474 HW kWh: 2622 → 2320 (slice 1) → 2292 ✓ matches PDF 2292
  to 0.0%. SAP delta 4 → 3 (ceiling tightened 4 → 3).
- 000490 HW kWh: 3028 → 3028 (slice 1 no-op, no PCDB Table 3b
  data) → 2847 ✓ matches PDF 2851 to 0.1%. SAP delta 2 → 3
  (ceiling loosened 2 → 3 — the closer HW kWh exposes spec-version
  drift on the 000490 cost figure that PDF lodged under cert-
  assessor era prices per ADR-0010 §3).
- 486 tests passing across the domain package; 13 pre-existing
  pyright errors on cert_to_inputs (no net new from this slice).

Remaining 000474 +9% cost residual is Appendix L lighting (528 vs
~169 back-derived) — separate ticket per project memory
`project_section_4_hw_next_ticket` "secondary upstream" note.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 22:54:29 +00:00
..
domain §4 HW slice 2: Equation D1 monthly water-eff cascade 2026-05-21 22:54:29 +00:00
fetchers added potential file scaffolding: 2026-05-15 10:56:53 +00:00
repos added potential file scaffolding: 2026-05-15 10:56:53 +00:00
utils added potential file scaffolding: 2026-05-15 10:56:53 +00:00
README.md added potential file scaffolding: 2026-05-15 10:56:53 +00:00

Shared packages

Workspace packages consumed by services/*. Each package is its own Python distribution with its own pyproject.toml; services import via the workspace dependency mechanism ({ workspace = true }).

Package Purpose
domain/ Shared domain types — Property, BaselinePerformance, Plan, Scenario, EpcPropertyData, etc. No persistence, no IO, no business logic.
repos/ Persistence layer — one repo per aggregate. Owns the SQL. Depends on domain.
fetchers/ External API clients (gov EPC, Ofgem, Google Solar, etc.). Depend on domain for response shapes.
utils/ Cross-cutting infra — logging, S3, CloudWatch URL builders, SQS task helpers.

Adding a new shared package

Only when a real second consumer materialises. Don't pre-shatter (repos-epc, repos-property, ...) — split when a deployment needs to drop a dep, not before.

See ../ara_backend_design.md §11 for the broader monorepo layout and ../CONTEXT.md for the domain glossary that names the types living in domain/.