Per domain semantics: lodged_* on property_baseline_performance is the
gov-registry (actual) figure, effective_* is the modelling-adjusted baseline.
Use the lodged columns for the "current" carbon/primary-energy display and the
individual cost columns (summed) for bills. Bills return NULL when no baseline
row exists, so they're excluded from AVG/SUM rather than shown as £0.
(property_baseline_performance is still unwritten DB-wide; this makes the reads
correct for when the pipeline populates it.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
For new-approach properties the modelling pipeline currently writes only
epc_property + epc_energy_element + plan/recommendation — property_baseline_
performance, epc_property_energy_performance metrics and the property-row
headline columns are not yet populated.
- layout: guard propertyMeta.detailsEpc?.estimated (detailsEpc can be absent)
- resolveConditionReport: degrade to an all-Unknown report instead of throwing
when the EPC graph/legacy row is missing (no more 500s)
- getProperties: join recommendation via recommendation.plan_id instead of the
retired plan_recommendations table, so Plan Cost / recommendation SAP populate
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The new modelling pipeline no longer writes property_details_epc. Route all
EPC reads through src/lib/services/epcSources.ts, which branches on the cutoff
(property.updated_at >= 2026-06-01): legacy rows keep reading
property_details_epc; new-approach rows read epc_property (+ children),
property_baseline_performance, and plan/recommendation.
- per-property: resolveConditionReport (building passport),
resolveDetailsEpcMeta (/api/property-meta)
- aggregates: shared carbon/bills/energy/estimated/expired/floor-area/
lodgement/mainfuel SQL fragments + newApproachJoins, wired into the
portfolio list + filters, reporting metrics, and both scenario metrics routes
estimated = predicted-only EPC. Gracefully omits gap fields for new
properties (mainfuel, energyTariff, floorHeight, installed-measures bill
adjustment, SAP-05 likely-downgrade).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a `source` discriminator to `epc_property` so a property can hold a
lodged and a predicted EPC at the same time, per the EPC Prediction
production-wiring branch in the Model repo (docs/MIGRATION_NOTE_predicted_epc_source.md).
- `source` text NOT NULL default 'lodged' — backfills every existing row as
a real lodged EPC.
- Unique index becomes (property_id, portfolio_id, source) so lodged +
predicted rows can coexist for the same property/portfolio.
- New (property_id, source) index — lodged/predicted reads filter on both.
Allowed values: 'lodged' | 'predicted'.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Self-contained brief to start a fresh context implementing the per-Property fact
layer in the bulk_upload_finaliser: locked decisions, the four-input assembly,
the two open hazards (classifier-CSV↔combiner-output join key; property_id for
no-UPRN rows), candidate architectures, and a first-steps list. v1 (async
finalise writing `property`) is shipped and working.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The async finaliser (ADR-0005) introduced the `finalising` status, but the
server page's STATUS_CONFIG had no entry for it, so it fell through to the
`ready_for_processing` fallback ("Awaiting column mapping") and never mounted the
live poller — the page looked stuck even though the Lambda had inserted the
properties and written `complete`.
- Add the `finalising` card ("Uploading to ARA") to STATUS_CONFIG.
- Render OnboardingProgress during `finalising` so it polls live.
- Refresh the server page once when the poll first sees a terminal status
(guarded by a new `serverStatus` prop to avoid a loop; uses react-query v4
onSuccess, no useEffect) so it advances to the "Processing complete" card.
- Add a `finalising` → "Uploading to ARA" badge on the uploads list.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
For uploads with classifier columns, surface the classifier's
description→enum assumptions on the awaiting_review screen so the user can
correct any (written source='user') and acknowledge before Finalise.
Previously only the multi-entry order step existed, so non-multi-entry
uploads got no classification review at all and the assumptions were
applied silently.
- detectMultiEntry: capture a sample whenever classifier columns are
mapped (largest-count row if multi-entry, else first classified row);
the sample now carries all classifier columns. "sample != null" means
"there is something to verify"; largestCount >= 2 stays the multi-entry
signal.
- setVerifyAck + verify-classification PATCH route + useConfirmVerification.
- VerifyClassificationPanel (Step 1); MultiEntryOrderingPanel slimmed to
order-only with read-only classification annotation; canFinalize gated
on both steps where each applies.
- Unit tests for detectMultiEntry + ordering helpers.
The verify_ack column + 0219 migration landed separately via #303.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
#298: read the classifier's resolved enums for the multi-entry sample's
entries (joined from landlord_*_overrides by normalized description) and show
each beside the raw text, or "not classified" when absent.
#299: make each classification editable — a dropdown of the category's valid
enum values whose selection upserts the override by (portfolio, description)
with source='user', so the classifier never re-clobbers it. UI notes the
portfolio-wide blast radius. Verification ack is folded into the existing
order-confirm (no separate flag/migration); editing is optional review.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds the multiEntryOrdering jsonb column + interactive order picker: the
largest-count multi-entry sample is shown with a building-part dropdown per
file position (one Main building + Extensions), validated as a permutation.
A PATCH route persists { count: permutation } + confirmed, and Finalise is
disabled until the ordering is confirmed when the upload is multi-entry.
Migration for the new column is intentionally not included here — generated
after origin/main is merged (its multi_entry_summary migration lands first).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>