Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/1008-regional-childcare-plan.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a regional childcare planning page (docs/book/programs/gov/dfe/regional-childcare-plan.md) listing the Scottish, Welsh and Northern Ireland childcare schemes not yet modelled and how to add them.
1 change: 1 addition & 0 deletions changelog.d/1069-pip-points-plan.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a PIP point system planning page (docs/book/programs/gov/dwp/pip-points-plan.md) setting out the SI 2013/377 scoring rules and a phased route to modelling them, starting from #1661.
1 change: 1 addition & 0 deletions changelog.d/1114.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a planning docs page (`docs/book/policy/indirect-tax-effects-plan.md`) on letting indirect tax revenue respond to direct tax reforms through a consumption elasticity, from a single household-level factor to per-category elasticities and a link to `consumer_incident_tax_revenue_change`.
1 change: 1 addition & 0 deletions changelog.d/1209.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Documented the Ubuntu vs macOS reproducibility issue (#1209) at `docs/book/validation/ubuntu-vs-macos.md`: the import-time uprating cause, how it was resolved, and the October 2026 check that the parameter tree is byte-identical across macOS and Linux.
1 change: 1 addition & 0 deletions changelog.d/1320.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a planning docs page for firm-level VAT (`docs/book/programs/gov/hmrc/firm-vat.md`): a proposed `Firm` entity, the registration threshold and supply split, output, input and net VAT, the data needed for a synthetic firm panel, and open questions.
1 change: 1 addition & 0 deletions changelog.d/1354.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added an effective take-up analysis plan (docs/book/assumptions/takeup-analysis-plan.md) listing each programme's take-up flag, reference parameter and current handling, where the data builds' seed rates live, and how to measure drift from them.
1 change: 1 addition & 0 deletions changelog.d/1398.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a child poverty validation page (docs/book/validation/child-poverty-tcl.md) comparing the two-child limit removal on Microcosm UK 2024-25 (about 463,000 children lifted after housing costs, £3.26bn in 2029-30) with the DWP, Budget 2025 (OBR-certified) and Resolution Foundation estimates.
1 change: 1 addition & 0 deletions changelog.d/1621.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a UK pipeline alignment planning page (docs/book/assumptions/uk-pipeline-alignment-plan.md): the model-side take-up gap still open, and what Microcosm UK now covers (reported-anchored take-up, the SPI stage-2 fill).
1 change: 1 addition & 0 deletions changelog.d/1628.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Documented the policyengine.py household-impact zero-return diagnosis (docs/book/validation/policyengine-py-household-impact.md); the UK model returns the expected values, re-checked on 2.123.7.
1 change: 1 addition & 0 deletions changelog.d/1692.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a planning docs page (`docs/book/assumptions/mp30k-uk-switch-plan.md`) setting out the gates and rollback path for changing the default dataset. It was written for Microplex UK and now applies to its successor, Microcosm UK.
1 change: 1 addition & 0 deletions changelog.d/435.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a plan for modelling Cold Weather Payment and the Scottish Winter Heating Payment (#435) at `docs/book/programs/gov/dwp/cold-weather-payment-plan.md`.
1 change: 1 addition & 0 deletions changelog.d/466.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a plan for a rule-based Bereavement Support Payment and historical Widowed Parent's Allowance (#466, #465) at `docs/book/programs/gov/dwp/bereavement-support-plan.md`.
1 change: 1 addition & 0 deletions changelog.d/502.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a plan for modelling the Warm Home Discount (#502) at `docs/book/programs/gov/ofgem/warm-home-discount-plan.md`, reflecting the benefit-based eligibility in England and Wales from winter 2025-26 and the separate Scottish scheme.
1 change: 1 addition & 0 deletions changelog.d/636.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a page (docs/book/policy/future-date-announcements.md) on encoding announced policy changes as date-keyed parameter values, and how those dates become model-year values.
1 change: 1 addition & 0 deletions changelog.d/669.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a planning docs page for child maintenance (`docs/book/programs/gov/cms/child-maintenance.md`): how `maintenance_income` and `maintenance_expenses` are treated today, the gap for spousal maintenance in Universal Credit, and a route to modelling the Child Maintenance Service calculation.
1 change: 1 addition & 0 deletions changelog.d/672.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a documentation page (`docs/book/programs/gov/hmrc/pensions-comparison-stbm.md`) comparing PolicyEngine UK's treatment of pension contributions in income tax with the Scottish Tax-Benefit Model's source code, including a gap both share: contributions do not reduce adjusted net income for the personal allowance taper.
1 change: 1 addition & 0 deletions changelog.d/704.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a documentation page at `docs/book/programs/gov/hmrc/pension-tax-relief.md` explaining how PolicyEngine UK models personal pension tax relief (full marginal-rate reduction in taxable income via `pension_contributions_relief`, with separate annual-allowance excess charge via `personal_pension_contributions_tax`), and clarifying that the model correctly reports the *total* relief (both relief-at-source + higher-rate top-up combined) for the scenarios reported in #704.
1 change: 1 addition & 0 deletions changelog.d/806.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a plan for a reform impacts dashboard (#806) at `docs/book/validation/reform-impacts-dashboard-plan.md`, tracking the regression fixtures in `reforms_config.yaml` over model and dataset versions.
1 change: 1 addition & 0 deletions changelog.d/818.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Documented how capital gains are modelled and imputed (#818, #817) at `docs/book/assumptions/capital-gains-distribution-plan.md`, including the Microcosm UK stages that now fit gains jointly to HMRC Table 3 and what is left to do.
1 change: 1 addition & 0 deletions changelog.d/842.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add a planning docs page (`docs/book/assumptions/non-uk-benefit-receipt-plan.md`) on benefit spending that does not reach UK private households (payments abroad, institutions, fraud and error) and how calibration targets should exclude it.
133 changes: 133 additions & 0 deletions docs/book/assumptions/capital-gains-distribution-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# Capital gains distribution

```{note}
**Planning page, updated October 2026.** Tracks
[#818](https://github.com/PolicyEngine/policyengine-uk/issues/818)
(model gains jointly across income groups) and
[#817](https://github.com/PolicyEngine/policyengine-uk/issues/817)
(don't impute gains to households with no wealth). The imputation lives
in the data build, not in this repo. Most of what this page proposed
in May 2026 has since been built in
[Microcosm UK](https://github.com/PolicyEngine/microcosm), which builds
the replacement for the Enhanced FRS. The certified UK default dataset is
still the Enhanced FRS from
[policyengine-uk-data](https://github.com/PolicyEngine/policyengine-uk-data)
(release 1.58.0). What remains is listed at the end of this page.
```

## How the model uses capital gains

`capital_gains_before_response` is a person-level input, uprated by OBR
per-capita GDP growth. `capital_gains_tax` charges it at the main CGT
rates, with three components charged at their own rates (all added by
[#1861](https://github.com/PolicyEngine/policyengine-uk/pull/1861)):

- `capital_gains_badr`: gains qualifying for Business Asset Disposal
Relief or Investors' Relief, at the relief rate up to the lifetime
limit;
- `capital_gains_residential_property`: gains on UK residential
property, at the residential rates;
- `capital_gains_carried_interest`: carried interest, at the carried
interest rates.

Each is a component of the total, not an addition to it.

Behavioural responses: `capital_gains_behavioural_response` changes
realisations using an elasticity with respect to the retention rate
(`relative_capital_gains_retention_rate_change`) or the marginal tax
rate. Gains use `gov.simulation.capital_gains_responses.elasticity`,
which is 0 by default, so there is no response unless a user sets it.
When `gov.simulation.capital_gains_responses.separate_badr_elasticity`
is true (false by default), gains qualifying for BADR respond at
`badr_elasticity` instead (1.4, the value the OBR used for these gains
in its January 2025 costing), through `capital_gains_badr_elasticity`.

## How the gains are imputed

### Enhanced FRS: one distribution per income band

The Enhanced FRS (policyengine-uk-data, the certified default) fits a
spline to the Advani and Summers gains percentiles within each income
band and draws each household's gains from its band. The spline alone
cannot produce gains above about £2m, so policyengine-uk-data main (not
yet in a release) also stacks 30 donor households per HMRC
size-of-gain band and calibrates to HMRC counts and amounts of gains by
band. #818 pointed out the problems with the
band-by-band fit:

- each band's upper tail was fitted on few observations, so the tails
were noisy and the joint distribution of income and gains had breaks
at band boundaries;
- two people in the same band drew from the same distribution however
different their incomes;
- gains depended on income only, not on wealth, so they could be
imputed to households with no assets (#817).

### Microcosm UK

Microcosm builds gains in six stages (see the UK
[sources specification](https://github.com/PolicyEngine/microcosm/blob/main/packages/microcosm-build/src/microcosm/build/uk/spec/sources.yaml)):

1. **Support split** (`cgt_support_split`). Within each income band of
HMRC Capital Gains Tax statistics Table 3, the households with the
most investable wealth (financial wealth, business wealth and
property other than the main home) are split into lighter copies, so
that there are enough rows to hold the largest gains.
2. **Who has gains** (`cgt_incidence_clone`). The set and order of
gainers come from the incidence distribution in Advani and Summers
(2020), *Capital Gains and UK Inequality* (CAGE Working Paper 465).
3. **How much** (`hmrc_cgt_gains_spine`). Amounts are redrawn so that
gains match HMRC Table 3 for 2024-25, which counts taxpayers and
gains **jointly by size of gain and taxable income**, conditioned on
Tables 1, 2.1a, 5 and 6.
4. **Weight anchor** (`cgt_incidence_anchor`). Clones below the annual
exempt amount carry more weighted people than HMRC publishes, so the
excess weight is moved back to each clone's paired original.
5. **Residential property** (`cgt_residential_split`). Gains on UK
residential property are fitted to Table 8 (2024-25 residential
property disposals) by splitting households into weighted copies,
which fills `capital_gains_residential_property`.
6. **What kind** (`hmrc_cgt_asset_type_spine`). Of the remaining gains,
those qualifying for BADR or Investors' Relief are fitted to Table
4.1, which fills `capital_gains_badr`, and the rest are given asset
types from Table 7 (gains by asset type, 2023-24).

All the HMRC tables come from the Capital Gains Tax statistics July
2026 release, through Microcosm's pinned Chronicle feed.

Against #818: gains are now fitted to the published joint distribution
of gain size and taxable income, not band by band. Against #817:
the largest gains are placed on the wealthiest households in each
income band. Microcosm's release checks also include a projection check
on people just below the annual exempt amount
(`uk_cgt_projection_entrants` in `gates.json`), so that
uprating does not push implausible numbers of them into paying CGT in
later years.

## What is left

- **A zero-wealth test.** Add a test, here or in Microcosm, that no
positive gains sit on households with zero investable wealth. Neither
repo asserts this directly yet, so #817 should stay open until it
does.
- **Close #818** once a Microcosm UK dataset is the certified default
and its diagnostics confirm the Table 3 fit; link them from the issue.
- **Elasticities by group.** Responses use one main elasticity and one
BADR elasticity. With the joint distribution in place, an elasticity
that varies by income or size of gain becomes possible, at the cost
of more parameters to justify.
- **Wealth source.** Investable wealth comes from Microcosm's Wealth
and Assets Survey imputation. Its quality limits how well #817 can be
met.

The quantile regression forest approach proposed here in May is no
longer needed for this.

## References

- Issues: [#818](https://github.com/PolicyEngine/policyengine-uk/issues/818), [#817](https://github.com/PolicyEngine/policyengine-uk/issues/817).
- CGT components: [#1861](https://github.com/PolicyEngine/policyengine-uk/pull/1861).
- HMRC, [Capital Gains Tax statistics](https://www.gov.uk/government/statistics/capital-gains-tax-statistics).
- Advani, A. and Summers, A. (2020), *Capital Gains and UK Inequality*, CAGE Working Paper 465.
- Microcosm UK [sources specification](https://github.com/PolicyEngine/microcosm/blob/main/packages/microcosm-build/src/microcosm/build/uk/spec/sources.yaml) (stages `cgt_support_split`, `cgt_incidence_clone`, `hmrc_cgt_gains_spine`, `cgt_incidence_anchor`, `cgt_residential_split`, `hmrc_cgt_asset_type_spine`).
- OBR (2025), [Costing of changes to the main, BADR and IR rates of capital gains tax](https://obr.uk/docs/dlm_uploads/CGT-supplementary-release-Jan-2025.pdf).
104 changes: 104 additions & 0 deletions docs/book/assumptions/mp30k-uk-switch-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Switching the default dataset: gates and rollback

```{note}
**Planning page.** [#1692](https://github.com/PolicyEngine/policyengine-uk/issues/1692)
asked for a switch and rollback path from the Enhanced FRS (eFRS) to Microplex UK
(`mp-30k-uk`). The `microplex-uk` repository has since been archived, and its
successor is [Microcosm UK](https://github.com/PolicyEngine/microcosm), whose
UK national line publishes `microcosm_uk_2024_25.h5`. This page applies the
same switch and rollback path to Microcosm UK.
```

## Current state

PolicyEngine UK has no built-in default dataset. `Simulation()` uses, in order:

1. an explicit `dataset=` argument;
2. the `POLICYENGINE_UK_DEFAULT_DATASET` environment variable
(`DEFAULT_DATASET_ENV_VAR` in `tax_benefit_system.py`);
3. otherwise, unless an inline `situation` is passed, it raises a `ValueError`
(`get_default_dataset_url` in `simulation.py`).

The test suite sets the variable to the private
`hf://policyengine/policyengine-uk-data-private/enhanced_frs_2023_24.h5@1.40.3`
when a Hugging Face token is available (`policyengine_uk/tests/conftest.py`).
So the eFRS is still the dataset the model is tested against, and the
default in downstream tools such as policyengine.py.

Direct microsimulation through `Microsimulation()` in this package is
deprecated in favour of [policyengine.py](https://github.com/PolicyEngine/policyengine.py),
whose managed bundle pins certified datasets (see the repository README). The
default most users meet is therefore the one that bundle pins, so a switch has
to be made there as well as in this repository's tests.

## What the switch needs

### Loader

- `UKMultiYearDataset` and `UKSingleYearDataset`
(`policyengine_uk/data/dataset_schema.py`) are the containers both datasets
load into. A Microcosm file must use the same table and column conventions,
because `_pre_encode_enum_columns` (in `simulation.py`) walks each year's
tables.
- The dataset's `years` drive uprating. Microcosm's base year is 2024-25,
one year later than the eFRS file used in tests, so uprating paths from the
earlier base year need checking.
- Enum columns must use the labels in this repo's variable definitions.
Unknown labels do not encode correctly.

### Variables

- `policyengine_uk/variables/input/` is the data contract. A switch should
report the input columns present in one dataset but not the other, and
decide for each whether a missing column is acceptable.
- Take-up and other reported-versus-simulated inputs have to come from the
new data, not be carried over from the eFRS.

### Calibration

- Microcosm calibrates its own weights against its target register, and
certifies each release through its own checks. The model side should
compare results against those targets, not re-weight.

## Switch criteria

A documented gate must pass before any environment's default changes:

1. **Aggregates:** headline totals (income tax, NICs, UC, Child Benefit,
State Pension) on both datasets for the same year, each set against OBR
outturn, with any difference of more than £1bn or 2% (whichever is wider)
explained.
2. **Distribution:** decile mean net income and HBAI poverty rates (before
and after housing costs) within 2 percentage points, or explained.
3. **Reforms:** at least three standard reforms (for example +1p on the basic
rate, +£5 a week on the UC standard allowance, abolishing the two-child
limit) give the same sign and are within 5% of each other.
4. **Tests:** the suite passes with the new default, including
`test_latest_data_smoke.py`, `test_deterministic_variables.py` and
`test_no_economic_assumptions.py`.
5. **Documentation:** the `assumptions/` section records the switch and any
remaining aggregate gaps.

## Rollback path

1. Dataset choice stays a runtime setting: no code in this repo depends on
which dataset is loaded.
2. While both are in use, CI runs the dataset-dependent tests on both.
3. The default is set per environment through
`POLICYENGINE_UK_DEFAULT_DATASET`, with the eFRS file kept available.
4. Rolling back is changing that variable and redeploying, with no code
change here. This assumes the eFRS file stays published while the switch
beds in.

## Acceptance

PolicyEngine UK switches its default only after the gates above pass, with a
rollback that needs no code change in this repo. Until then either dataset can
be used by passing `dataset=` or setting the environment variable.

## References

- Tracking issue: [#1692](https://github.com/PolicyEngine/policyengine-uk/issues/1692) (still open). Its umbrella discussion is in the archived [`microplex-uk`](https://github.com/PolicyEngine/microplex-uk/discussions/2) repository.
- Related: [#1621](https://github.com/PolicyEngine/policyengine-uk/issues/1621) (aligning the UK model and data pipeline).
- Microcosm UK: [repository](https://github.com/PolicyEngine/microcosm).
- Dataset loading: `policyengine_uk/simulation.py`, `policyengine_uk/data/dataset_schema.py`.
Loading
Loading