Model/packages
Khalim Conn-Kowlessar 9106621aee slice S-A6: SAP10.3 rating + EI rating formulas (§13 + §14)
Tenth slice of the SAP10 Calculator Session A (ADR-0009). Ships four
pure functions under domain.sap.worksheet.rating implementing the SAP
10.3 rating formulas:

  energy_cost_factor(total_cost_gbp, total_floor_area_m2)
    -> equation (7): ECF = 0.36 × cost / (TFA + 45)
       Deflator 0.36 sourced from Table 12 (page 191).

  sap_rating(ecf)
    -> equations (8)/(9), continuous (un-rounded) SAP value:
       ECF ≥ 3.5:  108.8 − 120.5 × log10(ECF)
       ECF < 3.5:  100   − 16.21 × ECF
       Naturally rises above 100 for net energy exporters (negative ECF).

  sap_rating_integer(ecf)
    -> integer SAP value as published on the EPC: round to nearest, clamp
       to minimum 1 per §13.

  environmental_impact_rating(co2_emissions_kg_per_yr, total_floor_area_m2)
    -> equations (10)-(12), continuous EI rating:
       CF = CO2 / (TFA + 45)
       CF ≥ 28.3:  200 − 95   × log10(CF)
       CF < 28.3:  100 − 1.34 × CF

8 AAA cycles cover: ECF formula hand-computed, SAP linear branch (typical
home), SAP log branch (high cost), boundary continuity at ECF=3.5,
net-exporter SAP > 100, integer rounding + min-1 clamp, EI linear branch,
EI log branch.

Orchestrator (S-A7) wires these into Sap10Calculator alongside the monthly
heat balance loop from S-A5e.
2026-05-18 09:12:25 +00:00
..
domain slice S-A6: SAP10.3 rating + EI rating formulas (§13 + §14) 2026-05-18 09:12:25 +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/.