Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

UK bonus sacrifice: meet OBR's base at the final weights, not the stage's

Open
#1,390 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
48/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
python
Domain
backend, data

Research direction

Read the salary_sacrifice stage and convert_bonuses_to_bonus_sacrifice, then trace how calibration produces the final weights and check whether annual allowance tests read the pension contributions this step changes. Re-run the selection after calibration with the same identity-keyed order and £13.0bn anchor; preserve the stage selection where the post-calibration step does not run. Done means the final-weight projection meets OBR's base without moving calibrated income or violating any bound row.

Written by the indexing model from the issue text.

Description

Problem

The salary_sacrifice stage imputes pension_contributions_via_bonus_sacrifice (#1340, #1383). It picks bonus sacrificers in the order of identity-keyed draws, until the engine's projection of the sacrificed bonuses above the £2,000 threshold at 2027-28 is nearest OBR's base. That base is £13.0bn (OBR supplementary forecast information, 5 February 2026, Table 1.1).

The stage measures the projection at its own weights, before calibration. On #1383's review arm, the base at the final weights falls short of OBR's line by more than a quarter. The column is the same in both files; only the weights move. Vahid flagged the risk in his review of #1383 (item 7).

Why

Calibration to the HMRC SPI income-band rows lowers the weights of the highest earners, and the bonus sacrificers sit mostly there:

  • a candidate must be paid at least the upper earnings limit;
  • the larger bonuses belong to the higher earners;
  • most of the sacrificers are rows of the SPI channel, and calibration lowers those the most.

No calibration row reads the bonus base, so nothing holds it. The salary route does not drift this way, because the HMRC salary-sacrifice rows bind it. The figures behind this diagnosis rest in part on the SPI channel's households, so they stay with the licensed data.

Proposal

Re-pick the bonus sacrificers after calibration, at the final weights. This is a post-calibration step that reruns convert_bonuses_to_bonus_sacrifice on the calibrated weights, with the same identity-keyed order and the same anchor.

  • The sacrifice sits beside pay, so no calibrated income moves.
  • The £2,000 NICs cap reads it only from April 2029.
  • First, check that no bound row reads the pension contributions it adds to, for example through the annual allowance tests.
  • Where the step does not run, keep the stage's selection.

The alternative is to bind the base during calibration, as a row deflated to 2025 by the anchor's growth factors. That needs a ruling, since the build refuses facts dated after the calibration year (_refuse_fact_after_target).

Until then

#1383's Phase B and C receipts record that the base holds at the stage's weights only. A costing of the bonus-sacrifice cap on a release built before this lands would understate the base.

Dominant language
Python
Stars
0
Forks
6
Avg merge
1d 20h
Merged PRs (30d)
132

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from PolicyEngine/microcosm

All issues in PolicyEngine/microcosm

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.