# `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.