Skip to content

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

Closed

Description

@juaristi22

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_up calls assign_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.py redraws 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 in frs_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 both frs_take_up.py and spi_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.py already 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_uc from the uk_take_up_signal gate 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.py already 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:
    1. fix 2 (UC take-up);
    2. fix 3 (pensioner receipt);
    3. fix 1 (HMRC reconciliation);
    4. 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

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

  1. 13 remaining items

  2. juaristi22 commented on Oct 23, 2026

    @juaristi22
    CollaboratorAuthor

    Pensioner poverty after #1344, recorded here as Vahid asked (item 29).

    On the pre-Budget arm at e399d21ef against #1338's certified run at 829c1bc26 (both on policyengine-uk 2.147.2; dashboard statistics), pensioners in 2024:

    Measure Control → #1344 HBAI FYE25
    Relative BHC 13.6% → 12.7% 15.9%
    Relative AHC 13.0% → 12.2% 13.9%
    Absolute BHC 11.4% → 11.8% —
    Absolute AHC 11.4% → 11.6% —

    2025 moves the same way (absolute BHC 11.0% → 11.4%, AHC 11.3% → 11.5%).

    🤖 Generated with Claude Code

  3. PavelMakarchuk commented on Oct 23, 2026

    @PavelMakarchuk
    Contributor

    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:

    Decile 1 2 3 4 5 6 7 8 9 10
    uk-data 1.58.1 28% 21% 22% 25% 20% 22% 12% 8% 6% 3%
    Microcosm 19 Oct 19% 17% 20% 24% 19% 17% 22% 24% 17% 11%

    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

  4. added a commit that references this issue on Oct 23, 2026
  5. juaristi22 commented on Oct 23, 2026

    @juaristi22
    CollaboratorAuthor

    Closing: #1344 and #1347 are merged. What shipped, and where each open piece went:

    Shipped

    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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions