Commit graph

13 commits

Author SHA1 Message Date
Khalim Conn-Kowlessar
57867832f6 docs(adr): Bill Derivation (ADR-0014) + calculator goes load-bearing (ADR-0013 amend)
Pin the bills design from a /grill-with-docs session:
- ADR-0014: whole-home annual bill from SAP10 Calculation's delivered kWh per
  end use, re-priced at real Fuel Rates (NOT the calculator's SAP-notional
  total_fuel_cost_gbp, which is RdSAP Table 32 standardised prices ~half real
  electricity). Fuel enum + FuelRates + FuelRatesRepository static snapshot;
  per-section + total flat columns; raise on unpriced fuel (house coal /
  heat network are the named gaps).
- ADR-0013 amendment: the shadow stepping-stone is collapsed — the calculator
  is load-bearing now. effective=calculated for sap_version<10.2 (StubRebaseliner
  floor 10.0->10.2); >=10.2 keeps lodged + logs divergence; a strict-raise
  aborts the batch (load-bearing for bills regardless of version).
- CONTEXT: EPC Energy Derivation -> Bill Derivation (no "service" suffix);
  Baseline Performance energy block = per-end-use kWh + per-section bill + total;
  Fuel Rates = committed static snapshot; Rebaselining trigger threshold 10.2.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 09:20:50 +00:00
Khalim Conn-Kowlessar
561e1b8b49 feat(baseline): run Sap10Calculator in shadow on Property Baseline (ADR-0013)
Wire Sap10Calculator into PropertyBaselineOrchestrator as a non-load-bearing
shadow runner. For each property it scores the Effective EPC beside the
load-bearing Lodged/Effective write, catches any strict-raise -> log.error
(never aborts the batch), and on success log.warning's divergence from Lodged:
SAP |continuous - lodged| > 0.5; PEUI/CO2 > 1% relative (CO2 after kg->tonnes).
Every line is tagged with sap_version so SAP-10.2 signal separates from
older-spec drift (ADR-0010 Validation Cohort).

Per ADR-0013, Calculated SAP10 Performance is not a persisted third value-set:
effective = calculated in every baselining scenario, so the calculator IS the
mechanism that produces Effective Performance (the Rebaseliner). It runs in
shadow only while being hardened; when overrides/estimation land it is promoted
to drive Effective and the failure posture flips to abort (ADR-0012, calculator
now load-bearing). No table change.

- ADR-0013 + CONTEXT (Calculated SAP10 Performance / Effective Performance /
  Rebaselining) record the decision.
