10 modelling_e2e properties failed with "unmapped SAP code in fuel_code: 10":
the billing layer (`sap_code_to_fuel`) had no carrier for Table-32 code 10
(dual fuel, mineral + wood) and raised rather than guess one.
SAP 10.2 treats dual fuel as its OWN fuel (its own Table-12 factors), so model
it as its own billing carrier rather than collapsing onto wood or coal:
- New `Fuel.DUAL_FUEL_MINERAL_AND_WOOD`.
- `_CODE_TO_FUEL[10]` -> that carrier.
- Fuel Rates snapshot prices it at 7.69 p/kWh — the midpoint of the COAL proxy
(7.13) and WOOD_LOGS (8.25). This mirrors SAP's own construction: Table-32
dual fuel (3.99) ~= midpoint of house coal (3.67) and wood logs (4.23).
Marked `derived` with a documented _note/_gap/_assumption (like the COAL and
HEAT_NETWORK proxies), since there is no retail blend price.
A dedicated carrier + rate (vs a one-line map to an existing carrier) keeps the
fuel identity faithful to SAP and avoids mispricing dual fuel as pure wood/coal.
Tests: code 10 -> DUAL_FUEL carrier; snapshot prices it at 7.69; grid-export
codes (36/60) still raise (the genuine no-carrier case).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bill / EnergyBreakdown / BillDerivation / sap_fuel were under
domain/property_baseline/ only because Baseline was built first. The Modelling
stage now needs them too, so move them (and their tests) to a neutral
domain/billing/ — Fuel/FuelRates already live in the shared domain/fuel_rates/.
Avoids a modelling -> property_baseline cross-stage import and a package name
that wrongly implies ownership (ADR-0011, ADR-0014 amendment). Pure git mv +
import rewrite across 10 files; 40 billing/baseline/repo tests pass, pyright
strict clean. CONTEXT.md Bill Derivation location updated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>