From b089bde1e65d659e368020045af398b3b74d7f10 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Sat, 6 Jun 2026 21:33:09 +0000 Subject: [PATCH] docs(modelling): add Products term to CONTEXT (ADR-0025) The rich catalogue collection over Product carrying cost-composition behaviour; records the catalogue-math vs dwelling-interpretation split. Co-Authored-By: Claude Opus 4.8 --- CONTEXT.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CONTEXT.md b/CONTEXT.md index 57a8d08a..7c325f66 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -215,6 +215,10 @@ _Avoid_: simulation config (the legacy EPC-API flag object), patch, delta, diff A catalogue entry a **Measure Option** installs — insulation, glazing units, heat pumps, boilers, cylinders, PV panels, inverters, batteries — carrying the data to price an Option and shape its **Simulation Overlay**. Named *Product*, not *material*: the catalogue is dominated by equipment and appliances, and a heat pump is not a building material. Read via `ProductRepository`, which for now combines two inputs — the Products in the database plus a committed costs file holding what the ETL does not yet supply. Single-source unification (ETL-supplied costs) is separate, queued work; legacy `Costs.py` is retained but queued for deletion. _Avoid_: material, building material (inaccurate for appliances), part (the per-Option installed line item), SKU +**Products** (the catalogue collection): +The rich in-memory domain collection over **Product** — an iterable the **ProductRepository** yields, carrying the cost-composition behaviour a single `Product` row cannot. Where a simple measure prices as one row (unit cost × area), a composite measure (an **ASHP bundle**) prices by *selecting and summing many priced line items* — so `Products` exposes per-measure cost methods (e.g. `ashp_bundle_cost`) that filter the relevant catalogue rows and sum them into a **Cost**. The split is load-bearing: `Products` owns the **catalogue math** (line-item lookup + summation from clean cost-inputs) and stays free of `EpcPropertyData` / the `Sap10Calculator`; the **dwelling interpretation** that produces those inputs (sizing a heat pump from heat loss, proxying beds/radiators, detecting a reusable wet system) lives in the modelling layer, which may depend on the calculator. ProductRepository = fetch; Products = behaviour. +_Avoid_: ProductRepository (that is the IO port, not the domain collection), putting sizing/EPC logic on Products + **Cost** (of a Measure Option): A single **fully-loaded total** — products + labour + preliminaries + VAT + margin rolled into one figure — **plus a separately-carried Contingency**. Only contingency is broken out; the rest is not decomposed, as that breakdown proved unhelpful.