Model/domain/epc_prediction/README.md
Khalim Conn-Kowlessar f66e2cb020 docs(epc-prediction): module README + end-to-end showcase test
README at domain/epc_prediction/README.md — the flow diagram, where each piece
lives, links to the ADRs/CONTEXT/handover/migration note, and a runnable test
command. The team's entry point.

tests/e2e/test_epc_prediction_e2e.py — the whole gap-fill flow against the REAL
Postgres Unit of Work + EPC/Property repositories + EpcComparablePropertiesRepository
+ EpcPrediction, with only the three external HTTP clients faked (EPC API,
geospatial S3, Solar). Proves: EPC-less Property → Ingestion predicts from its
postcode cohort → persists to the predicted slot → reloaded Property resolves
effective_epc via source_path == "predicted". The canonical "see it in action".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 04:13:30 +00:00

69 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# EPC Prediction
Predict a structured `EpcPropertyData` for an **EPC-less** UK home from its
postcode neighbours, so it flows through the rest of the pipeline (Baseline, Bill
Derivation, Modelling) exactly like a home that has an EPC. It is **deterministic
neighbour synthesis** — cohort modes + a coherent template + per-component
weighting — **not ML**. ~30% of UK homes (typically long-tenure) have no EPC.
- **Design**: [ADR-0029](../../docs/adr/0029-epc-prediction-from-comparable-properties.md) (algorithm),
[ADR-0030](../../docs/adr/0030-epc-prediction-validation-is-sap-version-aware-and-component-first.md) (validation),
[ADR-0031](../../docs/adr/0031-epc-prediction-production-wiring.md) (production wiring).
- **Glossary**: see *EPC Prediction*, *Comparable Properties*, *Component
Accuracy*, *EPC Anomaly Flag* in [CONTEXT.md](../../CONTEXT.md).
## The flow (gap-fill)
```
Ingestion: a Property has no lodged EPC (epc_fetcher.get_by_uprn → None)
├─ resolve its attributes (property_type/built_form/wall) from Landlord Overrides
│ └─ property_type unknown? → GATED OUT, not predicted (no national defaults)
├─ build a PredictionTarget (postcode + coordinates + attributes)
├─ ComparableProperties repo: fetch the postcode cohort (search → per-cert → coords)
├─ select_comparables(): filter to the reference cohort (type-hard, built-form-soft)
├─ EpcPrediction.predict(): synthesise the picture (modes + template + donor + weights)
└─ persist to the Property's PREDICTED slot (source = "predicted")
Modelling/Baseline: Property.effective_epc returns the predicted picture
(source_path == "predicted"), scored like any other Effective EPC.
```
A lodged EPC always wins — prediction is last-resort gap-fill.
## Where the pieces live
| Concern | File |
|---|---|
| Synthesis (modes, template, heating donor, geo/recency/similarity weights) | `epc_prediction.py` |
| Cohort selection (filter-then-relax ladder) | `comparable_properties.py` |
| Target assembly + eligibility gate | `prediction_target.py` |
| Cohort IO port + EPC-API/geospatial adapter | `repositories/comparable_properties/` |
| Predicted-EPC persistence (`source` discriminator) | `repositories/epc/` |
| `predicted` source path on the aggregate | `domain/property/property.py` |
| Ingestion wiring (gate → predict → persist) | `orchestration/ingestion_orchestrator.py` |
| Validation (leave-one-out, component-first) + ratcheting gate | `validation.py`, `tests/domain/epc_prediction/test_component_accuracy_gate.py` |
## See it run
`tests/e2e/test_epc_prediction_e2e.py` — the whole flow against the real DB +
repos, only the external HTTP clients faked. Start there.
## Status
Algorithm + validation: **built**. Production gap-fill wiring: **built behind
seams** (slices 5a5e). Two things finish it — a DB migration and the
`property_overrides` read adapter — see
[the wiring handover](../../docs/HANDOVER_EPC_PREDICTION_WIRING.md) and
[the migration note](../../docs/MIGRATION_NOTE_predicted_epc_source.md).
**EPC Anomaly Flags** (predict for *every* home, compare to lodged) is the
designed next step the storage already supports.
## Run the tests
```bash
PYTHONPATH=. python -m pytest tests/e2e/test_epc_prediction_e2e.py \
tests/domain/epc_prediction tests/orchestration/test_ingestion_prediction.py \
tests/repositories/comparable_properties tests/repositories/epc/test_epc_predicted_slot.py \
-o addopts="" -q
```