Commit graph

6152 commits

Author SHA1 Message Date
Daniel Roth
c22ee3821b Merge branch 'main' into feature/handle-new-magicplan-response-structure 2026-06-08 09:57:26 +00:00
Daniel Roth
41a40c9ba0 Fix Pylance unknowns in SQLModel table tests and correct pytest paths 2026-06-08 09:56:54 +00:00
Daniel Roth
7a1aaf4965 Window carries no opening_type — ventilation table is the sole persistence point 🟩 2026-06-08 09:45:15 +00:00
Daniel Roth
3f5b3cf172 Window carries no opening_type — ventilation table is the sole persistence point 🟥 2026-06-08 09:43:41 +00:00
Jun-te Kim
98297f803a
Merge pull request #1186 from Hestia-Homes/feature/landlord_data
fix
2026-06-05 20:03:55 +01:00
Jun-te Kim
e60ca6ee5d source of the problem in address2uprn 2026-06-05 19:03:33 +00:00
Jun-te Kim
8b9dcc73f2 fix 2026-06-05 17:24:17 +00:00
Daniel Roth
c6f94b576b remove commented out import from dockerfile 2026-06-05 16:17:08 +00:00
Daniel Roth
cf6c63f059 correct orchestrator tests 2026-06-05 16:13:04 +00:00
Daniel Roth
11fd88bcb0 rename database environment variables 2026-06-05 16:04:33 +00:00
Daniel Roth
e84de954fb define MagicPlanConfig class to get environment variables 2026-06-05 15:46:32 +00:00
Jun-te Kim
0320f240cd
Merge pull request #1184 from Hestia-Homes/feature/landlord_data
Feature/landlord data
2026-06-05 16:40:00 +01:00
Jun-te Kim
9427a6d40b description reverted 2026-06-05 15:38:36 +00:00
Jun-te Kim
411ea79b80 permissions 2026-06-05 15:37:21 +00:00
Daniel Roth
198d2afdb1 Merge branch 'main' into feature/handle-new-magicplan-response-structure 2026-06-05 14:35:56 +00:00
Daniel Roth
8e349704b1 move magic plan handler to applications/ 2026-06-05 14:33:26 +00:00
Daniel Roth
641420be00 [UNRELATED] update sero address list for sharepoint file renaming 2026-06-05 14:22:09 +00:00
Jun-te Kim
6778c427bc
Merge pull request #1181 from Hestia-Homes/feature/landlord_data
property override
2026-06-05 15:16:06 +01:00
Daniel Roth
37b5a3a6e5 move domain code out of datatypes/domain 2026-06-05 14:07:28 +00:00
Daniel Roth
050f983152 Extract door height from API response into height_mm 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 13:53:22 +00:00
Daniel Roth
db3477d6bb Extract door height from API response into height_mm 🟥
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 13:49:57 +00:00
Daniel Roth
b3b4ae2191 Convert Door.width_mm to store actual millimetres (multiply size.x by 1000)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 13:30:54 +00:00
Daniel Roth
bffac89abb Fix pyright strict violations in mapper and test imports 🟪
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 13:10:59 +00:00
Daniel Roth
5797ddbda6 Persist window and door ventilation via SQLModel tables 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 13:06:15 +00:00
Daniel Roth
192a3cf20f Persist window and door ventilation via SQLModel tables 🟥
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 13:02:47 +00:00
Daniel Roth
0211fb8092 Migrate all MagicPlan tests to single new-format fixture 🟪
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 12:59:56 +00:00
Daniel Roth
8deaba1f94 Glass door ventilation carries opening_type from custom_displayable_fields 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 12:54:58 +00:00
Daniel Roth
45925d48eb Reclassify doorglass wall items as Window domain objects 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 12:54:04 +00:00
Daniel Roth
cdefa65887 Reclassify doorglass wall items as Window domain objects 🟥
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 12:53:45 +00:00
Daniel Roth
1dd3baeac5 Map door custom_displayable_fields to DoorVentilation 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 12:52:36 +00:00
Daniel Roth
06816c3f9c Map door custom_displayable_fields to DoorVentilation 🟥
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 12:51:57 +00:00
Daniel Roth
cda2091e23 Window with no custom_displayable_fields yields ventilation=None 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 12:51:28 +00:00
Daniel Roth
9a3987b4f1 Map window custom_displayable_fields to WindowVentilation 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 12:49:52 +00:00
Daniel Roth
10bbf0bb60 Map window custom_displayable_fields to WindowVentilation 🟥
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 12:47:50 +00:00
Jun-te Kim
b07db1ef6b property override 2026-06-05 12:18:13 +00:00
Daniel Roth
5a582bbff0 Merge branch 'main' into feature/handle-new-magicplan-response-structure 2026-06-05 11:01:28 +00:00
KhalimCK
3bdfa0287c
Merge pull request #1169 from Hestia-Homes/feature/per-cert-mapper-validation
Feature/per cert mapper validation
2026-06-05 11:50:11 +01:00
Khalim Conn-Kowlessar
a6b798218f fix: normalize empty API sap_roof_windows to None for round-trip fidelity
`test_epc_property_data_round_trips[RdSAP-Schema-21.0.1]` failed with
`sap_roof_windows: None != []` — a normalization mismatch, not lost data.
The 21.0.1 fixture has no roof windows, but the 21.0.1 API mapper emitted
an empty list `[]` while the domain field defaults to None
(`Optional[List[SapRoofWindow]] = None`), the 21.0.0 path yields None, and
the persistence reload yields None (roof windows aren't stored yet — doc
§2.4). Append `or None` so "no roof windows" has one canonical
representation across mapper paths and the round-trip.

