fix(building-passport): fill tenure from EPC graph

Tenure read the property-row tenure column, null for new-approach properties.
Backfill propertyMeta.tenure from epc_property.tenure (mostly text labels like
"Rented Social"; numeric SAP codes 1/2/3 mapped to the same labels).

Local authority / constituency have no source in the new pipeline (not on
epc_property, null on the property row, energy_assessments doesn't cover these
properties) — left as-is pending the pipeline writing them to the property row.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-06-23 11:30:46 +00:00
parent 9750770c7c
commit 1aeb33762e

View file

@ -504,6 +504,14 @@ const BUILT_FORM_LABELS: Record<string, string> = {
"5": "Enclosed End-Terrace",
"6": "Enclosed Mid-Terrace",
};
// SAP tenure codes → the text labels already used in the data. NOTE: best-effort
// (standard SAP 1/2/3); most rows store the text label directly, only a few use
// codes. Confirm against the backend tenure enum.
const TENURE_LABELS: Record<string, string> = {
"1": "Owner Occupied",
"2": "Rented Social",
"3": "Rented Private",
};
// Matches the backend ConstructionAgeBand enum (RdSAP England & Wales letters).
const AGE_BAND_YEARS: Record<string, string> = {
A: "before 1900",
@ -533,6 +541,7 @@ async function resolvePropertyDescriptors(
builtForm: string | null;
yearBuilt: string | null;
numberOfRooms: number | null;
tenure: string | null;
}> {
const cols = {
id: true,
@ -540,6 +549,7 @@ async function resolvePropertyDescriptors(
builtForm: true,
dwellingType: true,
habitableRoomsCount: true,
tenure: true,
} as const;
const ep =
(await db.query.epcProperty.findFirst({
@ -563,6 +573,7 @@ async function resolvePropertyDescriptors(
builtForm: null,
yearBuilt: null,
numberOfRooms: null,
tenure: null,
};
}
@ -583,11 +594,16 @@ async function resolvePropertyDescriptors(
const ageBand = mainPart?.constructionAgeBand ?? null;
const yearBuilt = ageBand ? AGE_BAND_YEARS[ageBand] ?? ageBand : null;
const tenure = ep.tenure
? TENURE_LABELS[ep.tenure] ?? ep.tenure
: null;
return {
propertyType,
builtForm,
yearBuilt,
numberOfRooms: ep.habitableRoomsCount ?? null,
tenure,
};
}
@ -642,6 +658,7 @@ export async function resolvePropertyMeta(propertyId: string) {
builtForm: descriptors?.builtForm ?? propertyMeta.builtForm,
yearBuilt: descriptors?.yearBuilt ?? propertyMeta.yearBuilt,
numberOfRooms: descriptors?.numberOfRooms ?? propertyMeta.numberOfRooms,
tenure: descriptors?.tenure ?? propertyMeta.tenure,
currentSapPoints:
headline.currentSapPoints ?? propertyMeta.currentSapPoints,
currentEpcRating: