Commit graph

238 commits

Author SHA1 Message Date
Khalim Conn-Kowlessar
3c9b75cbce Hand-pick selection by landlord_property_id, not property.id
uploaded_files has no property_id — matching is on landlord_property_id — so the
property_ids path was pointless indirection (look property.id up in property just
to translate back to landlord_property_id). The FE holds landlord_property_id per
row anyway.

task.inputs hand-pick key is now landlord_property_ids: str[] (was property_ids:
int[]). resolve_selection unions two landlord_property_id sources — project_codes
expanded via hubspot_deal_data, and the hand-picked ids taken as given — and no
longer queries the property table at all. Trigger-only change; the domain plan,
orchestrator and matching already work in landlord_property_id.

ADR-0060, CONTEXT.md and the request schema updated to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 12:04:35 +00:00
Khalim Conn-Kowlessar
90fe2914e0 Select documents by HubSpot project_code(s), unioned with hand-picked property_ids
The 'all properties' selection resolved against property.portfolio_id, but a
portfolio spans multiple HubSpot projects — so 'all' pulled the whole portfolio,
not the project the user was looking at. The project↔property grain lives on
hubspot_deal_data, not property.

task.inputs is now {project_codes?: str[], property_ids?: int[], portfolio_id?}:
the route resolves the distinct landlord_property_id set as the union of every
property in the named project_codes (from hubspot_deal_data) and the hand-picked
property_ids; portfolio_id is optional and only names the package. Drops the
portfolio-scoped select_all. Cap now applies to the resolved set size.

ADR-0060, CONTEXT.md and the request schema updated to match. New router tests
cover project-code resolution, the union+dedup, null landlord_property_id drop,
and the empty-project rejection.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 11:42:17 +00:00
Khalim Conn-Kowlessar
0b52a28808 Read the property selection from task.inputs; route takes only task_id 🟩
Per PR review: the FE writes the selection config
({portfolio_id, property_ids?, select_all?}) into the FE-owned task.inputs and
passes only task_id, so a large hand-picked selection never travels in an HTTP
body. The route reads task.inputs, resolves to landlord_property_ids, caps, and
pins the recipe onto sub_task.inputs as before. Declares the FE-owned inputs
column on the TaskRow mirror so the backend can read it and the test schema
builds it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 10:41:14 +00:00
Khalim Conn-Kowlessar
6db6bbd98f ADR-0060: dedicated exports bucket + multi-GB streaming (drop DATA_BUCKET lifecycle) 🟪
Per review: packages go to a separate DOCUMENT_EXPORTS_BUCKET (not DATA_BUCKET),
no 7-day lifecycle imposed on the shared data bucket; packages can be several GB
so they stream via /tmp + multipart upload with raised ephemeral storage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 09:52:43 +00:00
Khalim Conn-Kowlessar
6d001d650e ADR-0059/0060: Bulk Document Download design — SES-SMTP email sender + capped best-effort Download Package 🟪
Grilled 2026-07-08. Locks: app-owned-task + attach-mode lane (ADR-0055);
FastAPI route resolves the requesting user (dbId -> UserModel.email) and pins
it + the resolved property_id set into tasks.inputs; one capped Download
Package = one sub_task; landlord_property_id matching (property_id a future
gap); address-named folders (hubspot-enriched), latest per Document Type,
null-type skipped+reported; best-effort (fail only on infra / wholly-empty);
URL to sub_task.outputs + email; DATA_BUCKET/bulk-downloads/ ~7-day lifecycle.
Backend-sent email via a repositories/email port + infrastructure/email SES-SMTP
adapter. Glossary: Bulk Document Download, Download Package, Document Type.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 08:54:43 +00:00
Jun-te Kim
269aade481 test(address2uprn): cover ambiguity withholding + override dedup; add ADR-0057
- unit tests for resolve_group_ambiguity (distinct addresses withheld,
  same-address re-listing kept, order preserved)
