mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
Legacy property columns no longer resolve type or built form 🟩
ADR-0056 amended: override and EPC own type/form facts; a property with neither is Unknown whatever the legacy columns say. Mirror columns removed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
ddd64a9297
commit
07190fc332
3 changed files with 19 additions and 27 deletions
|
|
@ -52,12 +52,12 @@ class _ComponentResolution:
|
|||
"""How one filterable component (property_type / built_form) resolves at
|
||||
each ADR-0056 precedence level: which override row names it, how its RdSAP
|
||||
numeric codes map (text labels pass through as-is), and which columns hold
|
||||
it on the EPC and the legacy property row."""
|
||||
it on the EPC. The legacy property.property_type / built_form columns are
|
||||
NOT consulted (ADR-0056 amendment — overrides own those facts)."""
|
||||
|
||||
override_component: str
|
||||
codes: dict[str, str]
|
||||
epc_columns: tuple[str, ...]
|
||||
legacy_column: str
|
||||
|
||||
|
||||
_PROPERTY_TYPE = _ComponentResolution(
|
||||
|
|
@ -71,7 +71,6 @@ _PROPERTY_TYPE = _ComponentResolution(
|
|||
},
|
||||
# A cert without the property_type column falls back to its dwelling_type.
|
||||
epc_columns=("property_type", "dwelling_type"),
|
||||
legacy_column="property_type",
|
||||
)
|
||||
|
||||
_BUILT_FORM = _ComponentResolution(
|
||||
|
|
@ -85,7 +84,6 @@ _BUILT_FORM = _ComponentResolution(
|
|||
"6": "Enclosed Mid-Terrace",
|
||||
},
|
||||
epc_columns=("built_form",),
|
||||
legacy_column="built_form",
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -94,12 +92,12 @@ def resolve_filtered_property_ids(
|
|||
) -> list[FilteredProperty]:
|
||||
"""Resolve *filters* against *portfolio_id* per ADR-0056: base set is the
|
||||
portfolio's rows with ``marked_for_deletion = false``; property_type /
|
||||
built_form resolve override → lodged EPC → predicted EPC → legacy columns
|
||||
→ "Unknown". Filters AND-combine; an absent key is unconstrained."""
|
||||
built_form resolve override → lodged EPC → predicted EPC → "Unknown".
|
||||
Filters AND-combine; an absent key is unconstrained."""
|
||||
# IS NOT TRUE rather than = false: the FE schema defaults the flag, but a
|
||||
# NULL must never silently exclude a property.
|
||||
base_sql = (
|
||||
"SELECT id, postcode, property_type, built_form FROM property"
|
||||
"SELECT id, postcode FROM property"
|
||||
" WHERE portfolio_id = :portfolio_id"
|
||||
" AND marked_for_deletion IS NOT TRUE"
|
||||
)
|
||||
|
|
@ -109,14 +107,7 @@ def resolve_filtered_property_ids(
|
|||
params["postcodes"] = filters.postcodes
|
||||
base_sql += " ORDER BY id"
|
||||
candidates = [
|
||||
_Candidate(
|
||||
property_id=int(row[0]),
|
||||
postcode=row[1],
|
||||
legacy_values={
|
||||
_PROPERTY_TYPE.legacy_column: row[2],
|
||||
_BUILT_FORM.legacy_column: row[3],
|
||||
},
|
||||
)
|
||||
_Candidate(property_id=int(row[0]), postcode=row[1])
|
||||
for row in session.connection().execute(text(base_sql), params)
|
||||
]
|
||||
|
||||
|
|
@ -142,7 +133,6 @@ def resolve_filtered_property_ids(
|
|||
class _Candidate:
|
||||
property_id: int
|
||||
postcode: Optional[str]
|
||||
legacy_values: dict[str, Optional[str]]
|
||||
|
||||
|
||||
def _resolved_component_values(
|
||||
|
|
@ -150,7 +140,7 @@ def _resolved_component_values(
|
|||
) -> dict[int, str]:
|
||||
"""Each candidate's effective value for *component* per the ADR-0056
|
||||
precedence: override (building_part 0) → lodged EPC → predicted EPC →
|
||||
legacy column → "Unknown"."""
|
||||
"Unknown"."""
|
||||
property_ids = [c.property_id for c in candidates]
|
||||
|
||||
override_rows = session.connection().execute(
|
||||
|
|
@ -186,7 +176,6 @@ def _resolved_component_values(
|
|||
by_override.get(c.property_id)
|
||||
or by_epc_source["lodged"].get(c.property_id)
|
||||
or by_epc_source["predicted"].get(c.property_id)
|
||||
or c.legacy_values.get(component.legacy_column)
|
||||
or _UNKNOWN
|
||||
)
|
||||
for c in candidates
|
||||
|
|
|
|||
|
|
@ -40,9 +40,7 @@ lands in both codebases and amends this ADR.
|
|||
built_form: 1=Detached, 2=Semi-Detached, 3=End-Terrace, 4=Mid-Terrace,
|
||||
5=Enclosed End-Terrace, 6=Enclosed Mid-Terrace. Text passes through
|
||||
as-is;
|
||||
3. else the legacy `property.property_type` / `property.built_form`
|
||||
columns;
|
||||
4. else **"Unknown"** — a selectable filter value meaning exactly this
|
||||
3. else **"Unknown"** — a selectable filter value meaning exactly this
|
||||
bucket (no resolvable value at any level).
|
||||
4. An absent filter key is unconstrained; present keys combine with **AND**.
|
||||
|
||||
|
|
@ -57,3 +55,11 @@ lands in both codebases and amends this ADR.
|
|||
- Drift risk is accepted and mitigated by this document; a cross-repo
|
||||
contract test (same fixture set, both implementations) is the natural
|
||||
follow-on if drift ever bites.
|
||||
|
||||
## Amendment (2026-07-08): the legacy property columns are not consulted
|
||||
|
||||
The original rule fell back to `property.property_type` / `property.built_form`
|
||||
before "Unknown". Those columns are legacy: the override layer owns
|
||||
user-supplied type/form facts, so a property with no override and no EPC is
|
||||
**"Unknown"** whatever the legacy columns say. The app's preview must apply
|
||||
the same amendment.
|
||||
|
|
|
|||
|
|
@ -57,10 +57,7 @@ class PropertyRow(SQLModel, table=True):
|
|||
has_recommendations: Optional[bool] = Field(default=None)
|
||||
updated_at: Optional[datetime] = Field(default=None)
|
||||
|
||||
# Columns the Modelling Run filter resolution reads (ADR-0056): the base-set
|
||||
# exclusion flag and the legacy type/form columns (the last resort before
|
||||
# "Unknown" in the resolution precedence). NOT NULL / defaulted in the FE
|
||||
# schema; nullable mirrors are safe — prod enforces the real constraints.
|
||||
# The Modelling Run filter resolution's base-set exclusion flag (ADR-0056).
|
||||
# The legacy property_type / built_form columns are deliberately NOT
|
||||
# mirrored: overrides and EPCs own those facts (ADR-0056 amendment).
|
||||
marked_for_deletion: Optional[bool] = Field(default=None)
|
||||
property_type: Optional[str] = Field(default=None)
|
||||
built_form: Optional[str] = Field(default=None)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue