Skip to content

Bind local-authority energy and regional bus journeys before the Budget (#1207) - #1286

Merged
juaristi22 merged 21 commits into
mainfrom
uk-local-energy-bus-1207
Oct 15, 2026
Merged

juaristi22 merged 21 commits into
mainfrom
uk-local-energy-bus-1207

Conversation

@juaristi22

@juaristi22 juaristi22 commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator

Delivers the ready items of #1207 under María's rulings of 2026-10-14 and 2026-10-15, in one PR as she ruled: DESNZ sub-national domestic energy as local-authority targets, DfT BUS01a journeys by English region, and the other #1207 items that can land before the Budget build. It does not close #1207; what still waits is listed at the end.

Based on main at 8a7f79a82 (after #1283; policyengine-uk 2.130.1). The 735820c feed artifact is in: the new resource is vendored from it, and the references are regenerated on it against main.

What changes

Energy stage text (C1). The energy_pricing header, the energy_rake gate docstring, the region crosswalk's policy text and the stage note now describe the calendar-2024 level, the connect leg and the household kWh ceilings (#1113, #1164). Text only; the coverage manifest and the H2 spine fixture move with the stage note (regenerated in the last commit).

Northern Ireland bus fares from their own yields (C2). Northern Ireland publishes no bus fares index, so its 2024-25 yield was re-priced to calendar 2024 with England's local bus fares index, which carries the January 2025 English fare-cap rise. A new price_index basis, own_fiscal_yields, weights NI's own published yields of the fiscal years opening in 2023 and 2024 three months and nine over the later yield. The factor moves from 0.982 to 0.989. This is the PR's only change to a spine column: between the two spines, only NI's bus fare columns and the receipts should differ.

Report-only receipts (C3, C4).

  • division_capture gains, per COICOP division, the donor's weighted total and the frame's over it, so the furnishings and health over-draw can be read on any build against the 2024-25 donor. The recompose receipt records the donor's other fuels beside ONS 04.5.3 and 04.5.4.
  • The measure resolver's receipt gains bus_engine_parity: the locked engine's gov.dft.bus.boardings_per_trip and yield_per_boarding beside the stage's, area by area, against a 0.1% tolerance. An engine without the parameters records why.
  • consumption_drift gains the full-rate VAT base at design and final weights.

Crosswalk vintage (C5). DESNZ stamps every authority with publication_2025_nspl; the England, Wales and Scotland accept-sets gain it. Barnsley and Sheffield resolve through the existing lad_2025 aliases.

Local energy appliers (C6). uk_runtime/domestic_energy_targets.py:

Local energy family (C7). Three local-authority rows for England, Wales and Scotland: desnz.subnational.electricity_kwh, desnz.subnational.gas_kwh and desnz.subnational.gas_connected_households (census family domestic_energy, two DESNZ sources, four fences).

  • Metrics energy/electricity_kwh, energy/gas_kwh and energy/gas_connected_households, appended after the high-value homes metrics, local authorities only. They read the stored spend at the dataset period: policyengine-uk uprates electricity and gas spend by CPI away from the period they were supplied for (an engine test pins this).
  • The kWh rows declare local_routes: no_higher_control (DESNZ's region rows are the authorities' sums, and a gas bridge would put the three authorities without gas rows in controlled legs).
  • The gas-connected rows join the census household partition (census_gas_connected_share) and take the census-household uprating, so their share does not drift.
  • Orkney and Shetland have no mains gas: their gas cells are signed deferrals, never zeros. The Isles of Scilly and the City of London take the existing support-floor deferral.
  • Weight bases: kWh rows are amounts, gas-connected households a count. The appliers read desnz_local_energy_facts.json (authority meter counts and four ONS household totals, with the OGL v3.0 attribution for DESNZ and ONS).

BUS01a journeys by English region (C8). Nine national rows, family dft_bus_journeys: London and the eight other English regions, FY2024-25. The frame carries NTS trips, not boardings, so the resolver's new household measures bus_in_london_boardings and other_local_bus_boardings price each household's trips at the boardings per trip the stage priced each series at; a persisted column of either name is refused. London's row counts every resident's bus-in-London trips and has no residence filter. The selectors take BUS01a only (dimensions: []; BUS01c's concessionary rows carry a journey category). They pin no year; instead each row's uprating_index, dft.bus01.stage_pricing_year, holds it at the fiscal year the stage prices boardings per trip from and refuses any other year. The stage's bus receipt sets each English region's share of the eight regions' other local bus trips, at prior weights, beside its share of BUS01a's journeys.

Loss-share floors (C9). UK_LOCAL_FAMILY_LOSS_SHARE_FLOORS: a check-only minimum share of the dense solve's loss weight for domestic_energy (2.5%) and dft_bus_journeys (1.25%), against about 2.8% and 1.5% under the doctrine rule (one of nine local-authority families; one of seventeen nation and region families). It runs after the row-metadata rule builds the weights and is recorded in the problem's bindings; the weights do not change. A share equal to its floor meets it.

Fixes and guards found in local lanes. The kWh read-back decodes the engine's region enum, and it skips households that pay nothing: a defensive guard for a region no QEP price covers (policyengine-uk's UNKNOWN; the frame has none). The bus parity reads engine parameters at the year, as the resolver's other reads do.

Vendoring and regeneration on 735820c.

  • desnz_local_energy_facts.json, declared in uk/country_package.json: 701 rows. They are the domestic electricity meter counts of 350 authorities, the gas meter counts of 347 (the Isles of Scilly, Orkney and Shetland have no gas rows), and four ONS household totals (England, Wales, Scotland and the UK). The licence is in its header.
  • desnz_domestic_energy_facts.json and ofgem_price_cap_facts.json take the C1 purpose texts; no value moves. The lcfs_consumption stage pins the first, so the H2 spine fixture's stage contract hash moves.
  • National references: 1,283 to 1,292 active (the nine BUS01a rows).
  • Local references: 24,269 to 25,309 active. Of the 1,050 new cells (350 authorities, three rows), 1,040 compile. Seven are signed deferrals: the support floor's five (the Isles of Scilly and the City of London on the electricity and gas-connected rows, and the City of London on gas kWh), and Orkney and Shetland's gas-connected cells. The Isles of Scilly, Orkney and Shetland have no gas kWh row; for Orkney and Shetland that absence is signed.
  • Compile parity receipts: the new rows are all ledger_only (national 691 to 700, local 4,991 to 6,031); no calibration_drift or fixture_only count moves.
  • The coverage manifest and the H2 spine fixture are regenerated in the last commit for the whole PR: the rebase onto main after UK local surface: band domain, signed small-cell rules, renewals, support flag (#1278) #1283 kept main's copies in the C1 and C2 commits.

Review round 1 (Vahid, 2026-10-15)

  1. Period guard: the journey rows' uprating_index (dft.bus01.stage_pricing_year) holds each row at the stage's pricing year and refuses another, as the energy rows refuse a DESNZ year other than their level's.
  2. One factor for eight regions: the stage's bus receipt now has england_outside_london_regions (prior-weight trip shares beside BUS01a's journey shares, and London residents' share of the other local trips). Per-region factors need NTS0318 (trips and stages by mode and region of residence), which the feed does not carry yet; it is item 6 of UK local energy, area classification and Welsh bus facts: DESNZ Northern Ireland and sub-local consumption, rural-urban lookups, BUS04 country rows (PolicyEngine/microcosm#1207) chronicle#356.
  3. Electricity period: the texts now say non-half-hourly meters from 31 January to 30 January and half-hourly meters over the calendar year, both counted.
  4. Zero-spend guard: kept as a defensive guard, with a test for the case it covers.
  5. Licence: a vendored resource may declare its publishers' licence; desnz_local_energy_facts.json declares OGL v3.0 for DESNZ and ONS.
  6. WIP titles: reworded in round 2.

Review round 2 (Vahid, 2026-10-15)

  • Artifact and the four artifact-bound tests: the resource is vendored and the references regenerated (above); the four tests pass.
  • 6. WIP titles: reworded with git rebase --exec; the tree did not change. After the rebase they are 30681db03, 0eb83e8c9 and 1cd20e248.
  • 7. Full engine-free run: the verification below runs CI's own engine-free file list without --maxfail.
  • 8. Body: the verification is at the new head, and the last paragraph now says how the branch was rebased.

Rulings (María)

  • 2026-10-14: the whole issue in one PR; local-authority grain only for energy; rows reconciled onto the stage's Energy Trends level; no constituency rows before the Budget; a check-only floor.
  • 2026-10-15, signed in the registers (each expires 2026-12-15):
    • the kWh rows are held at 2024 (matched_period): both sides are 2024 by design, and Energy Trends 2025 was weighed as an index and not taken, so the weights do not absorb the change in use per household;
    • the gas-connected rows keep their 2024 meter share under the household controls (control_rescaled);
    • the BUS01a rows are held at FY2024-25 (matched_period; journeys have no published index);
    • the four domestic_energy fences;
    • floors of 2.5% and 1.25%, checked under the doctrine's row-metadata rules only.

Verification (local, at e2e38751a)

The full runs were at 2ec0c12df, which differs from the head only by the scorer pin below; at the head, the scorer's tests and the dataset-size tool's tests pass.

  • Engine-free, CI's own file list without --maxfail (581 files, 18,819 tests): the four artifact-bound tests pass. Six tests failed. Five come from this machine's environment:

    • test_spawned_workers_score_identically_to_sequential_cli: its worker flag needs Python 3.14.7, and this machine has 3.14.6;
    • test_live_latest_pointer_resolves_to_a_coherent_certified_release[uk-2025-national]: it reads the live published release pointer;
    • the two Orrery parser tests: tools/orrery-contract has no node_modules here, and CI installs them;
    • test_engine_is_reported_unavailable_without_the_uk_extra: this environment has the UK extra installed.

    The sixth was the local candidate scorer's count, which UK local surface, consumption and high-value homes: remaining items (consolidation) #1278 ties to the committed active references. The last commit moves it to 25,309.

  • Engine UK lane (51 files, 209 tests, policyengine-uk 2.130.1): green.

  • tools/ci_test_plan.py verify, tools/graph_acceptance_burndown.py --verify, ruff check . and ruff format --check on every touched Python file: clean.

  • Disclosure: the new commit holds publishers' rows (DESNZ meter counts, ONS household totals), reference and cell counts, hashes and pins. It holds no microdata quantity.

  • Not run here: the integration smoke (CI runs it).

Disclosure control

The committed values are publishers' (DESNZ, DfT, ONS) or declared rules. No per-authority model estimate, error or support count is committed or posted. Build receipts will report, per family, counts and shares of areas within 10% and 25%, support in bands, and no maxima, minima or single areas.

Next

Two spines (control at main, candidate here), two dense arms at K=15, and R1 on the candidate spine, one heavy job at a time; receipts in experiments/1207-local-energy-bus-receipts.md; and the exclusion figures restated from R1. The PR was retargeted to main on 2026-10-15 after #1270 merged and rebased onto main (579296653) so that CI runs. It was rebased again the same day after #1283 merged (8a7f79a82).

🤖 Generated with Claude Code

@juaristi22
juaristi22 force-pushed the uk-high-value-homes-1240 branch 2 times, most recently from e851e76 to e1a65e2 Compare October 15, 2026 10:39
@vahid-ahmadi

Copy link
Copy Markdown
Contributor

@juaristi22

Direction fine. Ready once the 735820c feed artifact is in, the WIP commits are finished and the four artifact-bound tests pass, with 1 and 2 below answered.

I reviewed only this PR's own diff against uk-high-value-homes-1240 at 0263998d4 (head 5689949fe).

Findings

  1. should: the BUS01a rows have no period guard. uk/uk_population_targets.json:15406 onwards declares the nine rows with no period_value, and tests/engine_free/uk/test_uk_bus_targets.py:570 asserts that none is pinned. The matched_period hold in uprating_holds.json says both sides are FY2024-25 on purpose: the target is BUS01a FY2024-25, and the measure uses the stage's boardings per trip, which are priced from FY2024-25 boardings. If a later feed pin carries FY2025-26, the selector will most likely move to it while the stage's factors stay on FY2024-25. The holds register is keyed by target id and kind, not by the fact's period, so it would not catch the move. Nothing else I found would refuse it either, and the hold's reason would then be wrong without anyone noticing. The energy side already refuses this case (domestic_energy_targets.py:321). Either pin period_value, or add the same refusal for the journeys rows against the stage's fiscal_start.

  2. should: one boardings-per-trip factor covers all eight regional rows. household_bus_boardings (uk_runtime/measure_simulation.py:128-166) prices every English region's other_local_bus_trips at the single england_outside_london factor (uk/spec/sources.yaml:3340). Each regional row therefore binds the region's residents' NTS trips times a constant. BUS01a's regional split also reflects things that are not resident trip rates: interchange per trip, cross-boundary travel (counted where buses run, not where people live), and NTS coverage. Whatever part of the BUS01a-versus-NTS regional gap comes from those, the weights will absorb as a difference in who travels. The bindings' notes say that only the split is new information, so I read this as a known choice. Even so, please add a design-weight receipt per region before the cut: the frame's share of England-outside-London boardings beside BUS01a's. Then a large regional pull can be read as a measurement gap or as a population gap. If the NTS regional trip-rate table can be vendored, per-region factors would remove most of this.

  3. nit: the electricity period in the text is slightly off. The fence (local_target_census.py, desnz_subnational_consumption_basis) and the hold reason in uprating_holds.json say domestic electricity is read February to January. DESNZ's subnational methodology booklet (December 2025 edition, section 1) gives 31 January to 30 January for non-half-hourly meters and 1 January to 31 December for half-hourly meters, and counts both. As more domestic smart meters move to half-hourly settlement, a larger part of the series is on calendar 2024. This is text only; since only the split is bound, it does not change the arithmetic.

  4. nit: paying = spend > 0 in uk_runtime/domestic_energy_targets.py:145 looks redundant, because spend_to_kwh already floors spend - fixed at zero. I changed it to >= 0 and the domestic energy, local targets and diagnostics tests all still passed. The body lists it as a fix found in local lanes. If it guards a real case (a region with no gas price, say), add a test for that case. If not, it is harmless, but the body overstates it.

  5. nit: none of the Chronicle-vendored resources carry a licence line, whereas the UK: data fixes to model the High Value Council Tax Surcharge (mansion tax) correctly, and the related housing and council-tax gaps #1240 derived resources state OGL v3. When desnz_local_energy_facts.json is vendored, it would be worth adding the OGL v3 attribution for DESNZ and ONS in the same way, or recording it in country_package.json.

  6. nit: bf76e354, 1bdd4e78 and 847f4bc5 carry "WIP" in their titles. Reword or squash them when the artifact work completes them.

Source and method checks (no change needed)

  • DESNZ sub-national basis, checked against DESNZ's subnational methodology booklet. Gas covers mid-May 2024 to mid-May 2025, is weather-corrected, and treats meters under 73,200 kWh as domestic. Electricity is not weather-corrected (see 3 for its period). Both cover Great Britain, with Northern Ireland published separately. Apart from 3, the fences state this correctly. Only the split between authorities is bound, at the stage's Energy Trends level (actual temperature), so weather correction only enters through within-GB shares. The Northern Ireland interim is fenced and already has a source requested in UK local energy, area classification and Welsh bus facts: DESNZ Northern Ireland and sub-local consumption, rural-urban lookups, BUS04 country rows (PolicyEngine/microcosm#1207) chronicle#356.
  • Roster. 350 electricity and 347 gas authorities, matching the vendor selection's 697. The three without gas rows are Orkney, Shetland and the Isles of Scilly. Orkney and Shetland are signed absent in tools/generate_uk_local_target_references.py, so the applier's refusal on a missing meter row will not fire for them once the references are regenerated. The crosswalk already carries the lad_2025 aliases the body relies on for Barnsley and Sheffield. I did not check the full 2025 roster against lad_2023 beyond those.
  • Units. The kWh read-back is the exact inverse of kwh_to_spend (fixed cost and then unit rate, both from QEP including VAT), and the spend is read at the stored period, so the engine's CPI uprating does not touch it. The engine test pins this.
  • No double-binding with UK: lcfs_consumption on LCFS 2024-25, with the energy, income-band and prepayment fixes (#1164) #1260. The national ONS energy spend rows are signed exclusions, so the local kWh rows are the only bound energy rows, and they sit on the level the stage rakes to. The gas-connected rows overlap the stage's regional meter share by design, and the overlap is fenced.
  • Northern Ireland bus re-pricing. The weights are 0.25 on the yield of the fiscal year opening in 2023 and 0.75 on the one opening in 2024, which is the right calendar-2024 window.
  • Bus parity. On the locked engine, bus_engine_parity is within the 0.1% tolerance in all four areas (largest gap about 0.06%), so the fare rows and the journeys rows read the same factors.
  • Disclosure. The files, fixtures, commit messages and body carry only publisher figures, synthetic test values and declared rules. I found no microdata quantities.

What I checked

  • Fresh worktree at 5689949fe, fresh uv sync --all-packages --locked.
  • tests/engine_free/uk: exactly four failures, the ones the body lists, and nothing else: test_uk_ledger_fact_vendoring.py (two tests, missing desnz_local_energy_facts.json), TestPreflightBindings::test_local_default_target_surface_uses_metric_names_and_signed_deferrals, and test_uk_bus_targets.py::test_bus_journey_rows_are_active_references. Each fails on the missing resource or references. The battery gate reports exactly the energy cells as missing from the local surface. Without the UK extra, the CGT test from the body does not fail, as expected.
  • tests/engine_free/shared: no failures.
  • A second venv with --extra uk: tests/engine/uk/test_uk_bus_engine_parity.py and test_uk_local_energy_metrics.py both pass.
  • ruff check ., ruff format --check on the touched Python files, tools/ci_test_plan.py verify and tools/graph_acceptance_burndown.py --verify: all clean.
  • Revert check: restoring sources.yaml and source_stages.json to the base makes the three Northern Ireland own-yield tests in test_uk_bus_fare_pricing.py fail.
  • Read DESNZ's subnational methodology booklet (the gov.uk PDF, December 2025 edition) for the period, weather-correction and coverage points.
  • What I could not check: anything that needs the feed artifact. That covers the meter-share values per authority (including whether any authority falls outside (0, 1]), the Northern Ireland LGD cells' signed absences on the regenerated local surface, the compile parity receipts, and any design- or final-weight fit. I did not run the full engine UK lane or the integration smoke.

🤖 Generated with Claude Code

@juaristi22

Copy link
Copy Markdown
Collaborator Author

@vahid-ahmadi thank you. Rebased onto #1270's new head (e1a65e2c7, which sits on main at 412f91653, so policyengine-uk 2.130.1). Answers below; head 11c9fa57b.

  1. Period guard (should): done. The nine journey rows declare uprating_index: dft.bus01.stage_pricing_year. Its applier, hold_bus_journeys_at_the_stage_year in uk_runtime/bus_fare_pricing.py, does two things. It holds each row at the fiscal year the lcfs stage prices boardings per trip from (fiscal_start: 2024-04-01; factor one, under the signed matched-period hold). It refuses a row resolved to any other year, naming the stage's fiscal_start, which is the refusal the energy rows already have. It runs in the reference generator and in the runtime compile. I left period_value unpinned: a new edition then fails loudly, instead of the rows staying on FY2024-25 without anyone noticing. Tests: test_journey_rows_hold_at_the_year_the_stage_prices_from and test_a_journey_row_from_another_year_is_refused.

  2. Per-region receipt (should): done. Per-region factors: not yet. The stage's bus receipt gains england_outside_london_regions, at prior weights:

    • each English region's share of the eight regions' other local bus trips (with one factor, trip shares are boardings shares);
    • its share of BUS01a's journeys, and the ratio of the two;
    • London residents' share of the other local trips, which fall in no region row.

    It reads the BUS01a region rows that dft_bus_journeys.json already vendors; a test pins that the eight sum to England outside London. The receipt comes with the candidate spine, before the cut. Per-region factors need NTS trip rates by region of residence. DfT publishes them in NTS0318 (trips and stages per person per year, by mode and region of residence), but the feed carries the bus trip rates for England only (NTS0303a, NTS0601a and NTS0705a). NTS0318 is now item 6 of UK local energy, area classification and Welsh bus facts: DESNZ Northern Ireland and sub-local consumption, rural-urban lookups, BUS04 country rows (PolicyEngine/microcosm#1207) chronicle#356.

  3. Electricity period (nit): fixed. The source note, the fence, its adjudication, the kWh hold's reason and the contract note now say: non-half-hourly meters from 31 January to 30 January, half-hourly meters over the calendar year, both counted. Source: DESNZ's subnational methodology and guidance booklet (July 2026 update).

  4. Zero-spend guard (nit): kept, with a test. It covers a case the engine can produce but the frame does not: policyengine-uk's region enum carries UNKNOWN, which no QEP price region covers. A household there with no spend reads zero kWh; one that pays is refused. test_a_household_paying_nothing_needs_no_price_region pins it. The body now calls it a defensive guard, not a fix.

  5. Licence (nit): done. An entry in the selection register may declare a licence (the licence and the attribution lines). It is validated and copied into the vendored header. desnz_local_energy_facts.json declares OGL v3.0 for DESNZ and ONS. The other resources declare none, so their files do not change.

  6. WIP titles (nit): agreed. I will reword or squash those commits when the artifact work completes them.

Verification at 11c9fa57b:

  • Engine-free UK lane (4,975 tests): the same five failures as before. Four need the feed artifact: the two vendoring tests, the local default surface in TestPreflightBindings, and test_bus_journey_rows_are_active_references. The fifth, the CGT engine-extra test, fails only because my environment has the UK extra.
  • Engine-free shared lane (4,061 tests): green.
  • Engine UK lane (195 tests, policyengine-uk 2.130.1): green, including the bus parity and the local energy metrics.
  • tools/ci_test_plan.py verify, tools/graph_acceptance_burndown.py --verify, ruff check and ruff format --check on every touched Python file: clean.

🤖 Generated with Claude Code

@juaristi22 juaristi22 closed this Oct 15, 2026
@juaristi22 juaristi22 reopened this Oct 15, 2026
@juaristi22
juaristi22 marked this pull request as ready for review October 15, 2026 12:10
@juaristi22
juaristi22 changed the base branch from uk-high-value-homes-1240 to main October 15, 2026 12:11
@juaristi22
juaristi22 force-pushed the uk-local-energy-bus-1207 branch from 11c9fa5 to dc0756f Compare October 15, 2026 12:12
@vahid-ahmadi

Copy link
Copy Markdown
Contributor

@juaristi22

Fine once the 735820c feed artifact is in, the four artifact-bound tests pass and the WIP commits are reworded. Points 1 to 5 are fixed.

Round 2, at head dc0756f56 against main (579296653). #1270 has merged, and main's tree is the same as e1a65e2c7's, so the PR's diff against main is now only its own 20 commits. 11c9fa57b is no longer on the remote, so I compared with my round-1 head 5689949fe using git range-diff. The 16 earlier commits are unchanged apart from hashes and the target counts that moved with #1270's final head. The four new commits are the round-1 answers.

Round-1 points

  1. Period guard (should): fixed. All nine BUS01a rows now declare uprating_index: dft.bus01.stage_pricing_year (uk/uk_population_targets.json). hold_bus_journeys_at_the_stage_year (uk_runtime/bus_fare_pricing.py:878, registered at uk_runtime/ledger_targets.py:680) refuses (:900) a row whose ledger_fact_period is not the opening year of the stage's fiscal_start. _comparable_period_value turns DfT's closing-year label into the opening year, so FY2024-25 compares as 2024, and the check compares like with like. Leaving period_value unpinned so that a new edition fails loudly is a reasonable choice. Revert check: with the year test disabled, test_a_journey_row_from_another_year_is_refused fails.
  2. One factor for eight regions (should): partly fixed, as agreed. The stage's bus receipt now has england_outside_london_regions: each region's share of the frame's other local bus trips at prior weights, BUS01a's share, the ratio, and London residents' share, which falls in no region row. That is what I asked for before the cut. test_the_eight_regions_sum_to_england_outside_london pins that the vendored region rows add up to the England-outside-London row. Per-region factors wait on NTS0318 (UK local energy, area classification and Welsh bus facts: DESNZ Northern Ireland and sub-local consumption, rural-urban lookups, BUS04 country rows (PolicyEngine/microcosm#1207) chronicle#356 item 6), which is fine for this PR.
  3. Electricity period (nit): fixed. The source note, the fence, the adjudication, the kWh hold and the selector note all now give 31 January to 30 January for non-half-hourly meters and the calendar year for half-hourly meters.
  4. Zero-spend guard (nit): fixed. At uk_runtime/domestic_energy_targets.py:145. I was wrong that the guard was redundant: it is what lets an UNKNOWN-region household with no spend through without a price lookup. With spend > 0 changed to >= 0, test_a_household_paying_nothing_needs_no_price_region fails. The body now calls it a defensive guard.
  5. Licence (nit): fixed in the register. ledger_fact_vendor_selections.json gives desnz_local_energy_facts.json an OGL v3.0 licence with DESNZ and ONS attribution lines. ledger_fact_vendoring.py validates it and copies it into the vendored header, and the other resources' files stay unchanged. It will show in the file once the resource is vendored.
  6. WIP titles (nit): not yet, as agreed. ed1936da, 5f5068ea and e2b965e1 still say WIP.

New findings

  1. note, no change needed: CI's engine-free job only shows the first artifact-bound failure. tools/run_engine_free_tests.sh runs with --maxfail=1, so both Python versions stop at TestPreflightBindings::test_local_default_target_surface_uses_metric_names_and_signed_deferrals. The other three artifact-bound tests, and whatever was queued after them, did not run in CI. My local run below covers them. Once the artifact is in, treat a full green engine-free run as the check, not the current red.
  2. nit: the body's Verification section is still dated at 11c9fa57b, and its last paragraph says the branch "needed no rebase". All 20 commits have new hashes with committer time 12:12 UTC today, so it was rewritten after your reply. Worth updating the heading to dc0756f56 when you next edit the body.

I found nothing else new in the four commits. The region-share receipt is report-only, at prior weights, and only shares are recorded.

What I checked

  • gh auth status; PR, Place high-value homes where the Land Registry sees them (#1240) #1270 and CI state through gh; the CI job logs for both engine-free jobs.
  • Fresh worktree at dc0756f56, fresh uv sync --all-packages --locked.
  • tests/engine_free/uk locally: exactly four failures, the same four as round 1. They are the two test_uk_ledger_fact_vendoring.py tests (no desnz_local_energy_facts.json), the TestPreflightBindings local surface (energy cells missing), and test_bus_journey_rows_are_active_references (nine BUS01a ids not in the committed references). Nothing else failed. The 735820c pin is already in chronicle_feed.json; the resource and the regenerated references are what is missing.
  • tests/engine_free/shared: no failures.
  • ruff check ., ruff format --check on the touched Python files, tools/ci_test_plan.py verify, tools/graph_acceptance_burndown.py --verify: clean.
  • Revert checks for points 1 and 4, as above.
  • CI at dc0756f56: lint, wheels, engine-uk (3.13, 3.14) and integration-uk pass. Engine-free (3.13, 3.14) fails on the artifact-bound test above. Engine-us was still running.
  • Disclosure: the four new commits and the body hold only publisher figures, declared rules, test counts and synthetic test values. I found no microdata quantities.
  • Not checked: anything that needs the feed artifact (the vendored resource's contents, the regenerated references, the compile parity receipts, the region-share receipt on a real spine). I did not run the engine UK lane locally; CI ran it.

🤖 Generated with Claude Code

juaristi22 and others added 17 commits October 15, 2026 16:24
… ceiling legs (#1207)

The energy_pricing module header still summed Energy Trends over a fiscal
year and stopped at the level step; the stage levels to calendar 2024
(microcosm#1113) and since microcosm#1164 also connects zero-gas households
where a region's draw falls short and caps household kWh at the declared
domestic-meter limits. The energy_rake gate's docstring, the crosswalk's
policy text (pricing is at QEP regions, not cap levels) and the stage note on
the ceiling (capped households' NEED cells are re-raked, not every household)
now say so. Text only: no value moves. The stage note moves the coverage
manifest and the H2 spine fixture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
)

Northern Ireland publishes no bus fares index, so its 2024-25 yield was
re-priced to calendar 2024 on England's local bus fares index, a declared
proxy carrying the January 2025 rise in the English fare cap. A new
price_index basis, own_fiscal_yields, weights the area's own published yields
of the fiscal years opening in 2023 and 2024 three months and nine (the
calendar_year_window weights) over the later yield; the bus_pricing gate
recomputes it through the same bus_fare_prices call. The factor moves from
0.982 to 0.989. The schema admits the basis; the stage, coverage manifest and
H2 spine fixture move with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…els (#1207)

Report-only. division_capture gains, per division and in total, the donor's
weighted total and the frame's over it, in all and per household: the
furnishings and health over-draw #1207 lists can now be read on any build
against the 2024-25 donor. The recompose receipt's uncarried block (ONS
04.5.3 and 04.5.4, which stay in the housing total) gains the donor's own
other fuels at diary prices beside it. No column, gate or generated surface
moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s drift (#1207)

policyengine-uk prices bus fares from the dataset's trips at its own
boardings per trip and yield per boarding, while the national fare rows
calibrate the stage's priced column, and nothing compared the two. The
measure resolver's receipt now carries bus_engine_parity, area by area, with
each gap marked against a 0.1% tolerance (report only; an engine without the
parameters records why). On the locked engine the boardings per trip sit a
few hundredths of a per cent below the stage's, after the population re-pin,
and Northern Ireland's yield above it, after DfI's restatement; the other
yields agree. consumption_drift also reports the full-rate VAT base at
design and final weights. No target, gate or spine surface moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DESNZ's subnational energy statistics stamp every authority with the NSPL
their publication was built on, publication_2025_nspl: the April 2025 LAD
frame in England and Wales and the 2019 council areas in Scotland, the
roster's boundaries but for Barnsley and Sheffield, which the existing
lad_2025 aliases already carry. The crosswalk's England, Wales and Scotland
accept-sets gain the label, so the local energy family's facts compile; a
Northern Ireland fact stamped with it still refuses. The crosswalk was
regenerated from the pinned ladder (bed3f13d); only the accept-sets move.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…om spend (#1207)

Two uprating appliers for the local-authority energy rows: one factor per
fuel takes Great Britain's authorities to the lcfs stage's Energy Trends
level (Northern Ireland's part at Great Britain's share of UK households
until PolicyEngine/chronicle#356 lands), and the gas-connected households
take each authority's gas meters over its electricity meters. Both stamp a
hold for the register. household_energy_kwh inverts the stage's
kWh-to-spend step; the drift receipt carries kWh at both weights (M1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ily, routes (#1207)

Three local-authority rows for England, Wales and Scotland: electricity
and gas kWh and gas-connected households. The metrics energy/* are
appended after the high-value homes metrics and read the stored spend
at the dataset period. The census family domestic_energy carries two
DESNZ sources and four fences; kWh rows are amounts and gas-connected
households a count; the gas-connected cells join the census household
partition and take its uprating; the kWh rows declare no higher
control; Orkney and Shetland are signed deferrals. The vendored
resource and the regenerated surfaces land in the last commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ns (#1207)

Nine national rows, family dft_bus_journeys. The frame carries NTS
trips, so the resolver's household measures price each household's
trips at the boardings per trip the lcfs stage priced each series at;
a persisted column of either name is refused. The generator maps the
eight regions. The regenerated national references land in the last
commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…re (#1207)

A declared minimum share of the dense solve's loss weight for DESNZ's
local energy family and the BUS01 region journeys, checked after the
row-metadata rule builds the weights and recorded in the problem's
bindings. Check-only: the rule's arithmetic is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…enum (#1207)

A household paying nothing for a fuel uses none of it whatever its
region, so the kWh read-back prices paying households only. A plain
policyengine-uk Simulation returns region as enum codes, so the local
energy metrics decode it before pricing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… reads do (#1207)

The bus engine parity read parameters at "YYYY-01-01"; the resolver's
UC and rate-class reads pass the year itself, which the engine resolves
to the same instant. A stub that pins the year form refused the read.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the new rows (#1207)

The support-floor deferral pins move by the three energy rows; the BUS05
finance tests scope to their family and the BUS01a journey rows get
their own tests; the data-target parity register lists the three local
energy targets; changelog fragments for both families.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t period (#1207)

policyengine-uk uprates electricity and gas spend by CPI away from the
period they were supplied for; the engine test reads the metric at the
dataset period and checks the calibration period would differ.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#1207)

The rule's shares are ratios of small integers (one family in ten of a
grain's four is 2.5% exactly); a sum of float weights can land a hair
under the floor and refuse a surface that meets it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1207)

María's rulings of 2026-10-15: the nine BUS01a journey rows are held at
FY2024-25 (matched period, no published index for journeys); the four
domestic_energy fences are accepted as drafted; the loss-share floors
stay 2.5% and 1.25%, checked under the doctrine's row-metadata rules
only. Each signed entry expires on 2026-12-15.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
María's ruling of 2026-10-15: the kWh rows stay at 2024 (matched
period; Energy Trends 2025 was weighed as an index and not taken), and
the gas-connected rows keep their 2024 meter share under the household
controls (control rescaled). Both expire on 2026-12-15.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gion's share (#1207)

Review round 1, findings 1 and 2. The nine journey rows declare
dft.bus01.stage_pricing_year: an applier holds each row at the fiscal
year the lcfs stage prices boardings per trip from (factor one, the
signed matched-period hold) and refuses a row resolved to another year,
as the energy rows refuse a DESNZ year other than their level's.

The stage's bus receipt gains england_outside_london_regions at prior
weights: each English region's share of the eight regions' other local
bus trips (one boardings-per-trip factor, so trip shares are boardings
shares) beside its share of BUS01a's journeys, and London residents'
share of the other local trips, which fall in no region row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
juaristi22 and others added 4 commits October 15, 2026 16:24
Review round 1, finding 3. DESNZ's subnational methodology and guidance
booklet reads non-half-hourly meters from 31 January to 30 January and
half-hourly meters over the calendar year, and counts both; the source
note, the fence, its adjudication, the kWh hold and the contract note
said February to January. Text only: the rows bind DESNZ's split.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 1, finding 4. policyengine-uk's region enum carries
UNKNOWN, which no QEP price region covers: a household there that pays
nothing reads zero kWh, and one that pays is refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 1, finding 5. A selection register entry may declare a
licence (the licence and the attribution lines), validated and copied
verbatim into the vendored header, as the derived resources state
theirs. desnz_local_energy_facts.json declares OGL v3.0 for DESNZ and
ONS; the other resources declare none, so their files do not move.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1207)

The 735820c feed artifact, whose facts and manifest digests are the
ones chronicle_feed.json pins, vendors desnz_local_energy_facts.json
(declared in country_package.json): the domestic electricity meter
counts of 350 Great Britain authorities, the gas meter counts of 347
(the Isles of Scilly, Orkney and Shetland have no gas rows), and four
ONS household totals, 701 rows, with the OGL v3.0 licence in the
header. desnz_domestic_energy_facts.json and ofgem_price_cap_facts.json
take the C1 purpose texts; no value moves.

The national references gain the nine BUS01a rows (1,283 to 1,292
active). The local references gain 1,050 DESNZ cells (350 authorities,
three rows), 1,040 of them active (24,269 to 25,309): seven are signed
deferrals (the support floor's five, Orkney and Shetland's
gas-connected cells) and the Isles of Scilly, Orkney and Shetland have
no gas kWh row. The compile parity receipts take the new rows as
ledger_only (national 691 to 700, local 4,991 to 6,031); no
calibration_drift or fixture_only count moves. The reference, deferral,
resource and scorer count pins move with them.

The coverage manifest and the H2 spine fixture are regenerated here
for the whole PR: the rebase onto main after #1283 kept main's
regenerated copies in the stage-text and Northern Ireland fare commits,
whose source manifest and lcfs_consumption stage contract this PR
changes, as the re-vendored purpose text does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@juaristi22
juaristi22 force-pushed the uk-local-energy-bus-1207 branch from dc0756f to e2e3875 Compare October 15, 2026 17:04
@juaristi22

Copy link
Copy Markdown
Collaborator Author

@vahid-ahmadi thank you. #1283 merged into main while I worked, so I rebased onto it (8a7f79a82; policyengine-uk is still 2.130.1). Then I vendored the 735820c resource, regenerated the surfaces and reworded the WIP commits. The four artifact-bound tests pass. Head e2e38751a.

Artifact. My other lane built it from PolicyEngine/chronicle@735820c. Its facts and manifest digests (3033e437…, 2777dc33…, 950,242 rows) are the ones chronicle_feed.json already pins.

Rebase. For the generated files I took main's side, then regenerated them all on the rebased tree. I merged two files by hand. uk_runtime/local_targets.py keeps main's UK_COUNCIL_TAX_BANDS import beside the energy imports. The pin comment in test_uk_battery_bindings.py keeps #1278's small-cell deferral counts beside this PR's energy cells. The small-cell rules cover only the council-tax band and HMRC higher-rate prefixes, so they defer no energy cell. The C1 and C2 commits conflicted with main only in the coverage manifest and the H2 spine fixture; they keep main's copies, and the last commit regenerates both for the whole PR.

New commit e2e38751a. It vendors desnz_local_energy_facts.json and declares it in uk/country_package.json. The file has 701 rows: the domestic electricity meter counts of 350 authorities, the gas meter counts of 347 (the Isles of Scilly, Orkney and Shetland have no gas rows), and four ONS household totals. Its header carries the OGL v3.0 licence. desnz_domestic_energy_facts.json and ofgem_price_cap_facts.json take the C1 purpose texts; no value moves. The lcfs_consumption stage pins the first, so the H2 spine fixture's stage contract hash moves. The commit also regenerates the references against main:

  • national: 1,283 to 1,292 active (the nine BUS01a rows);
  • local: 24,269 to 25,309 active. Of the 1,050 new cells (350 authorities, three rows), 1,040 compile. Seven are signed deferrals: the support floor's five (the Isles of Scilly and the City of London on the electricity and gas-connected rows, and the City of London on gas kWh), and Orkney and Shetland's gas-connected cells. The Isles of Scilly, Orkney and Shetland have no gas kWh row; for Orkney and Shetland that absence is signed.
  • compile parity: the new rows are all ledger_only (national 691 to 700, local 4,991 to 6,031); no calibration_drift or fixture_only count moves.

The count pins move with them.

6. WIP titles: done. I used git rebase --exec before the rebase, and the tree did not change. After the rebase they are:

Their bodies now say that the resource and the regenerated surfaces land in the last commit.

7. Full run: agreed. The verification below runs CI's own engine-free file list (tools/ci_test_plan.py list-job engine-free) without --maxfail.

8. Body: fixed. The Verification section is now at e2e38751a, and the last paragraph says how the branch was rebased.

Verification at e2e38751a. The full runs were at 2ec0c12df, which differs from the head only by the scorer pin below; at the head, the scorer's tests and the dataset-size tool's tests pass.

  • Engine-free, CI's own file list without --maxfail (581 files, 18,819 tests): the four artifact-bound tests pass. Six tests failed. Five come from this machine's environment:

    • test_spawned_workers_score_identically_to_sequential_cli: its worker flag needs Python 3.14.7, and this machine has 3.14.6;
    • test_live_latest_pointer_resolves_to_a_coherent_certified_release[uk-2025-national]: it reads the live published release pointer;
    • the two Orrery parser tests: tools/orrery-contract has no node_modules here, and CI installs them;
    • test_engine_is_reported_unavailable_without_the_uk_extra: this environment has the UK extra installed.

    The sixth was the local candidate scorer's count, which UK local surface, consumption and high-value homes: remaining items (consolidation) #1278 ties to the committed active references. The last commit moves it to 25,309.

  • Engine UK lane (51 files, 209 tests, policyengine-uk 2.130.1): green.

  • tools/ci_test_plan.py verify, tools/graph_acceptance_burndown.py --verify, ruff check . and ruff format --check on every touched Python file: clean.

  • Disclosure: the new commit holds publishers' rows (DESNZ meter counts, ONS household totals), reference and cell counts, hashes and pins. It holds no microdata quantity.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UK consumption-tax levels: open items after #1167

2 participants