Skip to content

Roadmap: complete, interaction-aware UK tax–benefit coverage (2000-onward) #1775

@vahid-ahmadi

Description

@vahid-ahmadi

Summary

This is a roadmap for extending PolicyEngine UK toward a complete, interaction-aware UK tax–benefit model that runs correctly from 2000 onward. Today the model is, in practice, a ~2015-onward model of the current system: most core parameters floor at 2015, uprating indices floor at 2009, the microdata is forward-only from FRS 2023-24, and several major taxes/benefits are either absent or modelled as survey pass-throughs without rules.

The work below is organised into workstreams. Each item notes status today (with file paths) and what needs implementing. Suggested priority labels P0–P3 are at the workstream level.


Workstream A — Historical depth (2000-onward) — P0, foundational

The single largest gap. To simulate any year before ~2015 the model needs backward histories, not just the current schedule carried backwards (which is silently wrong).

  • Parameter backfill to 2000. Almost every core file starts 2015-04: income tax rates (parameters/gov/hmrc/income_tax/rates/uk.yaml), personal allowance (.../allowances/personal_allowance/amount.yaml), NI class 1/2/4, student-loan thresholds, dividend/savings rates, most DWP benefit rates (AA, DLA, PIP, Carer's Allowance, ESA, JSA, HB all at 2015). Backfill annual uprated values to 2000. Good existing examples to follow: basic State Pension (2002), Winter Fuel (2000), tax credits (2002).
  • Uprating indices pre-2009. gov/economic_assumptions/yoy_growth.obr.* outturn starts 2009-01-01; create_economic_assumption_indices.py and lag_cpi.py (range(2010, 2030)) cannot uprate earlier. Extend indices back to 2000.
  • Backward microdata path. data/economic_assumptions.py sets _FRS_BASE_YEAR = 2023 and only forward-extends to 2030. There is no mechanism to produce 2000–2014 populations; a historical-FRS ingestion/back-projection path is needed.
  • Missing legacy regimes required for historical years: pre-2016 basic State Pension uprating rules (pre-triple-lock), Working Families' / Disabled Person's Tax Credit (pre-2003), pre-2013 national Council Tax Benefit means test, MIRAS, the 10% starting rate of income tax (pre-2008, not representable in rates/uk.yaml today), the 50p additional rate (2010/11–2012/13) and the £150k→£125,140 additional-rate threshold path, the pre-2016 dividend tax-credit regime, and pre-2015 CGT (taper relief / 18% flat / 2010 split).

Workstream B — Missing tax systems — P0/P1

B1. Inheritance Tax — entirely absent (P0)

No parameters or variables anywhere. Add parameters/gov/hmrc/inheritance_tax/ (nil-rate band £325k frozen since 2009; residence nil-rate band 2017→£175k with £2m taper; 40%/36% rates; APR/BPR incl. the £1m cap from April 2026; PET 7-year taper) and variables/gov/hmrc/inheritance_tax/. Needs an estate/death concept that does not exist in the current annual person-level model — scope as a separate module. Interacts with total_wealth.

B2. Capital Gains Tax — asset-class logic and reliefs (P0)

variables/gov/hmrc/capital_gains_tax/capital_gains_tax.py applies a single rate set to one capital_gains input. Missing:

  • Residential-vs-other split (18%/28% historically; residential higher rate cut to 24% on 6 Apr 2024; main rates raised to 18%/24% on 30 Oct 2024).
  • Business Asset Disposal Relief / Investors' Relief (lifetime £1m; rate 10%→14% 2025/26→18% 2026/27).
  • Exemptions (gilts, legal-tender coins, chattels) and loss carry-forward.
  • Correctness check: parameters/gov/hmrc/cgt/basic_rate.yaml / higher_rate.yaml move 0.1/0.2 → 0.18/0.24 only at 2025-04-06, but the main-rate change was 30 Oct 2024 and the residential cut to 24% was 6 Apr 2024 — both the timing and the residential split need fixing. annual_exempt_amount.yaml starts 2018 and has no pre-2018 history.

B3. ISA / LISA / JISA wrappers (P1)

Only variables/.../ISA_interest_income.py exists (an input exempting ISA interest). No subscription-limit parameters (£20k since 2017/18, with history), no LISA (£4k + 25% bonus), no JISA (£9k), and crucially no wrapper interaction so that sheltered dividends and capital gains are excluded from taxable_dividend_income and capital_gains.

B4. Pensions — LTA and MPAA (P1)

Annual allowance + taper exist (variables/.../pension_annual_allowance.py); Lifetime Allowance (incl. the 2023/24 charge abolition and 2024 full abolition) and MPAA (£4k→£10k) are absent. Also flag that the AA taper currently keys off adjusted_net_income rather than the statutory adjusted income (incl. employer contributions) with a threshold income floor.

B5. Missing direct-tax allowances (P2)

  • Blind Person's Allowanceblind_persons_allowance.py has no formula and no parameter file; add params + formula on the existing is_blind variable.
  • Married Couple's Allowance — only a 10% deduction_rate exists; no amount parameter and no "both born before 6 April 1935" eligibility / income reduction.
  • Married women's reduced-rate NI (legacy) — absent; niche but needed for full historical completeness.

Workstream C — Indirect, property, local & devolved taxes — P1/P2

  • Missing excise/indirect taxes (consumption-side, revenue-relevant): alcohol duty (post-Aug-2023 ABV-band structure + draught/small-producer reliefs), tobacco duty, Soft Drinks Industry Levy (2018), Plastic Packaging Tax (2022), Insurance Premium Tax, Vehicle Excise Duty, Air Passenger Duty, Climate Change Levy, ATED. An alcohol_and_tobacco_consumption input already exists to build on.
  • VAT structure: today only full-rate vs reduced-rate split (parameters/gov/hmrc/vat/). Add explicit zero-rated/exempt categories and a registration-threshold parameter to enable base-broadening reforms.
  • Council Tax depth: currently an imputed household input (variables/input/consumption/property/council_tax.py + council_tax_band enum), not band × local-authority rate. Add band-D rate parameters, band multipliers, the 25% single-person discount, exemptions — so the freeze and revaluation can be modelled.
  • Business rates: top-down (national revenue × shareholding) and stale past 2021. Add reliefs (small business, retail/hospitality) and ideally a rateable-value basis.
  • Welsh Rates of Income Tax: no pays_welsh_income_tax flag or Welsh rate params; add (mirroring pays_scottish_income_tax) from 2019 even if currently equal to rUK, to support counterfactual Welsh reforms.
  • Scottish devolved benefits: implement Adult Disability Payment and Child Disability Payment (Scotland replacements for PIP/DLA — Scotland currently modelled under abolished GB benefits), plus Best Start Grant/Foods and Scottish Welfare Fund.

Workstream D — Means-tested benefits gaps — P1

  • Council Tax Reduction / Support is the largest means-test gap. Only a reported pass-through stub exists (variables/gov/dwp/council_tax_benefit.py); there is no computed pre-2013 Council Tax Benefit means test and no post-2013 localised CTR/CTS model. Implement: a default England working-age scheme + the national pensioner scheme + Scotland/Wales variants, with per-authority overrides. This sits outside UC and is locally varied — a key interaction gap.
  • Social-sector bedroom tax (removal of spare room subsidy, since Apr 2013): uc_housing_costs_element.py pays full rent for council/HA tenants and HB applies LHA caps only to private rent. Add the 14%/25% under-occupancy deduction reusing LHA_allowed_bedrooms against num_bedrooms for social tenants.
  • UC transitional protection / managed migration: variables/misc/uc_migrated.py is an inert flag. Add a transitional element flooring UC at prior legacy entitlement at migration, with erosion logic (needed for accurate 2022–2028 modelling).
  • UC surplus earnings rule — entirely absent; add carry-forward logic in universal_credit/income/.
  • Tax-credit income disregards — only a £300 non-earned disregard; the £2,500 in-year income-rise/fall disregards (which drive real awards/overpayments) are missing.

Workstream E — Contributory / disability / family benefits — P1/P2

  • Absent cash benefits: Cold Weather Payment, Warm Home Discount, Christmas Bonus, Shared Parental Pay (2015), Statutory Adoption Pay, Carer's Credit (NI credit feeding pension accrual).
  • Reported-only, no parameters (cannot be reformed/simulated counterfactually): Bereavement Support Payment (bsp.py, no params — 2017 lump-sum + 18-month structure unmodelled), Maternity Allowance, SMP/SPP/SSP (no rate params or qualifying-earnings logic), IIDB, AFCS, Incapacity Benefit, contributory ESA/JSA. The contributory-vs-income structure exists but the contributory side has no rules.
  • DLA / PIP are reported-only — they sum reported component amounts with no eligibility/assessment logic, so the 2013 DLA→PIP migration cannot be simulated as a reform. Consider entitlement-based variables; PIP params also start only 2015 (no DLA-era pre-2015 support).
  • HICBC params start 2015 but the charge began Jan 2013 — backfill 2013–2015. SSMG params start 2022 — backfill to introduction.

Workstream F — Interactions & passporting — P1

The aggregation/MTR backbone is solid (household_net_income.py, household_tax.py, household_benefits.py; marginal_tax_rate.py uses simulation branching correctly; benefit cap and UC means test layer correctly). Gaps:

  • Passporting is largely cosmetic. Free school meals (gov/dfe/free_school_meals.py), free milk, and free fruit/veg are CPI-uprated reported stubs not linked to benefit entitlement. CTR is partly reported-driven. A real interaction-aware model needs entitlement-driven passporting.
  • TFC ↔ UC childcare element mutual exclusivity is not enforced (cannot legally claim both).
  • Carer's Allowance overlapping-benefits / earnings-limit rules are not modelled — carers_allowance.py applies only an hours test + reported flag; add the overlap ("underlying entitlement") and earnings-limit rules. Note CA interacts with State Pension.
  • Verify State Pension → income tax (taxable; BSP tax-free) and State Pension → Pension Credit / Savings Credit feed-throughs.

Workstream G — Metadata / programs.yamlP2/P3

  • programs.yaml under-reports the codebase: it omits ~15 modelled programs (IIDB, AFCS, BSP, incapacity benefit, SMP/SPP/SSP, Council Tax Reduction/CTB, LHA, Welsh LTT, Scottish Carer Support Payment, Pension Age Winter Heating Payment, two-child-limit machinery, Cold Weather/Warm Home/Christmas Bonus once added). Add entries.
  • Most entries are complete with verified_start_year: 2019/2022 even where params extend to 1988–2008; align verified_start_year honestly after backfilling and add tests. Business rates is partial / verified only to 2021 — update.
  • Add verified_years where missing (CLAUDE.md requires it when extending year coverage).

Suggested sequencing

  1. Workstream A (historical depth) underpins everything — without it, pre-2015 results are wrong regardless of feature coverage.
  2. B1/B2 (Inheritance Tax, CGT asset-classes + the rate-date fix) and D (Council Tax Reduction, bedroom tax) are the highest-impact missing-system gaps.
  3. B3/B4 (ISA wrappers, pensions LTA/MPAA), C (indirect taxes, devolved benefits, Welsh flag), E (reported-only → entitlement), F (passporting/interactions).
  4. G metadata cleanup alongside each workstream as programs are added/extended.

Each workstream should be split into per-program sub-issues with parameters, variables, tests, and changelog.d/ entries per the contributing guide.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions