Conversation
Key each petrol and diesel rate to its effective date and day-weight it across each model year with fiscal_year_blend, instead of storing calendar-year averages dated 1 January. Model year 2027 (2027-28) was 59.25p; it is now 59.77p, the April 2027 RPI-uprated rate. The schedule follows SI 2026/164 as amended by SI 2026/555 (HMRC amended rates, 22 May 2026): 52.95p to 31 December 2026, 55.95p from 1 January 2027, 57.95p from 1 March 2027. RPI steps each 1 April from 2027 are generated from the OBR March 2026 RPI series by calculate_fuel_duty_rates.py and extended by cadence uprating. LPG and natural gas move to the same dates. The 2012 rate of 60.97p, never charged, is removed. Fixes #1882 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Full policy YAML suite on 9390415 ( |
- Cite HM Treasury's Budget 2025 costing (page 14) for the 1 April 2027 uprating date and HMRC's amended note for final rates at Budget 2026; the generator takes the RPI forecast citation from yoy_growth.yaml. - Complete statutory references: heavy oil in FA 2010 s.13(2)(c), and FA 2012 s.188 and SI 2012/3055 for the 2012 rate never charged. - Notebook shows the dated schedule from the parameter file, re-executed. - Test that an annual override leaves every other model year unchanged. - Docs: keep the original HMRC note for RPI uprating from 2027/28, name the Scenario.parameter_changes path in the 2031+ limitation, and note the RPI index ends in 2039. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Axiom differential check for this fix. TheAxiomFoundation/axiom-oracles#565 rebuilds Axiom's
This agrees with the statutory part of this PR's schedule. Against pe-uk 2.102.0:
One nuance: the orders deduct a percentage from the amount payable, and column (D) is "only for ease of reference". So the operative charge is 0.5795 × 0.9137 = 0.52948915 a litre, not 0.5295 (and 0.55950725, not 0.5595). The gap is about £0.01 per 920 litres. HMRC publishes the column (D) figures, so the Axiom comparison uses them and compares at a £0.00005 per-litre tolerance. |
Fixes #1882
Summary
gov.hmrc.fuel_duty.petrol_and_dieselstored calendar-year averages dated 1 January. Model years run from 6 April to 5 April, so each model year read the wrong average. Model year 2027 (2027-28) read 59.25p a litre, although every day of 2027-28 falls after the April 2027 RPI uprating. This PR keys each rate to its effective date, cites its instrument, and turns onfiscal_year_blend: true, which day-weights the schedule across each model year.HMRC's Amended Fuel Duty rates: 2026 to 2027 (22 May 2026) and SI 2026/555 removed the 1 September 2026 step and moved the December step to 1 January 2027.
The April steps are a forecast, not law. Budget 2025 says rates will be uprated "by Retail Prices Index (RPI) from April 2027". HM Treasury's Budget 2025 policy costings, page 14 dates the uprating from 1 April 2027. HMRC's May 2026 note says final rates will be confirmed at Budget 2026. No official source I found (Budget 2025 costings, OBR November 2025 and March 2026 EFOs, the OBR fuel duties page) names the RPI measure. The model keeps its existing convention: each 1 April applies the previous calendar year's growth from
gov.economic_assumptions.yoy_growth.obr.rpi, which holds the OBR March 2026 calendar-year series at one decimal place. It rounds to the nearest 0.01p.calculate_fuel_duty_rates.pynow writes those steps to 1 April 2031. After that, cadence uprating (at_defined_interval) continues each 1 April.Model-year rates (£/litre)
A reform holding 55.95p for 2027 now saves 3.82p a litre (59.77p − 55.95p), where it previously saved 3.30p.
Other changes
lpgandnatural_gasmove to the amended dates (0.3052 and 0.2385 per kg from 1 Jan 2027; SI 2026/164 art. 8, Table E). Model year 2026 gas duty on 1,000 kg of each falls from £528.94 to £524.01.docs/engineering/excise-duties.mdand the fuel duty notebook describe the dated schedule, and no longer say petrol and diesel use calendar years.Invariants
Each is tested in
policyengine_uk/tests/test_fuel_duty_schedule.py.fuel_dutyon 1,000 litres for the same years.yoy_growth.obr.rpi, a differential against the generator's inputs. The test fails with a regeneration command when the RPI forecast changes.Scenariooverride sets that model year's rate andfuel_dutyexactly, and leaves every other model year from 2015 to 2040 unchanged.Mutation check: against main's parameter file, 32 of the 73 new Python tests fail.
Independent review (Subfleet, Opus) of 9390415 confirmed every rate, date, reference and computed value, and the code paths. Its valid findings are fixed in 0cfd91e: reference titles, the notebook, testing every year for reform isolation, and the limitation's scope. One finding was refuted: Budget 2025 does contain the RPI statement.
Known limitation
The limitation applies to
Scenario.parameter_changesoverrides on model year 2031 or later, where the steps come from uprating metadata. Those overrides make every later year one 1 April step low, because uprating restarts after the reformed year from the last written rate. Executed examples:This is how core uprating treats any uprated parameter, and the docs note it.
Commands run
uv run pytest policyengine_uk/tests/test_fuel_duty_schedule.py: 73 passed (at 0cfd91e, 106 with the fiscal-year, excise and reform suites)uv run pytest policyengine_uk/tests/test_fiscal_year_parameters.py test_excise_schedules.py test_fuel_duty_litres.py test_road_fuel_volume_uprating.py test_parametric_reform_impacts.py: 36 passeduv run policyengine-core test policyengine_uk/tests/policy/baseline/gov/hmrc/fuel_duty .../excise_integration.yaml -c policyengine_uk: 16 passeduvx ruff format .andruff checkon changed Python: cleancalculate_fuel_duty_rates.py --updatereproduces the committed block byte for byteThe full pytest suite and the microsimulation tests run in CI.
hypothesis>=6is added to thedevextra for the property test.axiom: TheAxiomFoundation/rulespec-uk#349 queued
🤖 Generated with Claude Code