Slice 5b: update the FE-owned migration spec so the other repo can create the bill columns in parallel. - Bill block: per-section delivered kWh + cost (heating, hot water, lighting, appliances, cooking, pumps/fans, cooling) + standing_charges_gbp, seg_credit_gbp, total_annual_bill_gbp, fuel_rates_period. - space_heating_kwh / water_heating_kwh (RHI recorded demand) marked SUPERSEDED by heating_kwh / hot_water_kwh (calculator delivered fuel); kept until the bill populates, then dropped. - Cooling section kept (mostly 0 but affects the bill, cheap to store). - Records the calculator-load-bearing posture (effective_* may differ from lodged_* for pre-10.2) and that columns are defined now / populated when the SapResult->EnergyBreakdown adapter + BillDerivation wiring land. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.4 KiB
property_baseline_performance table — FE-owned migration
Context: Slice 6 (Hestia-Homes/Model#1135) of the ara_first_run rebuild. The
PropertyBaselineOrchestrator establishes a Property's Baseline Performance (ADR-0004) and persists it
via a new PropertyBaselineRepository port. This is a brand-new table — no predecessor.
Per ADR-0004's amendment, the lodged/effective pair does not land on property_details_epc
(which is being retired as too coupled to the legacy EPC-API schema). It lands here, as its own
aggregate's table.
The SQLModel row is defined in infrastructure/postgres/ so the ephemeral-Postgres tests build it
via SQLModel.metadata.create_all. The production migration is FE-owned (Drizzle ORM) — a
straight lift-and-shift of the columns below.
property_baseline_performance — one row per Property
| Column | Type | Notes |
|---|---|---|
id |
serial PK | |
property_id |
int, FK → property.id, unique |
one Baseline Performance per Property |
lodged_sap_score |
int | Lodged Performance — gov register, off the Effective EPC |
lodged_epc_band |
text | the Epc enum, stored as its string value (e.g. "C") |
lodged_co2_emissions_t_per_yr |
float | tonnes CO₂/yr (whole dwelling) |
lodged_primary_energy_intensity_kwh_per_m2_yr |
int | PEUI (kWh/m²/yr); not "heat demand" — see CONTEXT.md |
effective_sap_score |
int | Effective Performance — what modelling scored against |
effective_epc_band |
text | |
effective_co2_emissions_t_per_yr |
float | tonnes CO₂/yr (whole dwelling) |
effective_primary_energy_intensity_kwh_per_m2_yr |
int | kWh/m²/yr |
rebaseline_reason |
text | none | pre_sap10 | physical_state_changed | both |
space_heating_kwh |
float | EPC renewable_heat_incentive recorded demand. Superseded by heating_kwh (delivered) when the bill block populates; kept until then to avoid an empty-kWh gap, dropped in the population slice. |
water_heating_kwh |
float | EPC renewable_heat_incentive; superseded by hot_water_kwh. |
Bill block (ADR-0014) — the energy bill, composed per section
Produced by Bill Derivation: the calculator's delivered kWh per end use priced at current
Fuel Rates (a committed snapshot, not SAP's standardised prices), per section + the total.
Per-section kWh is delivered fuel (demand ÷ efficiency — what the household pays for), distinct
from the recorded-demand space_heating_kwh/water_heating_kwh above which it supersedes.
| Column | Type | Notes |
|---|---|---|
fuel_rates_period |
text | which Fuel Rates snapshot priced this bill (e.g. "2026-04 to 2026-06") — provenance |
heating_kwh |
float | delivered fuel kWh (main + secondary heating) |
heating_cost_gbp |
float | priced at the heating fuel's current rate |
hot_water_kwh |
float | |
hot_water_cost_gbp |
float | |
lighting_kwh |
float | |
lighting_cost_gbp |
float | |
appliances_kwh |
float | unregulated load — 0 until the appliances/cooking fields land on SapResult (ADR-0014 TODO) |
appliances_cost_gbp |
float | |
cooking_kwh |
float | unregulated load — 0 until SapResult carries it |
cooking_cost_gbp |
float | |
pumps_fans_kwh |
float | |
pumps_fans_cost_gbp |
float | |
cooling_kwh |
float | mostly 0 in UK homes; carried for completeness as it affects the bill |
cooling_cost_gbp |
float | |
standing_charges_gbp |
float | daily standing charge × 365, once per distinct metered fuel (off-gas fuels have none) |
seg_credit_gbp |
float | SEG export credit on PV (subtracted) |
total_annual_bill_gbp |
float | Σ section costs + standing charges − SEG |
The calculator is load-bearing (ADR-0013 amendment): for sap_version < 10.2 the effective_*
columns hold the calculator's output (so effective_* != lodged_* legitimately); at/above 10.2 they
mirror the lodged figures and divergence is logged. A cert the calculator cannot score aborts the
batch rather than persisting a wrong row.
Population timing
The bill columns are defined now so the FE can create them, but are populated only once the
SapResult → EnergyBreakdown adapter + BillDerivation wiring land (gated on the appliances /
cooking SapResult fields). Until then the SQLModel mirror in infrastructure/postgres/ adds these
columns as nullable; the Drizzle migration can create them nullable in parallel.