Classify the landlord Glazing column into a glazing category 🟩

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jun-te Kim 2026-06-19 13:36:34 +00:00
parent 0b782bd1a6
commit db95205fc5
3 changed files with 107 additions and 0 deletions

View file

@ -8,6 +8,7 @@ from applications.landlord_description_overrides.landlord_description_overrides_
LandlordDescriptionOverridesTriggerBody,
)
from domain.epc.built_form_type import BuiltFormType
from domain.epc.glazing_type import GlazingType
from domain.epc.main_fuel_type import MainFuelType
from domain.epc.property_type import PropertyType
from domain.epc.roof_type import RoofType
@ -25,6 +26,9 @@ from infrastructure.postgres.engine import commit_scope, make_engine, make_sessi
from infrastructure.postgres.landlord_built_form_type_override_table import (
LandlordBuiltFormTypeOverrideRow,
)
from infrastructure.postgres.landlord_glazing_override_table import (
LandlordGlazingOverrideRow,
)
from infrastructure.postgres.landlord_main_fuel_override_table import (
LandlordMainFuelOverrideRow,
)
@ -116,6 +120,16 @@ def _build_columns(
session, LandlordMainFuelOverrideRow
),
),
"glazing": lambda src: ClassifiableColumn(
name="glazing",
source_column=src,
classifier=ChatGptColumnClassifier(
chat_gpt, GlazingType, GlazingType.UNKNOWN
),
repo=LandlordOverridesRepository[GlazingType](
session, LandlordGlazingOverrideRow
),
),
}
columns: list[ClassifiableColumn[Any]] = []

View file

@ -0,0 +1,24 @@
from enum import Enum
class GlazingType(Enum):
"""A landlord-supplied glazing description, as resolved by the
landlord-description-overrides context.
Each member's value is the canonical glazing description (type + era) that
the glazing Simulation Overlay
(``domain/epc/property_overlays/glazing_overlay.py``) decomposes into the
SAP10 ``glazing_type`` code the calculator's Table-24 cascade reads — so the
member values here MUST stay in lock-step with that overlay's
``_GLAZING_CODES`` keys. The era matters: double-glazing pre-2002 and
2002-onward resolve to different codes (and U-values). ``UNKNOWN`` covers
values the classifier cannot resolve, and any glazing not yet given a
verified overlay code (it leaves the lodged cert's glazing untouched).
"""
SINGLE = "Single glazing"
DOUBLE_POST_2002 = "Double glazing, 2002 or later"
DOUBLE_PRE_2002 = "Double glazing, pre-2002"
TRIPLE_PRE_2002 = "Triple glazing, pre-2002"
TRIPLE_POST_2002 = "Triple glazing, 2002 or later"
UNKNOWN = "Unknown"

View file

@ -0,0 +1,69 @@
"""SQLModel mirror of the ``landlord_glazing_overrides`` Drizzle table.
The schema source of truth lives in the ``assessment-model`` TS repo
(`src/app/db/schema/landlord_overrides.ts`). The migrations are owned there;
this row class only mirrors the columns so the Python lambda can read/write.
See ADR-0003. Shape mirrors ``LandlordWallTypeOverrideRow`` -- the only
differences are the table name, the ``glazing`` pgEnum on ``value``, and the
unique-constraint name.
"""
from datetime import datetime, timezone
from typing import ClassVar
from uuid import UUID, uuid4
from sqlalchemy import BigInteger, Column, UniqueConstraint
from sqlalchemy import Enum as SAEnum
from sqlmodel import Field, SQLModel
from domain.epc.glazing_type import GlazingType
from infrastructure.postgres.landlord_override_enums import override_source_sa_enum
class LandlordGlazingOverrideRow(SQLModel, table=True):
__tablename__: ClassVar[str] = "landlord_glazing_overrides" # pyright: ignore[reportIncompatibleVariableOverride]
__table_args__: ClassVar[tuple[UniqueConstraint, ...]] = ( # pyright: ignore[reportIncompatibleVariableOverride]
UniqueConstraint(
"portfolio_id",
"description",
name="landlord_glazing_overrides_portfolio_description_unique",
),
)
id: UUID = Field(default_factory=uuid4, primary_key=True)
# bigint to match the Drizzle ``portfolio_id`` FK; SQLModel's default int
# mapping is 32-bit Integer and would overflow once portfolio IDs exceed
# 2^31. The FK to ``portfolio.id`` is enforced by the Drizzle migration,
# not declared here -- the ``portfolio`` table is not modelled in Python.
portfolio_id: int = Field(
sa_column=Column(BigInteger, nullable=False, index=True),
)
description: str = Field(nullable=False)
value: GlazingType = Field(
sa_column=Column(
SAEnum(
GlazingType,
name="glazing",
values_callable=lambda cls: [m.value for m in cls], # pyright: ignore[reportUnknownLambdaType, reportUnknownMemberType, reportUnknownVariableType]
),
nullable=False,
),
)
# Shared SAEnum -- see ``landlord_override_enums`` for why this single
# instance is reused by every ``landlord_*_overrides`` row class.
source: str = Field(
sa_column=Column(override_source_sa_enum, nullable=False),
)
created_at: datetime = Field(
default_factory=lambda: datetime.now(timezone.utc),
nullable=False,
)
updated_at: datetime = Field(
default_factory=lambda: datetime.now(timezone.utc),
nullable=False,
)