No data-loss change: a cert WITH roof windows still produces the
populated list (test_golden_fixtures pins a 6-roof-window cert), and the
§2.4 roof-window persistence gap remains separately tracked. Full
sap10_calculator + documents_parser + epc-repository suites pass (2420);
pyright unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 10:45:44 +00:00
Daniel Roth
cfdd5a146a
Merge pull request #1179 from Hestia-Homes/increase-rds-storage
Increase size of RDS from 20GB to 50GB
2026-06-05 11:40:18 +01:00
Daniel Roth
47dd6ca20e postgres go bigger 2026-06-05 10:39:05 +00:00
Khalim Conn-Kowlessar
5597a8b87e review: bind test inputs in Arrange for the wall-insulation-thickness tests
PR feedback (dancafc): the `_api_resolve_wall_insulation_thickness` tests
passed literals straight into the Act call. Bind them as named variables
in Arrange (`lodged_thickness`, `measured_value_mm`, `ni_lodgement`) and
have the asserts reference those names, so the Act line reads
declaratively and the inputs/expectations are stated once. Applied to all
three tests in the class. No behaviour change; tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 10:26:17 +00:00
Khalim Conn-Kowlessar
86b875af35 review: clearer room-in-roof area variable names in heat_transmission
PR feedback (dancafc): the simplified room-in-roof branch used cryptic
locals. Rename for clarity (behaviour-unchanged; the geom dict keys and
the builder-function locals are untouched):

  rr_a_rr      -> rr_roof_area          (the worksheet's simplified A_RR)
  rr_common    -> rr_common_wall_area
  rr_gable     -> rr_gable_area
  a_rr_final   -> rr_residual_roof_area  (leftover roof-going area after
                                          deducting perimeter walls/gables
                                          /rooflights — takes the roof U)

Names now mirror the `rr_*_area_m2` geom keys they read from and say
"area of what". Added a one-line note that `rr_roof_area` is the RdSAP 10
§3.10.1 A_RR. Pyright unchanged; 1087 heat-transmission/cascade-pin tests
pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 10:18:58 +00:00
Daniel Roth
ebd6f1623f Merge branch 'main' into feature/handle-new-magicplan-response-structure 2026-06-05 10:16:14 +00:00
Khalim Conn-Kowlessar
77f90e144e review: store epc_building_part.wall_insulation_thickness as JSONB
PR feedback (dancafc): the SQLModel column was Optional[str], but the
domain `SapBuildingPart.wall_insulation_thickness` is Optional[Union[str,
int]] — `_api_resolve_wall_insulation_thickness` returns an int mm when the
API lodges `wall_insulation_thickness == "measured"` (SAP 10.2 §5.7 /
Table 8). The plain str column round-trips that int back as the string
"100", corrupting the Table 8 insulated-wall U-value lookup.

This column was missed in the round-trip-fidelity §1 JSONB sweep
(#1129) — its `Union[str, int]` sibling `roof_insulation_thickness` was
converted, but `wall_insulation_thickness` was not, and no 21.0.0/21.0.1
fixture lodges "measured" so the gap stayed latent. Convert to JSONB
(matching `roof_insulation_thickness` / `flat_roof_insulation_thickness`),
align the column type to Optional[Union[str, int]] (also removes a pyright
type-mismatch), record it in the migration doc §1, and add a round-trip
guard test asserting an int survives as an int (fails as '100' == 100 on
the old str column).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 10:07:24 +00:00
Khalim Conn-Kowlessar
c882cb2c95 review: typehint Optional locals around _parse_thickness_mm call sites
PR feedback (dancafc): `_parse_thickness_mm` handles a None input and
returns Optional[int], so its call-return locals — and the Optional[str]
raws they read from `_local_val` — read clearer when annotated. Annotates
`thickness_raw`/`ins_thickness_raw: Optional[str]` and
`thickness_mm`/`insulation_thickness_mm: Optional[int]` at all four call
sites (_wall_details_from_lines, _alternative_walls_from_lines,
_roof_details_from_lines, _floor_details_from_lines), plus the adjacent
`u_val_raw`/`default_u` Optional pair in _floor_details_from_lines for
consistency. Matches the project convention of typehinting call-return
locals. No behaviour change; pyright clean, 569 parser tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:56:06 +00:00
Khalim Conn-Kowlessar
218840db98 docs: handover for the open window-extraction work on the double_glazing fixture
Captures the diagnosis so the next agent doesn't re-derive it: what's done
(S0380.235-237), what's confirmed correct (calculator U-adjustment, party
wall, glazing labels), the worksheet pin targets, and the two open causes —
crucially the 000516 trap (byte-identical Summary data classified as a roof
window there but a wall window here, so flipping the U>3 rule regresses
000516). Includes a rebuildable tracer recipe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:47:29 +00:00
Khalim Conn-Kowlessar
14a27c7a61 Merge branch 'feature/per-cert-mapper-validation' of https://github.com/Hestia-Homes/Model into feature/per-cert-mapper-validation
# Conflicts:
#	backend/documents_parser/tests/test_summary_pdf_mapper_chain.py
#	tests/domain/sap10_calculator/worksheet/test_heat_transmission.py
2026-06-05 09:47:29 +00:00
Khalim Conn-Kowlessar
8133521c43 S0380.237: map "Secondary glazing - Low emissivity" → SAP 10.2 code 12
Completes the secondary-glazing family. S0380.235 mapped the unknown-data
(7) and normal-emissivity (11) secondary variants; the RdSAP-21.0.1
`glazed_type` enum also defines code 12 "secondary glazing, low
emissivity", whose Elmhurst §11 label "Secondary glazing - Low
emissivity" was unmapped and would strict-raise. Cascade code 12 carries
the same daylight/solar bucket as 7/11 (g_L=0.80, g⊥=0.76); the lodged
manufacturer U/g drive §3/§6. With this the double family (codes 1/2/3/
7/13 via their Elmhurst phrasings) and the secondary family (4/11/12) are
fully covered. Coverage test extended.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:35:35 +00:00
Khalim Conn-Kowlessar
ea35bed24c S0380.236: extension party-wall type read independently of "As Main Wall"
RdSAP 10 §3.3: "As Main Wall: Yes" makes an extension inherit the main
dwelling's external wall CONSTRUCTION only — the party wall type is
lodged separately per building part in the Summary §7 block and may
differ. `_extract_extensions` was copying `main_walls.party_wall_type`
into the inherited WallDetails, so every extension reused the main's
party wall U.

On the double_glazing fixture (Summary_001431) the Main lodges party
"CU Cavity masonry unfilled" (SAP10 wall_construction 4 → u_party_wall
0.5) but the 1st Extension lodges "U Unable to determine" (→ 0 → RdSAP
default 0.25). Pre-fix both building parts used 0.5, inflating worksheet
(32) party-wall heat loss by 6.56 W/K (Ext1 26.25 m² × 0.25). After the
fix worksheet (32) is exact: ours 32.573 vs worksheet 32.5725.

Now reads the extension's own "Party Wall Type" from its §7 chunk,
falling back to the main's only when the extension lodges none. Adds a
fixture + test asserting Main=4 / Ext=0 with distinct u_party_wall.
Suite 2413 pass; no cohort regression.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:19:43 +00:00
Khalim Conn-Kowlessar
3e45b7fa3b S0380.235: map the remaining Elmhurst §11 glazing labels to SAP 10.2 Table 6b
The double_glazing recommendation fixture (Summary_001431) exercises every
RdSAP-21 §11 glazing lodging in one cert; five labels were missing from
`_ELMHURST_GLAZING_LABEL_TO_SAP10` and strict-raised `UnmappedElmhurstLabel`:

  "Secondary glazing"                     -> 7   (Table 6b "secondary glazing", g_L 0.80)
  "Secondary glazing - Normal emissivity" -> 11  (RdSAP-21 secondary normal-E, g_L 0.80)
  "Triple pre 2002"                       -> 10  (triple pre-2002, g_L 0.70)
  "Triple with unknown install date"      -> 6   (generic triple glazed, g_L 0.70)
  "Single glazing, known data"            -> 15  (single known-data, g_L 0.90)

The glazing code's only cascade effect is the §5 (66)..(67) daylight factor
g_L in `_G_LIGHT_BY_GLAZING_CODE` (single 0.90 / double+secondary 0.80 /
triple 0.70); the lodged manufacturer U-value and solar_transmittance drive
§3 / §6 directly (`_g_perpendicular` prefers the lodged value). Codes are the
semantically-exact RdSAP-21 rows within the correct g_L bucket, kept distinct
for the strict-raise audit trail. Adds a full-coverage test over all 13
distinct labels. Suite 2413 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 08:15:11 +00:00