Commit graph

753 commits

Author SHA1 Message Date
Khalim Conn-Kowlessar
6f0dcc0455 test(modelling): characterise the portfolio aggregation over plan_id
Pin the FE-facing aggregate_portfolio_recommendations (previously untested): it
sums a Scenario's default Recommendations onto the Scenario row, joining
Recommendation → Plan on recommendation.plan_id. Locks the m2m→plan_id read cut
for the FE-critical path, now testable thanks to the full-parity ScenarioModel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 22:54:15 +00:00
Khalim Conn-Kowlessar
c18968ba3c refactor(modelling): consolidate scenario + installed_measure into the subpackage
Move the scenario and installed_measure tables into
infrastructure/postgres/modelling/ as full-parity SQLModel definitions
(ScenarioModel, InstalledMeasureModel + MeasureType), completing the cluster
consolidation. backend/app/db/models/recommendations.py is now a pure
re-export shim.

ScenarioModel.goal is the PortfolioGoal enum (legacy planning branches on it),
sourced from domain/modelling/portfolio_goal.py; the repo's to_domain maps it to
its value string, so domain Scenario.goal is now the value ("Increasing EPC")
consistent with the orchestrator's check — fixing the latent name-vs-value
inconsistency the old str column masked (the scenario repo test stored the enum
*name*). Parity columns are nullable (mirror convention; live NOT-NULLs owned by
Drizzle).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 22:52:35 +00:00
Khalim Conn-Kowlessar
2fbd7147b7 refactor(modelling): move PortfolioGoal to domain/modelling/
PortfolioGoal is domain vocabulary (a Scenario's goal — legacy planning branches
on PortfolioGoal.INCREASING_EPC), so it belongs in domain/ co-located with
scenario.py, mirroring how domain/epc/wall_type.py holds an enum that
infrastructure/ imports. This lets the consolidated ScenarioModel (next slice)
source the goal enum from domain without an infra→backend dependency.
portfolio.py keeps a re-export so every existing
`from ...portfolio import PortfolioGoal` caller is unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 22:44:48 +00:00
Khalim Conn-Kowlessar
01c2c3910e refactor(modelling): rename the cluster SQLModel classes …Row → …Model
Standardise the modelling persistence classes on the …Model suffix (PlanModel,
RecommendationModel, RecommendationMaterialModel) — matching the epc_property
precedent and the legacy names the rest of backend/ already imports, so the
shim's plan re-export becomes literal (no alias) and the eventual shim deletion
needs zero renames. The …Row→…Model sweep for the non-cluster tables
(Property/Task/Material/…) waits until their live legacy …Model counterparts
are retired, to avoid reintroducing dual-definition collisions. No behaviour
change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 22:42:21 +00:00
Khalim Conn-Kowlessar
b97d06882f feat(modelling): drop the plan_recommendations m2m
Stop writing the m2m (remove create_plan_recommendations + its call, the bulk
link insert and the now-dead plan_ids_by_index, and the plan_recommendations
delete in delete_property_batch) and remove the PlanRecommendationRow model +
its shim alias and the test_export fixture inserts. Measures now link to their
Plan solely via recommendation.plan_id (writers set it, readers join on it).

The live drop of the plan_recommendations table is the FE-owned Drizzle
migration documented in docs/migrations/recommendation-plan-id.md, sequenced
after the read-cut + backfill.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 21:13:00 +00:00
Khalim Conn-Kowlessar
af5dbe325d feat(modelling): cut plan→recommendation readers onto plan_id
Rewrite the three structurally-identical m2m-join readers
(portfolio_functions.aggregate_portfolio_recommendations,
Outputs.get_recommendations_from_db, export get_recommendations) to join
PlanModel directly via recommendation.plan_id, dropping the plan_recommendations
join and its now-unused import. The writers set plan_id (prior slice), so the
rows resolve. test_export pins the export reader through the cut (its fixtures
now set recommendation.plan_id). A portfolio_functions DB characterization test
lands with the scenario consolidation (which provides the full-parity scenario
table the aggregation writes to).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 21:09:43 +00:00
Khalim Conn-Kowlessar
27fcc5b184 feat(modelling): legacy writers set recommendation.plan_id (dual-write)
upload_recommendations and bulk_upload_recommendations_and_materials now set
plan_id on each recommendation row (the plan id is already in scope), while
still writing the plan_recommendations m2m — the dual-write that lets readers
move onto plan_id with no breakage during the transition (ADR-0017 amendment /
docs/migrations/recommendation-plan-id.md). The m2m write is removed in a later
slice once no reader depends on it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 21:01:56 +00:00
Khalim Conn-Kowlessar
c1c7b06f09 refactor(modelling): consolidate plan/recommendation models into infrastructure
Move the live plan, recommendation, recommendation_materials and (retiring)
plan_recommendations tables into a new infrastructure/postgres/modelling/
subpackage as single SQLModel definitions (the epc_property pattern), absorbing
the rebuild's partial PlanRow/RecommendationRow mirrors and carrying full
legacy column parity plus recommendation.plan_id. Out-of-cluster references are
plain indexed ints (mirror convention); the live FKs are owned by the Drizzle
schema. backend/app/db/models/recommendations.py becomes a re-export shim
(ScenarioModel/InstalledMeasure stay for a later slice).

