Repository navigation
Conversation
…9-30 standard_allowance_uplift held the s. 1 uplifts (2.3%, 3.1%, 4.0%, 4.8%) but nothing read it after the 2026-27 amounts, which include the first uplift, were written into amount.yaml, so 2027-28 to 2029-30 grew by CPI alone. The standard allowance is now uprated by its own index, the benefit uprating CPI index (floored at 0% in 2026-27 to 2029-30, s. 1(3)) times one plus the year's uplift, so it grows by CPI times the change in uplift. A legislated amount for those years is rescaled if the uplift in force differs from the statutory one, so a reform to the uplift or to rebalancing.active reaches every year. Fixes #2239 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 10, 2026
…ation Review round 1 on #2242: - Treat the uplift as nil before its parameter starts, so switching rebalancing on from 2000 no longer crashes. - Rescale only amounts that still hold their amount.yaml value; an amount a reform sets is used as given. - Build the index from gov.benefit_uprating_cpi as uprating extends it, so a reform to that index is followed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 2 on #2242: - Sample gov.benefit_uprating_cpi on 30 April of each year, so a fiscal-year reform to it reaches that year rather than the next. - Rescale only amount entries loaded from amount.yaml (they carry its file path), each at most once, so a reform that sets the legislated amount itself is used as given. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 10, 2026
Review round 3 on #2242: after a bounded amount reform, Parameter.update writes an entry restoring the legislated amount, with no file path, and the builder took it for a reform amount, so it kept the statutory uplift with rebalancing off. apply_parameter_changes now records the periods each change set; the builder leaves entries in those periods as given and rescales every other entry by the uplift of the amount.yaml entry it carries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ance-uplift-2239 # Conflicts: # docs/book/policy/uc-rebalancing.md # policyengine_uk/tax_benefit_system.py
…he index Review round 4 on #2242 found another bounded-override case in the rescale of legislated amounts. Rather than track which entries a reform wrote, drop the rescale and the simulation.py hook it needed: the legislated 2026-27 amounts stay as legislated, and the index uses the uplift they include for legislated years (read from amount.yaml) and the uplift in force after. Switching rebalancing off or changing a later uplift moves every year after the legislated ones; changing a legislated year needs its amount set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 11, 2026
Collaborator
Author
|
PE-UK main fix landed (UK hub, 2026-10-11 21:42Z): #2349 merged as |
The published-rates test skipped the four UC standard allowances because the model did not follow Universal Credit Act 2025 s. 1. It does now, through the allowance's own uprating index, so they are checked like any other series; only the LCWRA element (s. 3) stays an exception. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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 #2239.
What was wrong
rebalancing/standard_allowance_uplift.yamlheld the Universal Credit Act 2025 uplifts (2.3%, 3.1%, 4.0%, 4.8%), but no formula read it. #1691 wrote the 2026-27 amounts, which include the 2.3% uplift, intostandard_allowance/amount.yamland removed the formula step that applied the uplift. From 2027-28 the allowance grew by CPI alone. The reproducer: 2027 was 2.3% above 2026, CPI only.The law
Universal Credit Act 2025 s. 1(2) sets the minimum standard allowance for 2026-27 to 2029-30 in three steps:
Each uplift is measured against the CPI-only path from 2025-26, not compounded, because Step 1 takes the previous year's amount before its Step 3. So from one year to the next the allowance grows by CPI × (1 + this year's uplift) / (1 + last year's uplift).
Check: 2026-27 single 25+ is £400.14 × 1.038 × 1.023, rounded at each step, which gives the legislated £424.90.
Changes
rebalancing/create_standard_allowance_uprating.py(new) runs inprocess_parametersbefore uprating. It buildsgov.dwp.universal_credit.standard_allowance.upratingfrom two parts:gov.benefit_uprating_cpiread on 30 April of each year (the fiscal-year sampling date), as uprating extends it and including any reform to it, floored at 0% growth in 2026-27 to 2029-30 (s. 1(3)).amount.yaml(2026-27 so far, read from the file), the uplift is the one those amounts include, from the s. 1(4) table. For later years it is the uplift in force: nil withrebalancing.activefalse, and the reformed value under an uplift reform.amount.yamlis uprated by that index instead ofgov.benefit_uprating_cpi. Years after the legislated ones therefore get CPI times the change in uplift, and CPI alone after 2029-30.gov.benefit_uprating_cpi, so the difference from a CPI-only path is exactly the uplift.amountis used as given, as the replay's CPI-only counterfactual is.standard_allowance_uplift.yamlis dated from 6 April of each tax year and cites s. 1(4).uc-rebalancing.mdexplains the mechanism. Its uplift-reform example keys fiscal years ("2027"): single-day keys ("2026-01-01") never reached the 30 April sampling date.uc_reform.py: corrected a stale comment.Design note (review rounds 1-4). An earlier version rescaled the legislated 2026-27 amounts to the uplift in force, so that switching rebalancing off reached 2026-27 too. Telling legislated entries from reform entries, and from the entries
Parameter.updatewrites to restore a value after a bounded reform, kept producing edge cases. That version also needed a hook insimulation.py, a file the dated-Budget-reform work owns (session "Make dated Budget reforms correct on every route"). This version keeps the legislated amounts fixed and puts the uplift only in the index, which removes that class of case.One limitation remains, and it predates this PR:
Parameter.updaterestores a bounded override's prior value at the end of its period as an explicit entry, as it does for every uprated parameter. Uprating then starts from the latest explicit entry. So any year after the last legislated one, before or after a bounded override ofamount, can hold a stale value instead of the projected one. For example,{"2026": 500}gives £424.90 in 2027 instead of £438.07, and{"2028": 500}gives £424.90 in 2027 too. The dated-Budget-reform work (W1) is fixing this on every route.Tests
test_uc_standard_allowance_uplift.py:amountis used as given, including when combined withactivefalse, an uplift reform, or a value equal to the legislated one.active: True(from 2000) matches the baseline.gov.benefit_uprating_cpireform reaches the allowance in that year.amountreform before the legislated year leaves the later path as it would be without it.Mutation check. On
mainthe example, the differential and the rebalancing-off tests fail. The scalar-activation and benefit-index regressions fail on this PR's first head.Existing tests. These pass:
test_uc_rebalancing.py(existing-claimant protection, as now on main);test_no_economic_assumptions.py;parameter_changes.Under
no_economic_assumptions, the allowance grows only by the uplift ratio to 2029-30 and is then flat.National impact
Data:
enhanced_frs_2024_25.h5@1.58.0, this branch againstmainat 6d89338 (this branch merged with it), full microsimulation (£bn, branch minus main).universal_credituc_standard_allowance(all benefit units)uc_LCWRA_elementgov_balanceUC rises by much less than
uc_standard_allowance, for three reasons:uc_standard_allowanceis computed for every benefit unit, not only those paid UC.universal_credit_july_2025_reform(as on main since this branch was opened) sets the protected amount for 2027-28 to 2029-30 at the higher of the previous year's amount and that floor. A higher allowance lowers the floor, so the protected amount rises less: the −£0.19bn to −£0.58bn. The scenario sets it only to 2029-30, so in 2030 the LCWRA element is the same in both runs.Who gains and who loses:
uc_deductionsisuc_deduction_rate × uc_standard_allowance, so their debt deductions grow with the allowance.Fiscal-event replay: Spring Statement 2025 UC standard allowance increase
Real microsimulation runs of the replay construction on the proposed certified data (
enhanced_frs_2024_25.h5@1.58.0), this branch againstmain6d89338. The construction is copied from policyengine-scorecardpipeline/build_uk_event_registry.pyon main, snapshotted 2026-10-11 (event_replay.py). Gain to the Exchequer, £bn.Reversal: the 2025-26 monthly amounts × 1.038 (September 2025 CPI) × benefit CPI ratio from April 2026, for 2026-2029.
universal_creditsavingOn main the reform's effect stayed flat because the certified world lacked the 2027-29 uplifts. With them it grows to £1.56bn in 2029-30, against the OBR's £1.55bn cited in #2239. Input support: the standard allowance needs no new input, so the national exposure is not inert.
Overlaps
benefit-uprating-september-cpi(session 7d5c5e19, not live; notes in~/reviews/benefit-uprating-sep-cpi-2026-09-29/STATUS.md) also applies the uplift, through its ownstandard_allowance/create_uprating_index.pyon a September CPI index. Whoever revives it should rebase on this PR and keep one index builder, or the uplift is applied twice.amountto a CPI-only path. With the uplift now in the certified world's amounts, that reversal widens through 2029-30, as the issue expects.axiom: rulespec-uk#367 queued (UC Act 2025 s. 1, labelled
pe-parity). The 2027-28 to 2029-30 companion cases from this PR are added there.🤖 Generated with Claude Code
Reproducer:
policyengine_uk/tests/test_dwp_published_rates.py::test_projection_continues_from_last_published_rate,policyengine_uk/tests/test_uc_standard_allowance_uplift.py::test_single_claimant_aged_30_matches_the_act,policyengine_uk/tests/test_uc_standard_allowance_uplift.py::test_amounts_match_the_act_step_by_step,policyengine_uk/tests/test_uc_standard_allowance_uplift.py::test_growth_is_cpi_times_the_change_in_uplift,policyengine_uk/tests/test_uc_standard_allowance_uplift.py::test_switching_rebalancing_off_removes_the_uplift_from_that_year,policyengine_uk/tests/test_uc_standard_allowance_uplift.py::test_rebalancing_off_throughout_follows_cpi_after_the_legislated_year