What went wrong¶
policyengine-core’s changelog for 3.24.4 describes the bug: its cache
invalidation after apply_reform “wiped every variable’s
_memory_storage._arrays, which also wiped user-provided dataset inputs
loaded via set_input. Country-package subclasses calling set_input
during construction and then applying a structural reform (the
policyengine-uk pattern) silently lost their datasets.” In the failing
tests, inputs such as age, employment_income and would_claim_* were
gone before any calculation ran, so tax and benefits came out as zero.
Two other explanations were considered and do not fit the harness code
at policyengine.py#280’s head (6772ecc):
The dataset-required change (policyengine-uk 2.76.0, where
Simulation()with no situation, no dataset and noPOLICYENGINE_UK_DEFAULT_DATASETraises aValueError). The harness passed an explicit dataset (Microsimulation(dataset=...)insrc/policyengine/tax_benefit_models/uk/model.py), so it never reached that path.The default period (
default_input_periodanddefault_calculation_period, 2025 in both 2.74.0 and 2.88.0). The harness passedperiod=to every calculation, and the failing tests built 2026 households.
Reproduction from the UK side¶
Two comparable scenarios, run directly against policyengine-uk main for
2025 (the failing tests used 2026 and a one-adult, two-child family):
from policyengine_uk import Simulation
YEAR = 2025
# Scenario 1: single adult with employment income.
s1 = {
"people": {"adult": {"age": {YEAR: 30}, "employment_income": {YEAR: 50_000}}},
"benunits": {"benunit": {"members": ["adult"]}},
"households": {"household": {"members": ["adult"]}},
}
sim = Simulation(situation=s1)
print("income_tax:", sim.calculate("income_tax", YEAR).sum())
# -> 7486.00
# Scenario 2: couple with one child.
s2 = {
"people": {
"a1": {"age": {YEAR: 35}, "employment_income": {YEAR: 30_000}},
"a2": {"age": {YEAR: 33}},
"c1": {"age": {YEAR: 5}},
},
"benunits": {"benunit": {"members": ["a1", "a2", "c1"]}},
"households": {"household": {"members": ["a1", "a2", "c1"]}},
}
sim = Simulation(situation=s2)
print("child_benefit:", sim.calculate("child_benefit", YEAR).sum())
# -> 1354.60Re-checked on 23 October 2026 on policyengine-uk 2.148.2 (policyengine-core 3.33.2): both scenarios return £7,486 and £1,354.60. Both also return non-zero values for every year from 2022 to 2025. The income-tax figure is the same each year because the personal allowance (£12,570), the basic rate limit (£37,700) and the 20% basic rate are unchanged from 2021-22; child benefit follows the eldest-child rate (£1,133.60 in 2022, £1,248.00 in 2023, £1,331.20 in 2024).
References¶
Issue: #1628.
Where the failure showed:
PolicyEngine/policyengine.py#280(closed without merging, superseded by #282).The fix:
PolicyEngine/policyengine-core#475(core 3.24.4) andPolicyEngine/policyengine.py#283(core floor 3.25.0).Default-period contract:
policyengine_uk/simulation.py(default_input_period,default_calculation_period).Default-dataset env var contract:
POLICYENGINE_UK_DEFAULT_DATASET, defined inpolicyengine_uk/tax_benefit_system.pyand read inpolicyengine_uk/simulation.py.