Skip to content

Calibrate GB universal credit to one OBR total; reach the UC payment top band - #530

Draft
MaxGhenis wants to merge 2 commits into
mainfrom
fix/obr-uc-welfare-cap-targets
Draft

MaxGhenis wants to merge 2 commits into
mainfrom
fix/obr-uc-welfare-cap-targets

Conversation

@MaxGhenis

Copy link
Copy Markdown
Contributor

Summary

Two calibration-target fixes, both data-release changes for the d833 batch. Draft; do not merge outside the batch.

  1. OBR universal credit. obr/universal_credit_outside_cap asked for £12.9bn of nearly all UC: the model estimate was £72bn, +460% in every recent build. obr/universal_credit_in_cap compared £66.4bn with all UK UC (+12%). They are replaced by one target, obr/universal_credit. It is the sum of EFO table 4.9's two UC rows (£79.29bn in 2025-26), counted over Great Britain only.
  2. DWP UC payment distribution. The four dwp/uc_payment_dist/*_nan_to_nan targets (1.4k to 83k households) had a column of zeros. They are now reachable as *_30_000_to_inf.

1. Universal credit inside and outside the welfare cap

What OBR's split is. The welfare cap is the Charter for Budget Responsibility's limit on welfare spending, not the household benefit cap. It excludes the State Pension and the payments most sensitive to the economic cycle: JSA, the Housing Benefit paid with it, and their UC equivalent (NAO, Managing the welfare cap, 2016). The sources agree on what that UC equivalent is:

  • DWP's benefit expenditure and caseload tables (Spring Forecast 2026) give UC outside the cap as £12,875.55m in 2025-26, the figure in table 4.9 (£12.876bn), with a caseload of 1,323k. Their Notes ("Unemployment benefits table") say this UC "is the total expenditure outside the welfare cap directed to those in the Intensive Work Search group, the closest UC equivalent to JSA spend".
  • OBR EFO March 2026, paragraph 4.24, footnote 20: "The unemployed caseload here refers to the universal credit caseload in the 'intensive work search' labour market regime."
  • DWP's UC statistics methodology defines Stat-Xplore's "Searching for work" regime as Intensive Work Search. That is the all-work-related-requirements group (Welfare Reform Act 2012 s.22) with earnings below the Administrative Earnings Threshold, plus gainfully self-employed claimants in a start-up period. The threshold is set in UC Regulations 2013 reg 99(6) (SI 2024/536): monthly earnings from employment of 18 hours a week at the National Living Wage for one person, and 29 combined hours for a couple, from 13 May 2024.

The old column was UC for households whose benefit_cap_reduction is zero, which is a different concept.

Why one total rather than a corrected split. policyengine-uk 2.93.0, which this repo pins, has no UC conditionality regime. Its LCW/LCWRA flag (uc_limited_capability_for_WRA) is reported DLA/PIP receipt. I built proxies of the Intensive Work Search group from the legal tests and FRS employment status, and scored them on seeded builds against DWP's GB figures (£12.876bn, 1,323k):

  • Legal tests: below State Pension age, no LCW, not a carer, not the responsible carer of a child under 3, employment income below the AET (individual and couple), not under the minimum income floor.
  • Health stand-in: FRS self-reported long- or short-term sickness is used in place of LCW. Health takes precedence within the benefit unit, as DWP counts UC "directed at those with health conditions" as incapacity spending.
Proxy (2025-26, GB benefit units on UC) Build Outside-cap UC vs DWP Caseload vs DWP
Legal tests only (LCW = DLA/PIP) main £25.40bn +97% 2,479k +87%
Legal tests + self-reported health main £12.25bn −5% 1,309k −1%
Same #526 £16.30bn +27% 1,665k +26%
ILO-unemployed only main £3.7bn −71% 365k −72%

The close fit on main is partly luck. Main maps FRS EMPSTATI 11 ("other inactive") to LONG_TERM_DISABLED; #526 corrects that. With the correction, about 360k "other inactive" UC benefit units leave the health group and the proxy is 27% over. Other reasonable choices, such as how to treat students or couples where only one partner is in the group, move it between −26% and +42%.

Calibrating to a split this fragile would shift weight between kinds of UC household in a way no output reveals. The total, by contrast, is exactly OBR's figure. A chip tracks restoring the split once policyengine-uk models the work-related groups (#2081's uc_work_related_group_apart_from_earnings) and this repo supplies their inputs (#525, #526, #527).

Great Britain only. Both UC rows sit under table 4.9's "DWP social security", which DWP's tables label "DWP Social Security (GB)". Northern Ireland's UC is in the separate "NI social security" rows. The target therefore counts GB households only. In the main build that excludes £1.65bn of the model's £74.4bn UC in 2025-26. This uses #490's countries field and restrict_to_countries, copied byte for byte, so the two PRs merge cleanly in either order. Other DWP targets have the same GB-versus-UK mismatch; a chip covers them.

Parsing. The two rows are now located by section: one "Universal credit" row either side of "Welfare spending outside the welfare cap". The code no longer takes the first and second matches. If either row is missing, or a section has two, no UC target is produced, rather than a partial total.

2. UC payment distribution top band

The Stat-Xplore extract (storage/uc_national_payment_dist.xlsx, May 2025) ends with an open band, "£2500.01 or over". parse_band only understood "X to Y", so that band got NaN bounds and uc >= nan matched nothing.

  • Open top band. "or over" now parses to (£30,000, ∞) a year, and an unrecognised band raises.
  • No gaps. Bands are now (lower, upper], with lower set to the previous band's top. Before, uc >= 1,200.12 & uc < 2,400 left 12p gaps and dropped awards of exactly £100.00, £200.00, … a month.
  • No double counting. The parser rejects overlapping bands. The extract also lists a suppressed summary band ("£1500.01 or over") that would double count if filled in.

Target names are unchanged apart from the four top bands. One of the four, couples without children (1.4k households), stays at zero: no enhanced-FRS record of that family type has UC above £30,000 a year in 2025, so no weighting can reach it.

Invariants and tests

  • Conservation (UC total). The UC column sums UC over benefit units in GB households, each once; Northern Ireland households are zero; the column is non-negative. Hypothesis property test.
  • Conservation (payment bands). Summed over the payment bands, each household's column counts its benefit units with a positive award, and never one without. This holds for any awards, including awards exactly on band edges and one ulp either side. Hypothesis property test.
  • Band partition. Within each family type, the bands start at 0, each lower bound equals the previous upper bound, and the top is ∞. The band counts add up to the extract's Total less "No payment" (within 10 households, since Stat-Xplore perturbs cells for disclosure control).
  • Parsing. The UC target equals row 18 plus row 43 of the committed workbook in every year from 2024 to 2030. Moved rows still parse. Missing or ambiguous rows give no target.
  • Mutation check. Restoring the old >=/< band test fails the property test.

Impact (seeded production builds)

Seeded production build of this head (seed 0) against origin/main b45c373 (seed 0) is running; the impact goes here when it finishes.

Batch notes

🤖 Generated with Claude Code

MaxGhenis and others added 2 commits October 2, 2026 22:19
… band

OBR EFO table 4.9 splits UC between spending inside the welfare cap and
outside it. The outside row is DWP's UC equivalent of JSA (the Intensive
Work Search group), not UC for households the benefit cap leaves alone, so
computing it as UC where benefit_cap_reduction is zero asked for £12.9bn of
nearly all UC. policyengine-uk cannot identify the Intensive Work Search
group, so the two rows become one target, obr/universal_credit, restricted
to Great Britain (the rows sit under DWP social security; Northern Ireland
has its own). The GB restriction uses #490's countries field, copied
verbatim.

The DWP UC payment distribution's open top band ("£2500.01 or over")
parsed to NaN bounds, so its four targets had a zero column. Parse it as
(30,000, inf), make bands (lower, upper] so they meet without gaps, and
reject overlapping summary bands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Making the bands meet without gaps ((lower, upper]) moved penny-a-month
awards into the bottom band: policyengine-uk leaves 1p a month payable
after deductions (SI 2013/380 Sch 6), and 44 records (136k benefit units
in a seeded main build) sit there. The old lower bound of £0.12 a year
leaves them out, and the seeded build of the gapless version then
reweighted against them. Whether they belong in Stat-Xplore's lowest
award band turns on whether its award amount is before or after
deductions, which is outside this change. The bounded bands now parse and
compare exactly as before; only "£2500.01 or over" changes, to
[30,000.12, inf).

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

This branch has not been deployed

No deployments
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.

1 participant