Repository navigation
Conversation
pawhp was in gov_spending but not in household_benefits, hbai_household_net_income or hbai_benefits, so once the Winter Fuel Payment stopped covering Scotland (2024 qualifying week), Scottish pensioners' winter heating payment fell out of household net income and HBAI income. Add it to the three lists next to winter_fuel_allowance. disable_simulated_benefits could not run: Simulation never set tax_benefit_system.simulation (core's __init__ does, this one replaces it), and the reform named five _reported variables that no longer exist (AA, DLA and PIP follow the reported award through their categories). Set the attribute, drop the five, and count the one reported winter heating payment (FRS code 62, Scotland included) once: as pawhp in Scotland while PAWHP is paid, as winter_fuel_allowance otherwise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Matches the constant name used by the parallel disable-simulated-benefits rework, and keeps the two branches from adding the same test file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Net measures fall by pawhp less the change in the household's income tax (zero today), so the property still holds once the winter fuel payment charge (ITEPA 2003 s.681I) is modelled in income tax. Compare at float32 precision: a 1p tolerance failed on a household with net income of about 150,000, where one float32 step is 1.6p. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 2, 2026
Collaborator
Author
|
#2038 merged into main as 4012143, so this PR's base is now
🤖 Generated with Claude Code |
MaxGhenis
marked this pull request as ready for review
October 11, 2026 15:47
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2313
This was stacked on #2038, which pays the Winter Fuel Payment in Scotland up to the 2023 qualifying week and the Pension Age Winter Heating Payment (PAWHP) per person from 2024. #2038 has merged (
40121430). This branch now targetsmainand includes it at6d89338ab(merge commite554001fa, no conflicts).Summary
#1000 (merged 5 December 2024) stopped paying
winter_fuel_allowancein Scotland and addedpawhptogov_spending. It did not add it tohousehold_benefits,hbai_household_net_incomeorhbai_benefits, which all countwinter_fuel_allowance. Since then, Scottish pensioners' winter heating payment has been counted as government spending but never reached household net income or HBAI income. PolicyEngine/impact-iran-war-living-standards works around it (BENEFITS_OUTSIDE_HOUSEHOLD_BENEFITS = ["pawhp"]).This PR adds
pawhpnext towinter_fuel_allowancein all three lists.disable_simulated_benefitsChecking how the reform treats PAWHP showed that the reform could not run at all:
Simulation.__init__never settax_benefit_system.simulation. Core applies a reform by calling itsapply()with the tax-benefit system asself, so the reform'sself.simulationraisedAttributeError. Core's ownSimulation.__init__sets the attribute, but PolicyEngine UK's__init__replaces core's. It is now set before the structural reforms are applied. (adjust_budgetsreadsself.simulationthe same way.)attendance_allowance,dla_m,dla_sc,pip_dlandpip_m(ValueError: Variable attendance_allowance_reported does not exist). policyengine-uk-data converts their reported amounts into award categories (aa_category, …;add_disability_benefit_categories_from_reported_amounts), and the model pays the category's rate, so they already follow the reported award. They are dropped from the list. A code-health test now requires every listed benefit to have a_reportedvariable, and every simulated benefit with one to be listed or excluded with a reason. Maternity Allowance is excluded because it already addsmaternity_allowance_reported.Treatment of PAWHP. There is no
pawhp_reported. The survey records one winter heating payment, FRS benefit code 62, which policyengine-uk-data loads intowinter_fuel_allowance_reportedfor every respondent, Scotland included. Hadwinter_fuel_allowancestayed set from it whilepawhpstayed simulated, Scottish households would have counted the payment twice now that both are household income. The reform now sets both from the one report, year by year. A Scottish household's report becomes itspawhpin the years PAWHP is paid (gov.social_security_scotland.pawhp.active, from the 2024 qualifying week) and itswinter_fuel_allowancebefore then. Every other household's report stayswinter_fuel_allowance. Each report is counted once, under the scheme that pays it, and the programme totals match the simulated definitions.Note: the reform fires only when its parameter is set before the data load (
Scenario(applied_before_data_load=True, ...)). Set through an ordinaryreform=dict, it is silently ignored. That applies to every parameter-gated structural reform and is left to a follow-up.Overlap with #2075. #2075 owns the generic repair of this reform: the
tax_benefit_system.simulationline, the AA/DLA/PIP removal, and claimant-or-partner scoping of ESA, JSA and Income Support. This PR carries the same two generic fixes so it can run and test its winter heating treatment on its own stack. Whichever PR lands second keeps #2075's structure, takeswinter_fuel_allowanceout of itsBENEFITS, and keeps the winter heating split here, so the one reported payment is counted once.Cost-of-Living Payments
Unchanged. The pensioner payment (£300 in 2022-23 and 2023-24, £0 from 2024) is keyed on
winter_fuel_allowance > 0, which this PR does not change. #2038 pays the Winter Fuel Payment in Scotland up to the 2023 week. Under the reported-benefits reform, Scottish reports staywinter_fuel_allowancein 2022 and 2023, when PAWHP is inactive. Evidence: a 2023 YAML case, a reform test (the pensioner payment moves with the report only in 2023), and the Enhanced FRS run (largest change incost_of_living_support_paymentin any household, 2024-30: £0).Invariants
household_benefits,household_gross_incomeandhbai_benefitsby exactly itspawhp, andhousehold_net_incomeandhbai_household_net_incomeby itspawhpless the change in its income tax. That change is zero today; the term keeps the property true once the winter fuel payment charge (ITEPA 2003 s.681I) is modelled in income tax. Switching PAWHP off changes neitherwinter_fuel_allowancenorcost_of_living_support_payment. Tested as a Hypothesis differential property over households in every country, 2023-27, at float32 precision. On the Enhanced FRS, the base-to-branch change equalspawhpfor every household in every year 2024-30. Forhousehold_benefits,hbai_benefitsand both HBAI net income measures it holds to within 1p in every household. Forhousehold_net_incomeandhousehold_gross_income, the records more than 1p off all have household income above £60k, and each is within 2 float32 ulps (at most 1.8) of the larger of its net and gross income, at most 1.6 parts in 10 million of gross income.gov_spending,gov_balance,pawhp,winter_fuel_allowanceandcost_of_living_support_paymentare unchanged in every Enhanced FRS household, 2024-30 (largest absolute change: 0).gov_spendingitem is inhousehold_benefitsexceptother_public_spending_budget_change, a contrib budget lever. Both winter heating payments appear exactly once inhousehold_benefits, the HBAI net income list,hbai_benefitsandgov_spending.winter_fuel_allowance + pawhpequals the household's reported winter heating payment (conservation). The report ispawhpexactly where the household is in Scotland and PAWHP is paid (placement).household_benefitsandhbai_household_net_incomeexceed those of the same dataset with no report by the report plus the pensioner Cost-of-Living Payment it brings (differential). Tested with Hypothesis over datasets in every region starting 2022-25, underSimulationandMicrosimulation.Tests
tests/policy/baseline/household/income/winter_heating_payments_in_income.yaml: 5 cases.main(6d89338ab),household_benefits,household_net_income,hbai_benefitsandhbai_household_net_incomemiss the PAWHP, so these three cases fail there and the two controls pass (run 2026-10-11).tests/code_health/test_household_income_lists.py: invariant 3.tests/test_pawhp_household_income_properties.py: invariant 1, plus a non-vacuity case.tests/test_disable_simulated_benefits_winter_heating.py: the reform runs underSimulationandMicrosimulation, its list matches the reported variables, and invariant 4.27f5fdb0f(no Hypothesis shrinking):pawhpdropped from each of the three lists, listed twice, the reform putting every report inwinter_fuel_allowance, double counting Scotland, splitting a year late,Simulationnot settingtax_benefit_system.simulation, andattendance_allowanceback in the reform's list.Code changes: lint, smoke imports on Python 3.11-3.14,make test) one554001fa: run 38152748149 (in progress when this was written; see the checks). Before Test Winter Fuel Payment and PAWHP receipt per person #2038 merged, the same workflow was dispatched on27f5fdb0f(run 37005793386, all jobs passed).Impact (Enhanced FRS)
One real microsimulation per package state on a private copy of
enhanced_frs_2024_25.h5(sha256e433e532b17b…), 2024-30, re-run on 2026-10-11 aftermainchanged PAWHP's couple rule (#2038's final head). Base:mainat6d89338ab. Branch:e554001fa(this PR merged with thatmain). Aggregates only. The change moves no spending (gov_spendingandgov_balanceunchanged in every household), so the whole effect is on income and poverty.Absolute poverty (HBAI line, 60% of the FYE 2025 median held constant in real terms; percentage points, people in thousands):
Relative poverty (60% of the contemporary median):
Relative poverty moves in large, irregular steps because incomes are bunched near the line. A diagnostic on the run counted 25k to 182k Scottish people (by year) with equivalised income below the base BHC line by less than the largest equivalised PAWHP gain (£8.61 to £9.84 a week). Their incomes take only 27 to 42 distinct values. A gaining household receives £239 to £269 a year on average (about £5 a week), which moves whole blocks across the line: 80k Scottish pensioners in 2026, 72k in 2027, and 52k in each of 2029 and 2030 (BHC). The BHC median does not move. On the AHC basis, the PAWHP gains raise the median by at most £0.24 a week (2025), and at most 1.0k people outside Scotland cross into relative AHC poverty in any year. The absolute measures, whose line is fixed, are the cleaner read of the effect. Scottish pensioner AHC poverty falls 1.17 points (12.1k people) in 2025, the first year the model pays PAWHP to everyone of pensionable age in Scotland (
gov.social_security_scotland.pawhp.eligibility.require_benefitsis false from 2025).Scripts, logs and diagnostics:
dataset_impact.py,compare_impact.py,diagnose.pyanddiagnose_gross_ulp.py(kept privately with the run; the per-record arrays are not published).Axiom
axiom: n/a: aggregation only (PAWHP's place in household and HBAI income lists) plus a contrib reform; PAWHP itself is TheAxiomFoundation/rulespec-uk#420 queued (from #2038)
Follow-ups
pawhpon top ofhousehold_benefitsunconditionally. Once its policyengine bundle reaches a release with this PR, the PAWHP change would be counted twice there. A follow-up makes the adjustment conditional.gov_spendingomitsscottish_child_payment,healthy_start_vouchersandtwo_child_limit_payment, whichhousehold_benefitscounts.hbai_benefitsomitsscottish_child_paymentandcouncil_tax_benefit. A follow-up will verify these and reconcile them.adjust_budgets, which this PR'stax_benefit_system.simulationfix lets run for the first time under the currentSimulation.🤖 Generated with Claude Code