- CalculatorShadow port + LoggingCalculatorShadow + Calculator protocol.
- FakeCalculatorShadow for orchestrator unit tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 08:01:47 +00:00
Khalim Conn-Kowlessar
ce33cd94ef docs: correct SAP calculator path in CONTEXT (domain/sap → domain/sap10_calculator)
Factual staleness fix flagged in the handover; the calculator lives in
domain/sap10_calculator/calculator.py. Glossary term 'Baseline Performance'
deliberately left unchanged (concept vs PropertyBaselinePerformance class).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-01 18:56:41 +00:00
Khalim Conn-Kowlessar
76717dfc3a feat(baseline): BaselineOrchestrator + BaselinePerformance aggregate (#1135)
Stage 2 of First Run. Establishes each Property's Baseline Performance
from persisted source data and writes it back — reads only from repos,
never a Fetcher or HTTP (ADR-0003), so it is byte-identical whether
Ingestion ran milliseconds ago or last week.

Domain (`domain/baseline/`):
- `Performance` VO — the four rated quantities: SAP / EPC Band / CO2 /
  Primary Energy Intensity. `lodged_performance(epc)` reads them off the
  EPC's recorded fields (PEUI = `energy_consumption_current`).
- `BaselinePerformance` (ADR-0004) — the paired `lodged` + `effective`
  Performance + `rebaseline_reason`, plus the no-derivation part of the
  energy block (`space_heating_kwh` / `water_heating_kwh`, off the RHI,
  deterministic per ADR-0006). Both halves always populated.
- `Rebaseliner` port + `StubRebaseliner`: the re-score-on-override seam
  (ADR-0011). SAP10 certs pass through (effective == lodged, reason
  "none"); a pre-SAP10 cert raises `RebaselineNotImplemented` rather
  than fabricating a plausible-but-wrong "none" — ML rebaselining is not
  wired yet. Mirrors the repo's strict-raise culture.

Persistence: new `BaselineRepository` port + `BaselinePostgresRepository`
+ flat-column `baseline_performance` SQLModel (one row per Property). Per
ADR-0004's amendment this is a standalone table, NOT columns on the
retiring `property_details_epc`. Production migration is FE-owned
(Drizzle) — docs/migrations/baseline-performance-table.md.

Docs (grill-with-docs): corrected CONTEXT.md Lodged/Effective Performance
to Primary Energy Intensity (the term collided with its own _Avoid_ entry
under "heat demand") + fixed stale RHI field names; amended ADR-0004
Consequences for the standalone-table decision.

Fuel split + bills (rest of EPC Energy Derivation) deferred to a
follow-up — they need a Fuel Rates source (Ofgem-cap ETL) that does not
exist yet.

TDD, one test -> one impl: 7 tests (lodged read, rebaseliner pass-through
+ raise, orchestrator establish-and-persist + pre-SAP10 raise, Postgres
round-trip + absent). pyright strict clean; AAA layout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 21:21:34 +00:00
Khalim Conn-Kowlessar
5aebd90ef7 docs(ara): composable stage-orchestrator design (ADR-0011 + ADR-0003 amend + CONTEXT)
Records the grill-with-docs outcomes for the ara_first_run rebuild: three
composable stage orchestrators (Ingestion/Baseline/Modelling), one lambda per
use case chaining them through repos (not in-memory), and the Fetcher-vs-Repo
data-source taxonomy. Amends ADR-0003's chaining rule to generalise beyond
RefreshOrchestrator. Adds the pipeline-composition + First Run vocabulary to
CONTEXT.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 19:26:17 +00:00
Khalim Conn-Kowlessar
68401c517a refactor: lift-and-shift packages/domain/src/domain/ml → domain/sap10_ml
Sibling migration to the sap10_calculator move — `domain.ml` now lives
at the root-level layout (`domain/sap10_ml/`) matching the pattern
already used by `domain.addresses`, `domain.tasks`, `domain.postcode`,
and `domain.sap10_calculator`.

Changes:

- `git mv packages/domain/src/domain/ml → domain/sap10_ml` (19 files;
  history preserved).
- Subpackage rename: `domain.ml` → `domain.sap10_ml`. 32 references
  rewritten across .py and .md files: 11 internal + 21 external
  (datatypes/epc/domain/mapper.py, 14 files in domain/sap10_calculator,
  2 backend tests, 2 ADRs, 1 README, 1 design doc).
- Path-string updates: `pytest.ini` testpath
  `packages/domain/src/domain/ml/tests` → `domain/sap10_ml/tests` so
  ML tests stay in the default auto-discovered sweep. `CONTEXT.md`
  also updated.

`packages/domain/src/domain/` is now empty — the workspace `domain/`
tree has been fully migrated. Together with the `domain/__init__.py`
deletions from the sap10_calculator commit (29ac35cc), `domain` is
now a single root-level namespace package with subpackages
{addresses, sap10_calculator, sap10_ml, tasks} + the standalone
`postcode.py` module.

Verified:

- Focused sweep (backend mapper-chain + sap10_calculator worksheet
  e2e + golden fixtures): 99 passed / 19 failed — identical baseline.
- Wider sweep (all sap10_calculator + sap10_ml): 1654 passed / 20
  failed (same pre-existing failures).
- domain/sap10_ml/tests: 210/210 PASSED at new path.
- Pyright net-zero: heat_transmission.py 13, cert_to_inputs.py 35,
  mapper.py 33, rdsap_uvalues.py 1 (all unchanged from baseline).

Note: `packages/domain/pyproject.toml` still declares
`packages = ["src/domain"]` for the hatchling wheel — that target
directory is now empty and the wheel build is effectively a no-op.
Retiring the workspace package or repointing the wheel is a follow-up.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 13:01:35 +00:00
Khalim Conn-Kowlessar
87b6045c97 fixed merge conflicts from main 2026-05-26 11:21:09 +00:00
Khalim Conn-Kowlessar
bb9c5ac017 docs: ADR-0010 retargets calculator to SAP 10.2; rewrite handover
Adds ADR-0010 superseding ADR-0009's spec-version target, PCDB
sequencing, and cert-calibration layer. Captures the conclusions
of a grill-with-docs session:

  1. Active spec target is SAP 10.2 (14-03-2025), not SAP 10.3 — no
     SAP-10.3-lodged certs exist in the corpus to validate against.
  2. table_12_cert_calibration is deleted (not "re-derived at the
     end"). It was pre-March-2025 spec prices fit against a mixture
     distribution of two spec-version regimes, with downstream-
     component bugs absorbed into the fit — not Elmhurst deviation.
  3. Validation Cohort: filter the corpus to inspection_date ≥
     2025-07-01 so every cert in the probe was lodged on SAP 10.2
     (14-03-2025) prices. One spec, one signal.
  4. PCDB integration is promoted from "Session C deferred" to
     prerequisite P4 — dominates residual variance on heat pumps and
     the 78% of gas-boiler certs lodging main_heating_data_source=1.
  5. Trace mode (SapResult.intermediate) and BRE worked-example
     fixtures replace the 7 cert-based golden fixtures, which
     contained compensating errors.
  6. Strict-type EpcPropertyData via codes.csv-derived canonical
     enums (P6) — the in-source motivation lives at
     dimensions.py:74-82 (Khalim's comment, included in this commit).
  7. Worksheet-faithful structure is a sweep-time principle: each
     worksheet module mirrors SAP 10.2 worksheet line numbering.

CONTEXT.md additions:
  - Refined "Calculated SAP10 Performance" and "SAP10 Calculation"
    to reference SAP 10.2 + ADR-0010.
  - New term "SAP Spec Version" — domain-meaningful because the
    same EpcPropertyData yields different sap_score under different
    spec revisions.
  - New term "Validation Cohort" — the version-locked sub-corpus.

HANDOVER_SYSTEMATIC_REVIEW.md is rewritten section-by-section to
reflect ADR-0010: §1 framing, §2 status pointer, new §2.5 with the
six prerequisites P1–P6 in dependency order, §3 diagnosis (cert-cal
was stale prices, not Elmhurst deviation), §4 scope (PCDB IN,
SAP 10.3 stays OUT), §5 approach (worksheet-faithful principle as
§5.5), §7 tension dissolved, §7b findings re-framed, §8 dead-ends
re-classified as conditional, §9 cohort filter, §10 fixture
strategy, §11 trace mode as prerequisite, §12 prereqs-first,
§13 Phase 0/Phase 1 workflow, §14 ADR-0010 reference, §15 final
note.

P2.1 (commit ac1aa56a) already lands the first ADR-0010 slice
(probe swap to spec prices).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 09:54:24 +00:00
Khalim Conn-Kowlessar
8dbe873daf ADR-0009: pivot to deterministic SAP 10.3 calculator (Accepted)
Promotes ADR-0009 from Proposed to Accepted after the grill-with-docs
session resolved all seven open questions. Bundles the SAP 10.3 and
RdSAP 10 specifications under docs/sap-spec/ plus a calculator design
sketch (module layout, monthly-loop pseudo-code, status table).

CONTEXT.md adds three new domain terms parallel to existing performance
language:
  - Calculated SAP10 Performance (parallel to Effective / Lodged)
  - SAP10 Calculation (process; implemented by Sap10Calculator)
  - Measure Application (process; implemented by MeasureApplicator)

ML pipeline is NOT retired — it stays as the residual head once the
calculator reaches parity in Session B. ADR-0009 §"Grill outcomes" carries
the seven binding scope decisions plus three Session-A-scope changes
discovered during the grill (RdSAP §19 EER formula, SAP 10.2 Appendix A
cross-reference, RdSAP Table 29 cascade defaults).
2026-05-17 21:27:21 +00:00
Khalim Conn-Kowlessar
611ff24eb6 scaffolding for ml pipeline 2026-05-16 14:15:56 +00:00
Khalim Conn-Kowlessar
acb2518235 second grill session updating prd + context 2026-05-15 10:41:47 +00:00
Khalim Conn-Kowlessar
02df38e207 note kwh service not needing predictions 2026-05-13 21:52:02 +00:00
Khalim Conn-Kowlessar
d9c1696085 added architechtural decisions, added to prd 2026-05-13 21:26:18 +00:00