update instruction doc and context

This commit is contained in:
Daniel Roth 2026-06-03 10:33:52 +00:00
parent 5ac5dda877
commit 84aeeff117
2 changed files with 68 additions and 6 deletions

View file

@ -74,6 +74,20 @@ See [ADR-0001](./docs/adr/0001-bulk-upload-state-machine.md) for the deliberate
- A **BulkUpload** has at most one **Task** (the orchestration handle for the FastAPI pipeline run); a Task has many **SubTasks** (one per pipeline stage: address matching, combiner).
- A **Portfolio** has many **VocabularyMappings** — one row per `(category, description)` it has ever encountered across all its BulkUploads. See [ADR-0002](./docs/adr/0002-landlord-override-vocabulary.md).
### Baseline performance
**Lodged performance**:
The SAP score, EPC band, CO₂ emissions, and primary energy intensity as submitted to the government EPC register. Ground truth from the register; never modified.
_Avoid_: original performance, registered performance
**Effective performance**:
The SAP score (and associated metrics) that the modelling engine actually uses as its baseline. Usually equals Lodged performance, but differs when a Landlord override or data-quality issue makes the lodged certificate unreliable — triggering a Rebaseline.
_Avoid_: current performance, adjusted performance
**Rebaseline**:
The act of substituting a corrected set of performance metrics in place of the Lodged values. Recorded on `property_baseline_performance` with a `rebaseline_reason` enum value: `none`, `pre_sap10`, `physical_state_changed`, or `both`.
_Avoid_: override, adjustment, correction
## Example dialogue
> **Dev:** "If the **Combiner** finishes but the user hasn't clicked Finalise, what does the user see?"

View file

@ -1,6 +1,6 @@
# Drizzle schema handoff — pending EPC migrations
**Task:** Update Drizzle table definitions in `src/app/schema/property.ts` to match the
**Task:** Update Drizzle table definitions in `src/app/db/schema/property.ts` to match the
Python SQLModel definitions. Do **not** run `drizzle-kit generate` or any migration
commands — the developer will run generation manually after your changes.
@ -9,6 +9,27 @@ Two sets of changes are covered here:
1. EPC property round-trip fidelity gaps (fixes an active production error)
2. New `property_baseline_performance` table
### Before starting: update the import line
`jsonb` is not currently imported. Add it (and `pgEnum` is already present):
```typescript
import {
bigserial,
text,
timestamp,
pgTable,
real,
pgEnum,
integer,
boolean,
smallint,
bigint,
uniqueIndex,
jsonb, // ← add this
} from "drizzle-orm/pg-core";
```
---
## 1. `epc_property` — new columns
@ -122,12 +143,28 @@ curtainWallAge: text("curtain_wall_age"),
> **Note on `draughtProofed` and `permanentShuttersPresent`:** these are `boolean` in the
> current TypeScript schema but `Union[bool, str]` JSONB in the Python model. Change them
> to `jsonb(...).notNull()` — the TypeScript boolean type was incorrect.
>
> These two columns also require **boolean-specific** USING clauses in the generated migration
> (PostgreSQL will not implicitly cast `boolean` to `jsonb`):
>
> ```sql
> ALTER TABLE "epc_window" ALTER COLUMN "draught_proofed"
> SET DATA TYPE jsonb
> USING to_json("draught_proofed")::jsonb;
>
> ALTER TABLE "epc_window" ALTER COLUMN "permanent_shutters_present"
> SET DATA TYPE jsonb
> USING to_json("permanent_shutters_present")::jsonb;
> ```
>
> `to_json` converts `true`/`false` to JSON booleans (not quoted strings), which is correct
> for the `Union[bool, str]` Python type.
---
## 6. New table: `epc_renewable_heat_incentive`
Add this table to `src/app/schema/property.ts`:
Add this table to `src/app/db/schema/property.ts`:
```typescript
export const epcRenewableHeatIncentive = pgTable(
@ -151,7 +188,18 @@ export const epcRenewableHeatIncentive = pgTable(
## 7. New table: `property_baseline_performance`
Add this table to `src/app/schema/property.ts`:
First, add the enum (before the table definition):
```typescript
export const rebaselineReasonEnum = pgEnum("rebaseline_reason", [
"none",
"pre_sap10",
"physical_state_changed",
"both",
]);
```
Then add the table to `src/app/db/schema/property.ts`:
```typescript
export const propertyBaselinePerformance = pgTable(
@ -165,7 +213,7 @@ export const propertyBaselinePerformance = pgTable(
// Lodged performance (from gov EPC register)
lodgedSapScore: integer("lodged_sap_score").notNull(),
lodgedEpcBand: text("lodged_epc_band").notNull(),
lodgedEpcBand: epcEnum("lodged_epc_band").notNull(),
lodgedCo2EmissionsTPerYr: real("lodged_co2_emissions_t_per_yr").notNull(),
lodgedPrimaryEnergyIntensityKwhPerM2Yr: integer(
"lodged_primary_energy_intensity_kwh_per_m2_yr",
@ -173,7 +221,7 @@ export const propertyBaselinePerformance = pgTable(
// Effective performance (what modelling scored against)
effectiveSapScore: integer("effective_sap_score").notNull(),
effectiveEpcBand: text("effective_epc_band").notNull(),
effectiveEpcBand: epcEnum("effective_epc_band").notNull(),
effectiveCo2EmissionsTPerYr: real(
"effective_co2_emissions_t_per_yr",
).notNull(),
@ -181,7 +229,7 @@ export const propertyBaselinePerformance = pgTable(
"effective_primary_energy_intensity_kwh_per_m2_yr",
).notNull(),
rebaselineReason: text("rebaseline_reason").notNull(),
rebaselineReason: rebaselineReasonEnum("rebaseline_reason").notNull(),
// Interim energy demand (from EPC RHI data; superseded by bill block below once populated)
spaceHeatingKwh: real("space_heating_kwh").notNull(),