- Postgres integration tests for upsert_all's backstop dedup
- ADR-0057 recording the "confirm UPRNs before finalise" decision

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 15:21:04 +00:00
KhalimCK
9ff4de0563
Merge pull request #1481 from Hestia-Homes/feature/modelling-trigger-run
Modelling Run Distributor: POST /v1/modelling/trigger-run
2026-07-07 14:36:45 +01:00
Khalim Conn-Kowlessar
07190fc332 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>
2026-07-07 12:52:11 +00:00
Khalim Conn-Kowlessar
71a86f87fc ADR-0055 + ADR-0056: Modelling Run distributor decisions and glossary
The distributor pre-creates batch sub_tasks under the app-owned task and
sub_task status is a record, not retry fuel; filter resolution is a shared
contract with the app's preview. Scenario immutability replaces the
Scenario Snapshot fiction; Modelling Run, Distributor and First Run terms
pinned in CONTEXT.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 11:03:28 +00:00
Jun-te Kim
bc1cca77db
Merge pull request #1356 from Hestia-Homes/feature/historic-epc-repository
Historic EPC repository: DDD port + resolver for address→UPRN
2026-07-07 10:56:33 +01:00
Khalim Conn-Kowlessar
006c1317ac ADR-0054 amendment: band widths set by the 439-pair harness evidence
Age band equality -> ±1-band neighbourhood; TFA ±5% -> ±20%; whitelist
core validated (fuel 95% / type 91% / wall 79% stable); roof-insulation
collateral flagged for follow-up. CONTEXT.md term updated to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:09:15 +00:00
KhalimCK
180863ed41
Merge pull request #1456 from Hestia-Homes/fix/electric-boiler-cpsu-companions
Electric boiler/CPSU overrides drag category 2 and the conservative Group 1 control (#1444 A+B for 191/192)
2026-07-06 12:07:25 +01:00
Khalim Conn-Kowlessar
2788849e16 ADR-0054 + glossary: expired historic EPC conditions prediction with stable attributes
Settled in a grilling session with Khalim: the pre-2012 backup feeds EPC
Prediction landlord-override-style (stable attrs as relax-ladder filters,
TFA as a ±5% band, exact-UPRN lookup, source="expired"), never trusted as
current state; scoped to the historic source; validated by a pairs harness.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 08:15:43 +00:00
Khalim Conn-Kowlessar
1bcb55784a Amend ADR-0053: community default 2313 with keep-observed Group 3 controls 🟪
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 16:37:20 +00:00
Khalim Conn-Kowlessar
2a0cf05fdd Amend ADR-0051: the floor U-value gate landed; roof stays evidence-gated 🟪
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 16:08:57 +00:00
Khalim Conn-Kowlessar
77110f2260 Record ADR-0053: companion taxonomy complete, incomplete set raises 🟪
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 14:23:44 +00:00
Khalim Conn-Kowlessar
0f091e3ab1 Record ADR-0052: electric boiler/CPSU overrides drag category 2 + conservative Group 1 control 🟪
#1444 Parts A+B for codes 191/192, diagnosed on portfolio 796: 30 of the
first 40 live overrides inherit a replaced system's category (6/4/7) —
suppressing HHRSH or billing direct-acting heat as storage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 14:06:05 +00:00
Jun-te Kim
23ebd5e637
Merge pull request #1446 from Hestia-Homes/fix/ashp-size-to-dwelling-heat-loss
Size the ASHP to the dwelling's design heat loss (fix undersized fixed pump scoring below baseline)
2026-07-03 13:32:30 +01:00
Khalim Conn-Kowlessar
e110dd0746 Record ADR-0050 (underfloor override companions) and ADR-0051 (wall U-value gate) 🟪
WS2 of PRD #1435, diagnosed on property 711795: an electric-underfloor
override inherits the replaced community-heating category (no pathway,
baseline mis-rated 51 vs 67), and wall generators offer £4k insulation
that cannot change an age-band-L wall's derived U (0.280 → 0.280).
Glossary: Wall U-Value Gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 11:35:05 +00:00
Khalim Conn-Kowlessar
ac2b600bbd Merge remote-tracking branch 'origin/main' into fix/ashp-size-to-dwelling-heat-loss 2026-07-03 11:02:42 +00:00
Khalim Conn-Kowlessar
30616dc427 Record ADR-0049: ASHP sized to the dwelling's design heat loss at the efficiency peak
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 11:02:13 +00:00
Khalim Conn-Kowlessar
244c5b65ed Document heating-companion coherence: category/control forced, fuel/meter deferred (ADR-0048)
ADR-0048 records why a system-replacing heating override must emit a
complete companion set — category and control archetype-forced for
coherence, fuel and meter deferred where multiple values are valid, and
an unmapped companion logged rather than silently inherited. Adds the
Heating Companion Set glossary term to CONTEXT.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 09:21:47 +00:00
Khalim Conn-Kowlessar
6d812d99c5 An unlodged roof type with ND thickness gets no roof recommendation 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 11:20:55 +00:00
Khalim Conn-Kowlessar
9e1a194b27 Record ADR-0047 roof sentinel eligibility + lodgement-sentinel glossary entry
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 10:55:57 +00:00
Khalim Conn-Kowlessar
ef34f76116 Resolve electric-underfloor overrides to their own SAP codes dragging electricity 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 16:34:41 +00:00
Khalim Conn-Kowlessar
e5c112a2d3 Document the fuel-aware electric-CPSU resolution in ADR-0045 🟪
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 16:17:22 +00:00
Khalim Conn-Kowlessar
f253a7b9ba Resolve solid-fuel room-heater overrides off Gas CPSU to their SAP codes 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 15:58:25 +00:00
Daniel Roth
0488696df8
Merge pull request #1397 from Hestia-Homes/fix/1376-hhrsh-baseline-archetype
Add the HHRSH baseline archetype so it stops scoring as old storage (#1376)
2026-07-01 15:41:52 +01:00
Khalim Conn-Kowlessar
79f48c0564 Resolve a high-heat-retention storage override to SAP code 409 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 14:26:25 +00:00
Khalim Conn-Kowlessar
c24e465974 Resolve a from-main wood-logs water-heating override to the wood fuel 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 12:59:56 +00:00
Khalim Conn-Kowlessar
19c1a78613 Record the glazing reconcile collapsing to a MIXED sentinel (ADR-0042 amendment)
Per-window assignment from a landlord aggregate is strictly worse than the cert's
existing per-window sap_windows, so a mixed override always defers — the proportion
comparison only fed a 'flag when far' branch not worth a new schema field. Realized
decision: a GlazingType.MIXED sentinel (LLM classifies mixes to it) resolves to no
overlay, preserving the cert glazing; uniform assertions still apply.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 11:00:58 +00:00
Khalim Conn-Kowlessar
cba536eba8 Record flat-roof-thickness and glazing-reconcile decisions (ADR 0041/0042)
ADR-0041: flat roofs ARE scored by insulation thickness via RdSAP Table 16
col (1) ('joists at ceiling level and flat roof'); the RoofType taxonomy lacks
flat-thickness members so the depth is discarded — fix needs new FLAT_*MM members
(FE-owned pgEnum). ADR-0042: a landlord glazing override reconciles against the
cert's per-window sap_windows composition rather than flattening every window to
one type; mixed-and-close defers to the cert, mixed-and-far is flagged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 09:22:13 +00:00
Daniel Roth
0c701ba3de
Merge pull request #1373 from Hestia-Homes/fix/1361-class-b-predicted-null-lodged
Drop the phantom Lodged Performance on predicted Properties (#1361 Class B)
2026-07-01 08:35:58 +01:00
Khalim Conn-Kowlessar
09b3bc98ba Document the nullable lodged_* migration for the FE/Drizzle owner
Specifies the ALTER ... DROP NOT NULL on the four lodged_* columns (#1361) and
the ordering constraint: it must land before the backend writes NULL or runs the
backfill, else the predicted-Property INSERT aborts the batch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 22:19:54 +00:00
Khalim Conn-Kowlessar
7ecb7eebd1 Record that a predicted Property has no Lodged Performance
Amends ADR-0004's both-halves-always-populated invariant: EPC Prediction
borrows a neighbour's recorded figures, so a predicted Property has no Lodged
Performance — its lodged half is absent (NULL), only the Effective half is
persisted. Sharpens the CONTEXT.md glossary for Lodged / Baseline Performance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 22:07:27 +00:00
Khalim Conn-Kowlessar
56aaace5b1 Default a solid-fuel room heater's natural fuel to house coal 🟩
Solid fuel is ambiguous across coal/wood/smokeless/pellets, so the overlay
defaults to house coal (33, the most common) when no main_fuel override is
given; a specific solid-fuel override still wins by last-wins composition.
Updates the ADR-0041 natural-fuel amendment accordingly (every archetype drags
a natural fuel; solid defaults to coal).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:55:57 +00:00
Khalim Conn-Kowlessar
d5927c68a9 docs: ADR-0041 amendment — natural-fuel coherence
Record the natural-fuel drag-along rule the overlay now implements: drag a fuel
only where the archetype is unambiguous (electric/gas), leave ambiguous
solid/oil room heaters to the main_fuel override, let a present main_fuel
override win by last-wins composition, and LOG (not raise) a landlord fuel that
contradicts the archetype's natural fuel.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:46:56 +00:00
Khalim Conn-Kowlessar
72e1e67c6d docs: ADR-0041 — landlord-heating classification targets a complete taxonomy
grill-with-docs output for PRD #1361 Class A. The band-G baselines are not a
fabric/rebaseline bug (walls are correct — landlord asserted as-built); they are
a target-vocabulary gap in the landlord-description heating classifier. The LLM
maps unbounded free-text onto a closed internal taxonomy, but that taxonomy had
9 archetypes vs ~13 RdSAP families, so it overflowed into "Gas CPSU"/storage
(the "convector" collision sent direct-acting room heaters to off-peak storage
403 → SAP ~10).

- ADR-0041: fix the taxonomy not the mapper; unmapped input -> None (keep lodged
  EPC, surface to user), never a forced archetype; heat pumps modellable via a
  default Table 4a code (no PCDB id); community heating via codes 301/302/304
  with a documented DLF-1.50 / boiler-source default.
- CONTEXT.md: sharpen Landlord-Description Classification and the four distinct
  vocabularies (landlord / recognised-internal / lodged / SAP code).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 14:33:54 +00:00
Khalim Conn-Kowlessar
79b86a38c1 docs: ADR-0039 (override-aware rebaseline) + ADR-0040 (nested persistence) 🟪
Record the two load-bearing decisions and correct the CONTEXT.md
'Calculated SAP10 Performance' entry: the lodged figure is kept at >=10.2
only for a pristine lodged cert; overrides/prediction adopt the calculator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 19:25:54 +00:00
Khalim Conn-Kowlessar
1d236e3490 docs: mark the 7 calculator-read round-trip gaps closed 🟪
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 18:48:28 +00:00
Khalim Conn-Kowlessar
21b25b8b35 docs: record PV-array + floor-flag round-trip closures 🟪
Document Slice 2 in the persistence-fidelity migration log, plus the 7
calculator-read nested gaps the recursive guard newly surfaced (tracked
follow-up).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 16:53:42 +00:00
KhalimCK
6303343575
Merge pull request #1341 from Hestia-Homes/fix/coherent-gas-boiler-overlay
fix(overlay): coherent gas-boiler heating system on Landlord Override
2026-06-26 14:18:56 +01:00
Jun-te Kim
a680d65188 fix(overlay): synthesise a coherent gas-boiler heating system on Landlord Override
A Landlord heating-system override was applied as a sparse patch, so the
replaced system's fields bled through. A storage flat reclassified as a gas
combi (property 728513) kept mains_gas=False, heating category 7, the 2401
storage charge control, a Dual meter and an electric-immersion cylinder — an
incoherent record that gated out the gas-boiler-upgrade Measure and made the
heating Generator read the dwelling as off-gas (offering HHRSH storage).

Extend the ADR-0035 drag-along to gas boilers (Table 4b 102/104/120): the
overlay now sets the whole coherent companion set — mains_gas, gas main fuel,
heating category 2, fanned flue, full modern controls (2106), a single-rate
meter, and hot water from the main system with the cylinder set from the boiler
type (combi → none, regular/CPSU → cylinder). The main_fuel overlay also flips
mains_gas=True for a "mains gas" fuel. Non-off-peak archetypes now drag an
explicit Single meter so a system switch never leaves a stale Dual.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 12:48:33 +00:00
Jun-te Kim
706e0072d0
Merge pull request #1337 from Hestia-Homes/fix/predicted-property-display-unknowns
fix(epc-prediction): populate Heating-Control + Ventilation display for predicted properties
2026-06-26 13:45:22 +01:00
Khalim Conn-Kowlessar
58f6b868a7 docs: ADR-0038 + glossary — bound Solar PV array to the dwelling's own roof
ADR-0026 sized PV at 0.70 x Google maxArrayPanelsCount, assuming Google's roof
is the dwelling's. Medium-imagery footprint conflation (semi-detached/terraced)
returns the whole building's roof -> oversized arrays (property 742003: 55m2
bungalow -> ~16 kWp -> effective E/49.7 -> A/92.4 on solar alone). ADR-0038
bounds the array to the dwelling's own usable roof (roof_area-based budget,
proximity segment selection anchored on the dwelling), subsuming the legacy
GoogleSolarApi guards the rewrite dropped. CONTEXT: add Footprint Conflation +
Dwelling-Roof Cap, extend Solar Potential (per-segment centre + area).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 12:08:11 +00:00
Khalim Conn-Kowlessar
5fc8bd3b3d docs: record predicted-property display fixes (item 4) 🟪
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 10:54:53 +00:00
Khalim Conn-Kowlessar
cc1c763946 docs: mark 19.0/21.0.0 ventilation fixed (feat/rdsap-19-21-ventilation) 🟪
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 10:00:48 +00:00
Khalim Conn-Kowlessar
b2c74dbf5b docs: ventilation mapping inconsistency — 17.1/18.0/20.0.0 fixed, 19.0/21.0.0 open
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 08:46:01 +00:00
Khalim Conn-Kowlessar
3f69c4be02 docs: full-SAP baseline-downgrade follow-ups + Case A population sweep tool
Captures the calc-facing ventilation-type gap (older RdSAP mappers drop
mechanical_ventilation_kind), the FE-side Main Fuel display, the sweep survivor
clusters, and the predicted-property display path — all separate from ADR-0037.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 21:45:44 +00:00
Khalim Conn-Kowlessar
2d18e9a3b0 docs: ADR-0037 + Full-SAP Assessment term for the baseline-downgrade family
Captures the grill-with-docs decisions for the full-SAP-17.1 mapper completion:
rebaseline-to-10.2 (restores Rebaselining trigger (a)), calc-affecting fields
coupled with the sap_version flip, and growing Elmhurst-anchored validation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:24:34 +00:00