Repository navigation
UK national calibration moves weight away from low-income households: reconcile the HMRC low-band rows, model UC take-up by award size, impute pensioner benefit receipt (pre-Budget) #1334
Description
Summary
The UK living standards dashboard (PolicyEngine/uk-living-standards-outlook) runs policyengine-uk 2.130.1 on the 19 Oct national file. Against HBAI FYE2025 it shows:
- a median equivalised income about 6% too high;
- absolute poverty about 3–6pp too low, depending on group and measure;
- a Gini of 0.302 against 0.327;
- Northern Ireland as the highest-poverty region, where official figures put it among the lowest.
For the median and poverty rates, the engine and the FRS rows are not the cause. On the same file's FRS rows at FRS 2024-25 grossing weights, the engine reproduces HBAI's median and poverty rates:
- the median matches HBAI's;
- absolute poverty is 16.0% against 15.9% before housing costs (BHC), and 19.5% against 19.6% after housing costs (AHC);
- every age group is within about 1.2pp.
It does not reproduce HBAI's Gini (0.293 at those weights), probably because HBAI adjusts very high incomes using the SPI and the FRS rows do not.
The national calibration solve causes the median, poverty and Northern Ireland gaps; its net effect on the Gini is about +0.9 points. The same weights drive every Budget poverty and distributional output, so we are starting work on the causes for the 22 Oct build rather than patching the solver.
What the calibration does (measured, 2024-25, FRS design weights to the released weights)
- Median equivalised income rises about 6%, and the 10th percentile rises more. Absolute BHC poverty falls from 16.0% to 12.2%.
- People in the bottom FRS-design income decile lose about 24% of their weight; those in the second decile lose 16%.
- People with employment income rise from 27.7m to 29.9m. Working-age adults with no earnings fall from 11.0m to 9.6m.
- Pensioner absolute BHC poverty falls from 15.9% to 10.7%. Between prior and final weights, the weight on poor pensioners who receive none of Pension Credit, Housing Benefit, AA, DLA or PIP falls to about 0.64 of its prior level.
- Northern Ireland's relative BHC poverty goes from 13% to 23%. London's relative AHC poverty goes from 27% to 19%.
- The effective sample roughly halves.
The pre-Budget PR (#1329), which carries the calibration-period fix for #1324, leaves these gaps in place. These comparisons set weights solved to calendar-2025 targets against FRS 2024-25 design weights, so part of each move may come from the target year. That share is not yet measured.
Why: three target families that the rows cannot meet at design weights
The solve has no anchor to its prior and only an upper bound on weights (10× prior). Where the rows and a target disagree, the solve closes the gap by reweighting, and the cheapest reweighting moves weight away from low-income households. In replica re-solves:
- dropping the HMRC targets together with the UC targets removes all of the median lift;
- the HMRC rows below £30k alone remove about half of it.
1. HMRC income-band rows below £30k (counts, amounts and tax)
- The rows: 159 rows whose band starts below £30k, in three families:
- SPI Tables 3.6 and 3.7 (42 rows): employment, self-employment, private and State Pension, property, dividend and savings income, counts and amounts by total-income band;
- ITL Table 2.5 (9 rows): taxpayers, total income and tax by band;
- SPI Table 3.11 (108 rows): taxpayers, income and tax by band in 12 regions and countries.
- The shortfall: at FRS design weights, employment-income counts are 0.57 of target for £12,570–15,000 and 0.59 for £15,000–20,000. ITL taxpayer counts in those bands are 0.72 and 0.80.
- Why it may be partly a concept gap (a first replica of route 1b puts it at about a tenth to a third of the median lift):
- HMRC's counts are annual: they include anyone with taxable income during the year, part-year workers among them.
- The engine's incomes, like HBAI's, are current, annualised incomes.
- FRS 2024-25 has about 2.03m adults who were out of work at interview but worked in the previous 12 months.
- Calibration adds about 2.2m people with employment income. That is also about the gap between the FRS and HMRC's RTI count of payrolled employees. So part-year work and FRS under-coverage of low earners can't yet be told apart.
- More SPI copies would not fill these bands, because the SPI support channel's copies follow their FRS twin's earning status.
2. Universal Credit caseloads
- At design weights, the simulated caseload is above DWP's for:
- single people without children (1.15×);
- couples (1.5–1.9×);
- single people's three lowest award bands, under £300 a month (1.2–2.6×).
- Lone parents are below DWP's count (0.67×).
- The cause is how take-up is drawn.
frs_take_up.derive_frs_take_upcallsassign_binary_with_anchored_residual:- reporters always claim;
- the rest of the contract's count (one take-up rate times the age-eligible units) is filled at a single rate;
- that residual is spread uniformly over non-reporting age-eligible units, whatever their award.
spi_benefit_coherence.pyredraws the SPI-channel units the same way.- Real non-take-up is concentrated in small awards. The solve meets DWP's caseloads by down-weighting low-income families.
3. Pensioner benefit caseloads
- Attendance Allowance, Pension Credit and pension-age Housing Benefit caseloads are 10–30% short of DWP's at FRS design weights, and about 20–33% short at the solve's prior weights.
- The FRS under-reports receipt. DWP's AA and Pension Credit counts also include care-home residents, whom the FRS does not sample.
- The solve up-weights reporters and cuts poor non-recipients. In replica re-solves, the benefit targets as a whole (UC, disability and spending rows as well as these caseloads) account for about 2.9pp of the 4.5pp fall in pensioner absolute BHC poverty between a demographics-only solve and the full solve; the HMRC and other targets account for the rest.
- On FRS rows, AA comes only from reported receipt (read in
frs_spine.py; the rate category is set infrs_disability.py). SPI copies carry a forest draw trained on those reports. - Pension Credit has a take-up stage by component band (
pension_credit_take_up.py) that runs on the whole frame after the SPI income chain. Even so, the caseload is short before the solve.
Root-cause fixes
Each fix makes the rows and the targets measure the same thing before the solve, so the solve has less reason to move weight away from low-income households. How much each fix closes is measured before it rides. We rule out anchors, weight floors and hold-outs as the fix: they trade target fit for distribution without removing the mismatch.
Fix 1: reconcile the HMRC low-band rows with the engine's income concept
One route is chosen on Wednesday morning, after measurement:
- 1a. A calibration-only annual income measure (preferred).
- In the spine, build a per-person annual taxable income for calibration. Use the FRS 12-month work history: whether and how long people worked in the last 12 months. The pay of a job that has ended is not recorded, so it is imputed.
- Bind the HMRC band counts and amounts to band membership on that measure.
- Current incomes, which the engine taxes and HBAI measures, do not change.
- 1b. Convert the targets. Scale each HMRC low-band count and amount to a point-in-time equivalent, with per-band factors estimated from the same FRS data. A receipt records the factors.
- 1c. Point-in-time employment counts. Replace the low-band SPI employment counts with HMRC PAYE RTI point-in-time payrolled employees by pay band, if the published series supports it and can enter the Chronicle feed in time.
This fix also sizes how much of the low-band shortfall is concept and how much is FRS under-coverage. Only the concept part should be reconciled.
Acceptance:
- Shortfall closed: at design weights, report how much of each low band's shortfall the reconciled basis closes. Today employment counts are 0.57–0.59 of target and ITL taxpayer counts 0.72–0.80.
- No HMRC row gets worse: after the solve, no HMRC row that is within 10% on the baseline arm moves outside it, and the low-band employment rows now outside 10% move closer.
- Tax base unchanged: income tax and NICs totals change by no more than 0.5%.
- Bottom of the distribution: the bottom two FRS-design deciles keep more of their design mass than on the solve without fix 1.
Fix 2: Universal Credit take-up by award size and family type
- Replace the single-rate residual draw for
would_claim_uc, in bothfrs_take_up.pyandspi_benefit_coherence.py, with take-up probabilities by entitlement band and family type. Pool the cells so each rate rests on enough FRS households. - Compute entitlement with one temporary engine materialization after the SPI chain, as
pension_credit_take_up.pyalready does. - Set the rates so that the design-weight caseload by payment band and family type moves toward DWP Stat-Xplore. These targets are already in the registry.
- Reporters always claim. Northern Ireland uses the GB rates.
- Move
would_claim_ucfrom theuk_take_up_signalgate to a stage gate, as Pension Credit did.
Acceptance:
- Caseload by family type: at design weights, the over-counts for single people without children (1.15×) and for couples (1.5–1.9×) fall: for single people, to within ±10% of DWP; for couples, as far as reported receipt allows, since couples' reporters alone already exceed DWP's payment-band counts at design weights. No payment band moves further from DWP.
- UC spending: checked after the solve. At design weights it is 8.5% below OBR before this fix.
- Low-income families: report the change, from prior to final weights, in the person mass of UC-entitled families in the bottom two FRS-design deciles, against the baseline arm.
Fix 3: impute pensioner benefit receipt
- Attendance Allowance. A new stage imputes AA to non-reporting pension-age people with FRS care or disability needs, by rate (higher and lower). It aims at DWP's AA caseload by age band at design weights. Say whether it runs before the SPI chain, so that the copies' draws learn from it, or on both channels.
- Pension Credit.
pension_credit_take_up.pyalready runs on the SPI copies after the SPI income chain. Measure how much Pension Credit they carry, and why. Also check the State-Pension-only boundary in the SPI income draw (UK SPI channel after #840: residuals, post-merge measurements and stale pointers #1288; see UK pensions after #1084: open rulings, residual gaps and the engine pieces #1069). - Pension-age Housing Benefit. Check whether receipt is reported only. If it is, impute it to entitled non-reporters at DWP take-up rates.
- PIP and DLA for pensioners. The same check.
Acceptance:
- Caseloads: at design weights, the AA, Pension Credit and pension-age HB caseloads are within ±10% of DWP's, net of an estimate of care-home recipients.
- Poor non-recipients: from prior to final weights, the mass of pensioners who were poor non-recipients before imputation moves by less than 10%. Today it falls to ×0.64.
- Pensioner poverty: report pensioner absolute BHC poverty at design and final weights, both on the post-imputation rows. Fix 3 bears on part of the benefit targets' share of the fall (about 2.9pp for all benefit targets together, UC and spending rows included). How much it recovers is measured, not assumed.
Delivery and measurement plan
- One PR, rebased onto the pre-Budget PR (UK pre-Budget data: measure stored values at their period, draw Carer's Allowance claims, and the #1278 items (#1324, #1319, #1278) #1329). Ordered commits:
- fix 2 (UC take-up);
- fix 3 (pensioner receipt);
- fix 1 (HMRC reconciliation);
- one pin pass.
- Builds: one spine rebuild that carries fixes 2 and 3 (and, under route 1a, the calibration-only income column). Then two national solves on that spine: one from the PR head, and one from the commit before fix 1.
- Separating the effects:
- The stage receipts give the design-weight fit before and after fixes 2 and 3 on the same rows.
- The two national solves isolate fix 1.
- Fixed-weight decompositions split the remaining moves between rows and weights.
- The spine rebuild also retrains the SPI housing shell and income chain on the changed FRS rows, which moves AHC and consumption results from build to build. Comparisons against the baseline arm report that refit separately, on lineage-matched rows.
Measure everything with one script, against the current combined pre-Budget arm:
- Before the solve: design-weight fit of each targeted family.
- After the solve:
- the seven terminal gates (target_fit, weight_ess, weight_ratio, zero_weight_strata, aggregate_admin, calibration_reference_coverage, cgt_projection_entrants) and the take-up stage gates;
- the loss, and the share of targets within 10%.
- Weight movement:
- D1 and D2 mass against FRS design;
- effective sample size and the top-1% weight share;
- poor non-recipient pensioners;
- UC families by award band.
- Distribution:
- median, P10, P90, Gini and 90:10;
- relative and absolute poverty, BHC and AHC, for all people, children, working-age adults and pensioners;
- Northern Ireland and London.
- Budget costing totals:
- income tax, NICs, UC, Pension Credit, State Pension, AA and PIP;
- taxpayer counts from £12,570 to £50,270;
- reform proxies: personal allowance, basic rate, UC standard allowance and the two-child limit.
We also add these distribution checks to the calibration diagnostics as a report-only gate: D1/D2 mass, P10/P50, and poverty at design against final weights.
Timeline (48 hours; the build now starts on Thursday evening)
- Wed 21 Oct, by 09:00 UTC: agree this plan and freeze the measurement baseline (the current combined pre-Budget arm).
- Wed 21 Oct, during the day: implement fixes 2 and 3 (spine stages) and fix 1 (measure or targets), with unit tests. Each fix is developed in its own worktree, then the three are assembled as ordered commits.
- Wed evening: pin pass, then one spine rebuild and the two national solves, run one at a time on the engine slot.
- Thu 22 Oct, morning to afternoon: remeasure, review the PR and merge to main.
- Thu 22 Oct, evening: national + dense build.
- Fallback:
- A fix rides if every gate passes, its targeted family's design-weight fit improves, income tax and NICs move by no more than 0.5%, and no target newly falls outside 10%. The distribution measures are reported, not pass/fail.
- Fix 1 can drop by using the solve without it.
- Fixes 2 and 3 share one spine. Dropping either means another spine rebuild and solve before the evening build; if there is no time, both drop together.
- The affected outputs keep a caveat.
Not in scope here
- Northern Ireland identification. NI sits outside the GB-only benefit and council-tax targets. Fixes 2 and 3 may help; we remeasure NI and London on each arm.
- Two weight sets (one for costings, one for distribution): after the Budget.
- policyengine-uk items, to raise or track there:
- NI rate rebate;
- how LCWRA is assigned (UC LCWRA element: joint claimants who both have LCWRA get two elements; reg. 27(4) allows one policyengine-uk#2429 covers joint claims only);
- the free school meals expansion;
- the 2027-30 UC standard allowance uplift, fixed in 2.134.6 (Apply the Universal Credit Act 2025 standard allowance uplifts to 2029-30 policyengine-uk#2242). The scoring pin predates it.
References
#968 (the earlier poverty-gap diagnosis), #1329 (the pre-Budget PR), #1278, #1324, #1069, #1288, #1095, and the dashboard review, PolicyEngine/uk-living-standards-outlook#1.
🤖 Generated with Claude Code
Activity
Draw Universal Credit take-up by award band and family type (#1334 fi…
Bind every UC payment band with support; drop only unsupported bands (#…
Read a pinned tab's selected columns in one pass (#1334)
Record each adult's year of income beside the current income (#1334)
Measure the HMRC income rows over the tax year as well (#1334)
Bind the national HMRC income rows to each person's income over the t…
Let a UC take-up pool draw no claimant when none is nearest DWP's cou…
Keep legacy-benefit reporters off the UC take-up draw, and receipt wo…
Count the 48 UK spine stages and re-pin the gate battery without fix 3 (
Give the H2 spine fixture the annual income stage's FRS columns (#1334)
Regenerate the UK coverage manifest and spine fixture for #1334 witho…
Draw Universal Credit take-up by award band and family type (#1334 fi…
Read a pinned tab's selected columns in one pass (#1334)
Record each adult's year of income beside the current income (#1334)
Measure the HMRC income rows over the tax year as well (#1334)
13 remaining items
Let a UC take-up pool draw no claimant when none is nearest DWP's cou…
Keep legacy-benefit reporters off the UC take-up draw, and receipt wo…
Count the 49 UK spine stages in the H2 fixture tool (#1334)
Give the H2 spine fixture the annual income stage's FRS columns (#1334)
Count the stages from main's 47 in the #1334 changelog fragments
Re-pin the gate battery on main after #1338 (#1334)
Merge pull request #1344 from PolicyEngine/uk-annual-income
Compute the UK local metrics from their declarations (#1334)
Bind the local HMRC income rows to each person's year of income (#1334)
juaristi22 commentedon Oct 23, 2026
Pensioner poverty after #1344, recorded here as Vahid asked (item 29).
On the pre-Budget arm at
e399d21efagainst #1338's certified run at829c1bc26(both on policyengine-uk 2.147.2; dashboard statistics), pensioners in 2024:2025 moves the same way (absolute BHC 11.0% → 11.4%, AHC 11.3% → 11.5%).
🤖 Generated with Claude Code
Say what the local metrics now read, and guard their filters (#1334)
PavelMakarchuk commentedon Oct 23, 2026
A reform-level data point for this issue, from the production API after the 6.10.0 switch (served release
microcosm-uk-2024-25-national-20261019T083323Z-6cba5d71, policyengine-uk 2.132.6).Reform: 10 UC rates frozen at 2026-27 levels from 2027. Share of people in each income decile who lose:
Total UC is almost the same (£85.1bn vs £82.2bn), so the caseload target is met, but receipt has moved up the distribution: the average household loss is now largest in decile 8 (−£70, was −£18) and decile 1 loses −£17 (was −£34). The local-area breakdown on the dense file still looks geographically sensible (largest losses in Newham and Bradford East, smallest in Hart and Tatton), and its average loss matches the national file (£34 vs £33 per household), so the shift shows up in the national file's income ranking, which fits the down-weighting described here. It would be useful to rerun this reform on the release that includes #1344.
@juaristi22 a question on timing: the API still serves the 19 October national release, which predates #1344. When do you expect a release with #1344 to be certified and reach the API (via a .py bump in the sim API and policyengine-api)? Until then, UK distributional results (deciles, and likely poverty) from the live API carry this shift, so we'll hold off on publishing them. Happy to rerun this reform as a check as soon as it's out.
🤖 Generated with Claude Code
Merge pull request #1347 from PolicyEngine/uk-annual-income-local
juaristi22 commentedon Oct 23, 2026
Closing: #1344 and #1347 are merged. What shipped, and where each open piece went:
Shipped
uc_take_upspine stage.hmrcrows follow in UK #1334: compute the local metrics from their declarations, and measure the local HMRC rows over each person's year #1347.Moved
Still to run, with no issue work: the dashboard rerun (PolicyEngine/uk-living-standards-outlook#1) waits for the first certified national release from main.
🤖 Generated with Claude Code