-
Notifications
You must be signed in to change notification settings - Fork 31
Edit salary sacrifice implementation #1441
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The previous implementation incorrectly applied a 13% targeted haircut to only affected workers' excess contributions. This is economically incorrect because employers cannot target only affected workers without those workers negotiating to recoup the loss. The correct approach (from the blog at policyengine.org/uk/research/uk-salary-sacrifice-cap): - Full excess above £2,000 cap is redirected to regular pension contributions - Employers spread their increased NI costs across ALL workers - This results in a ~0.16% broad-base haircut on everyone's employment income Changes: - New parameter: salary_sacrifice_broad_base_haircut_rate (default 0.0016) - New variable: salary_sacrifice_broad_base_haircut (reduces all workers' income) - Remove old employer_salary_sacrifice_haircut parameter (targeted 13%) - Update salary_sacrifice_returned_to_income to redirect full excess - Update NI variables to use full excess (no targeted haircut) - Add employment_income to include broad_base_haircut in adds - Update tests to reflect new methodology This allows parametric simulation of the salary sacrifice cap reform: - Adjust the cap amount via salary_sacrifice_pension_cap - Adjust the broad-base haircut rate via salary_sacrifice_broad_base_haircut_rate 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Fixed: Broad-base haircut implementationThe previous implementation had a fundamental error in how the employer haircut was modeled. The ProblemThe old code applied a 13% targeted haircut to only affected workers' excess: # OLD (wrong)
excess = max_(intended_ss - cap, 0)
haircut = 0.13 # 13% of excess
return excess * (1 - haircut) # Only 87% redirectedThis is economically incorrect because employers cannot target only salary sacrificers without those workers negotiating to recoup the loss. The FixPer the blog methodology:
The new implementation:
New Parameters
Verificationfrom policyengine_uk import Microsimulation
sim = Microsimulation()
print(sim.calculate('salary_sacrifice_broad_base_haircut', 2030).sum() / 1e9) # -£2.3bn
print(sim.calculate('salary_sacrifice_returned_to_income', 2030).sum() / 1e9) # £13.6bnThe broad-base haircut is -£2.3bn (total employment income ~£1.4T × 0.16%), and full excess of £13.6bn is redirected. |
Is there any reference for the 0.16% rate? |
|
@PolicyEngine please review this pr. |
|
⚙️ Running tests to verify the implementation... |
Description
This PR implements the £2,000 salary sacrifice pension cap from the Autumn Budget 2025, which takes effect from April 2029.
Summary
Key changes
income tax relief)
employee_pension_contributions_reported
Usage
Test plan