Fix the export conftest to create SQLModel-first (so Base funding_package's FK
to the now-SQLModel plan resolves) and skip the redundant drop_all on its
function-scoped throwaway DB (the epc enum type is now shared across both
metadatas). Resolves the pre-existing dual-definition collision: the rebuild
and legacy export suites are now co-runnable. No behaviour change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 21:00:14 +00:00
Khalim Conn-Kowlessar
559616d3bb feat(epc): EPC persistence round-trip fidelity + JSONB code columns (Slice 1 #1129)
Relocate EpcPropertyModel + child tables from the dying backend/ tree to
infrastructure/postgres/epc_property_table.py (re-export shim keeps
documents_parser working). Add EpcRepository port + EpcPostgresRepository with
a full reverse mapper (epc_property tables -> EpcPropertyData).

Round-trip test surfaced two fidelity gaps:
 1. Union[int,str] SAP code fields were str()-coerced on save, losing the int
    (API) vs str (Site Notes) distinction. Now stored as JSONB (type-preserving).
 2. The schema was a partial projection. Closed the cheap gaps on the model
    (heating shower/bath counts, roof_construction_type, curtain_wall_age,
    addendum, mechanical_vent_duct_insulation_level, SAP 10.2 §2 ventilation
    fields + a ventilation_present flag). Structural gaps tracked as follow-ups;
    renewable_heat_incentive (P0, #1137) excluded from the assertion until landed.

Round-trip passes for RdSAP-Schema-21.0.0 and 21.0.1; pyright strict clean.
Migration inventory for the DB: docs/migrations/epc-property-round-trip-fidelity.md

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 16:28:48 +00:00
Jun-te Kim
d5ac70947d booking status 2026-06-01 16:28:47 +00:00
Jun-te Kim
b72a0c2be4 hubspot projects data is scraped 2026-06-01 16:28:47 +00:00
Jun-te Kim
99614820b9 made landlord overrides sqs 2026-05-29 10:41:46 +00:00
Jun-te Kim
0a99c92eb4 added batch description and nonfunded measures 2026-05-27 10:30:19 +00:00
Khalim Conn-Kowlessar
87b6045c97 fixed merge conflicts from main 2026-05-26 11:21:09 +00:00
Khalim Conn-Kowlessar
883028c89e P6.1 follow-on: unbox BuildingPartIdentifier at backend boundaries
Threads the strict BuildingPartIdentifier type (introduced in a8b443f6)
through the two remaining backend touchpoints:

- EpcBuildingPartModel.from_*: SQLModel column expects a string, so
  unbox the enum with .identifier.value before binding to the DB.
- documents_parser end-to-end tests: swap bare-string equality
  ("main" / "extension_1") for identity checks against the enum
  members (BuildingPartIdentifier.MAIN / EXTENSION_1).

Documents_parser test pack passes (105/105). No dedicated SQLModel test
covers EpcBuildingPartModel.from_*; the .value line is exercised
transitively via db_writer.py / local_runner.py in production.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 09:58:23 +00:00
Daniel Roth
dc3543ac5f Coordination Hub fallback stores correct file_source in DB 🟥 2026-05-19 11:07:41 +00:00
Daniel Roth
4cd59768c3 Wire coordination account fallback into config and handler, remove token-refresh retry 🟩 2026-05-18 09:22:32 +00:00
Khalim Conn-Kowlessar
0ffda529ec slice 15a: add wall/floor/roof + demand scalar features for retrofit simulation
15 new features wired through schema -> domain -> mapper -> transform:

Main Dwelling fabric (11):
  - wall_insulation_type, wall_insulation_thickness_mm, wall_dry_lined,
    wall_thickness_mm, party_wall_construction
  - roof_insulation_location, roof_insulation_thickness_mm
  - floor_construction, floor_insulation, floor_insulation_thickness_mm,
    floor_heat_loss

Dwelling-level scalars (4):
  - multiple_glazed_proportion, number_baths, number_baths_wwhrs,
    extract_fans_count

Thickness strings like '50mm'/'NI'/'ND' parsed via _parse_thickness_mm; NI
(no insulation) lands as 0mm so the model sees the physical zero rather than
a missing value. Categorical sentinels ('NA'/'NI'/'ND') become None.

Also fixed long-standing typo `multiple_glazed_propertion` -> `_proportion`
in domain dataclass + its lone DB-model usage.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 22:08:27 +00:00
Daniel Roth
c98fc8452f
Merge pull request #1086 from Hestia-Homes/feature/pashub-additional-files
Fetch coordination and design documents from pashub
2026-05-14 11:59:43 +01:00
Daniel Roth
cc6b64ee2b
Merge pull request #1080 from Hestia-Homes/feature/magicplan_uploaded_file_id
Include uploaded file ID on MagicPlan plan
2026-05-14 10:23:33 +01:00
Daniel Roth
5ff740d192 Merge branch 'main' into feature/pashub-additional-files 2026-05-13 15:27:04 +00:00
Jun-te Kim
27b5602608 remove pandas 2026-05-13 15:08:06 +00:00
Jun-te Kim
51460d1cd3 route at th ebeginnign 2026-05-13 14:47:24 +00:00
Jun-te Kim
54864bf102 resolve merge conflict 2026-05-13 14:22:04 +00:00
Daniel Roth
e315966565 add coordination and design document types to enums 2026-05-13 12:29:25 +00:00
Daniel Roth
265be9849b Store uploaded_file_id on magic_plan_plan row 🟥 2026-05-13 10:50:28 +00:00
Jun-te Kim
3bcb94f9e5 Merge branch 'main' into feature/integrate_new_epc_with_historical_epc 2026-05-13 08:38:50 +00:00
Jun-te Kim
09dbfe2106 fix dependency issue 2026-05-12 17:03:16 +00:00
Jun-te Kim
e458f0a2b7 task and sub tasks imrpvoed 2026-05-12 16:24:11 +00:00
Jun-te Kim
35d191c70e merged from main and resolved pytest.ini confict 2026-05-12 12:54:28 +00:00
Jun-te Kim
6504785e7c merged from main 2026-05-11 12:30:29 +00:00
Daniel Roth
6fd95d20af Merge branch 'main' into feature/magicplan-trigger 2026-05-11 09:06:47 +00:00
Jun-te Kim
c53d8b2a33 basic end up check 2026-05-10 21:07:16 +00:00
Daniel Roth
7c9cb5b161 Upload gzip-compressed MagicPlan JSON to S3 🟥 2026-05-08 14:14:42 +00:00
Jun-te Kim
8b6a572223 Merge branch 'feature/claude_skills_in_devcontainer' into feature/etl_process_for_old_csv 2026-05-08 13:09:19 +00:00
Daniel Roth
489b0ba30e Add MagicPlan SQS trigger to HubSpot orchestrator 🟥 2026-05-08 13:05:38 +00:00
Daniel Roth
f56dba4ad1 use pytest-postgresql in db tests instead of mocking and checking sql strings 2026-05-08 10:13:44 +00:00
Jun-te Kim
4f45eeb3e9 save 2026-05-07 15:55:44 +00:00
Daniel Roth
6b29086a1e typing and renaming 🟪 2026-05-07 13:26:49 +00:00
Daniel Roth
2f8e08a676 save_plan persisting domain Plan to magic_plan_* tables 🟩 2026-05-07 13:09:09 +00:00
Daniel Roth
5ec0fa5d04 save_plan persisting domain Plan to magic_plan_* tables 🟥 2026-05-07 13:01:04 +00:00
Daniel Roth
7ff7e90307 SQLModel ORM layer for magic_plan_plan/floor/room/window/door tables 🟩 2026-05-07 12:56:12 +00:00
Daniel Roth
61b91bdb5e add magicplan environment variables to config 2026-05-07 12:39:45 +00:00
KhalimCK
b4ee59c82e
Merge pull request #1042 from Hestia-Homes/feature/khalim-additional-db-features
Feature/khalim additional db features
2026-05-01 10:54:28 +01:00
Khalim Conn-Kowlessar
9e3f5a2205 Adding use model for storage of users 2026-04-30 18:53:15 +00:00
Khalim Conn-Kowlessar
b056deb5ee added additional columns to db 2026-04-30 17:10:00 +01:00
Daniel Roth
1bc8343738 identify site notes files after file upload so we can save them to epc_property table 2026-04-28 16:33:53 +00:00
Khalim Conn-Kowlessar
a1b207ba55 bolstering testing 2026-04-28 13:46:09 +00:00
Daniel Roth
51bd18e0d7 Rename window frame material column 🟩 2026-04-27 16:11:32 +00:00
Daniel Roth
5940977bb2 tweak window transmission data source type 2026-04-27 14:11:33 +00:00