Skip to content

obr/esa ("Incapacity benefits") leaves out incapacity benefit, SDA and the incapacity part of income support #582

Open

Description

@MaxGhenis

Corrected 2026-10-14: the premise below was wrong; see the correction comment. The remaining gap is incapacity benefit, SDA and the incapacity part of income support.

What's wrong

targets/sources/obr.py:538 (1.58.0 and 1.58.1) maps the OBR line "Incapacity benefits" to esa_income:

"esa": ("Incapacity benefits", "esa_income"),
  • The OBR "Incapacity benefits" line covers all ESA, contributory and income-related, plus Incapacity Benefit.
  • In policyengine-uk, esa_income is "ESA (income-based)" only. esa adds esa_contrib and esa_income, and incapacity_benefit is a separate variable.
  • So obr/esa (£7.21bn for 2025-26) is fitted to income-related ESA alone. It lands within 2% (estimate £7.34bn) only because calibration pushes income-related ESA up to meet a target that also covers contributory ESA and Incapacity Benefit. That inflates income-related ESA, and through it the legacy-benefit passports.

Found by the policyengine-model docs audit, the same kind of target-to-variable mismatch as #537. The UK hub confirmed the mapping and the variable definitions.

What to do

  1. Score obr/esa against the variables the OBR line covers: esa (contributory + income-related) plus incapacity_benefit. Check the OBR table's notes for anything else on that line, such as Severe Disablement Allowance, and add it if the model has it.
  2. Add a test that each OBR target's variable set matches the line's definition. Extend Stop calibrating OBR total NICs on ni_employee #537's two-targets-on-one-column check to a mapping table, with the OBR definition cited for each row.
  3. Measure in the next batch build: income-related ESA, contributory ESA and IB totals and caseloads, and the legacy-benefit passports that read them.

Related: #537 (total NICs on ni_employee), #581 (engine skew).

🤖 Generated with Claude Code

Activity

  1. changed the title [-]OBR "Incapacity benefits" target is scored against income-related ESA only (esa_income)[/-] [+]obr/esa ("Incapacity benefits") leaves out incapacity benefit, SDA and the incapacity part of income support[/+] on Oct 14, 2026
  2. MaxGhenis commented on Oct 14, 2026

    @MaxGhenis
    ContributorAuthor

    Correction: the premise of this issue was wrong. I checked only the registry mapping when I filed it.

    build_loss_matrix.py L413-L414 sends obr/esa to compute_esa, which returns esa_income + esa_contrib (compute/income.py L115-L119). That overrides the registry's esa_income, so the target is already scored against all ESA, not income-related ESA only. The docs audit session found the error, and an independent fact-check caught it.

    What is left is narrower. Footnote 2 on OBR table 4.9 (storage/obr_efo/efo_expenditure.xlsx, cell B50) says the "Incapacity benefits" row includes incapacity benefit, employment and support allowance, severe disablement allowance, and income support (incapacity part), and excludes the health element of universal credit. The model side leaves out:

    • incapacity_benefit (exists in policyengine-uk as a reported amount);
    • sda (same);
    • the incapacity part of income support (no separate variable).

    The OBR row is £12.41bn in 2024-25, £7.21bn in 2025-26 and £5.35bn in 2026-27. I have not measured how much of it these three benefits account for.

    I have retitled the issue to this narrower gap. A fix would add incapacity_benefit and sda to compute_esa.

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