-
Notifications
You must be signed in to change notification settings - Fork 145
Add UK salary sacrifice cap analysis blog post #2815
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 latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds a blog post analyzing the UK government's proposed £2,000 cap on salary sacrifice pension contributions. The analysis examines the policy's impact on households, government revenue, and income distribution using PolicyEngine's microsimulation model.
Key Changes
- Adds comprehensive analysis of salary sacrifice cap proposal with detailed calculations and visualizations
- Includes metadata entry for the new blog post with proper tags and author attribution
- Updates changelog to reflect the minor version bump for new content
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/posts/posts.json | Adds metadata entry for the salary sacrifice cap blog post with title, description, date, tags, filename, image, and author |
| src/posts/articles/uk-salary-sacrifice-cap.md | New 216-line article with introduction, household impact analysis, budgetary analysis, distributional analysis, and conclusion sections with embedded Plotly visualizations |
| src/images/posts/salary-sacrifice-uk.jpg | Binary image file for the blog post (370 lines of encoded data) |
| changelog_entry.yaml | Updates version bump from patch to minor and changes description to reflect new blog post addition |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Nice analysis! One question on the 13% employer haircut assumption: The model assumes employers can identify exactly which employees use salary sacrifice and reduce their specific compensation by 13%. But if employers have that level of targeting ability, couldn't they also just restructure benefits to avoid the cap (e.g., increase employer pension contributions directly)? There's a bit of an internal inconsistency:
A more defensible assumption might be an employer cost-neutral scenario where:
This is more realistic because employers typically don't adjust individual compensation based on personal benefit elections (discrimination concerns, admin complexity). Compensation decisions are usually made at cohort/company level. This would likely push the revenue estimate closer to the government's £2bn figure, with less concentrated impact on salary sacrifice users specifically. Worth considering as a sensitivity analysis or revision to the main assumption? |
|
Follow-up with specific implementation suggestion: Looking at the notebook, the current approach in # Current: targeted haircut on affected individuals
new_employment_income = emp_income + excess_ss_contrib * (1 - employer_response_haircut)This applies the 13% haircut only to individuals with salary sacrifice > £2k, which assumes employers can target compensation reductions to specific employees based on their benefit elections. Suggested alternative: Employer cost-neutral, broad-based response A more defensible approach would spread the employer's increased NI cost across all employees: def create_ss_cap_reform_v2(cap_amount: float = 2000):
def modify(sim):
for year in range(2026, 2031):
ss_contrib = sim.calculate("pension_contributions_via_salary_sacrifice", period=year).values
excess_ss_contrib = np.maximum(ss_contrib - cap_amount, 0)
emp_income = sim.calculate("employment_income", period=year).values
# Calculate total employer NI cost increase from excess becoming taxable
# Employer NI rate is ~13.8% (or 15% from April 2025)
employer_ni_rate = 0.138
total_employer_ni_increase = (excess_ss_contrib * employer_ni_rate).sum()
# Spread this cost across ALL employees (not just affected ones)
total_employment_income = emp_income.sum()
broad_haircut_rate = total_employer_ni_increase / total_employment_income
# All employees get slightly reduced income
new_employment_income = emp_income * (1 - broad_haircut_rate)
# Affected employees also get excess converted to taxable income
new_employment_income += excess_ss_contrib # Full amount, no targeted haircut
# Update employee pension contributions for affected individuals
employee_pension = sim.calculate("employee_pension_contributions", period=year).values
new_employee_pension = employee_pension + excess_ss_contrib
sim.set_input("employment_income", year, new_employment_income)
sim.set_input("employee_pension_contributions", year, new_employee_pension)
sim.set_input("pension_contributions_via_salary_sacrifice", year, ss_contrib - excess_ss_contrib)
return Scenario(simulation_modifier=modify)Key differences:
This should push revenue closer to the government's £2bn estimate and is more defensible from a labor economics perspective. Worth running as at least a sensitivity analysis? |
Revenue Calculation IssueAfter investigating the £1.33bn revenue figure, I believe there's an error in the original calculation. Here's my analysis: The IssueThe original analysis shows £1.33bn revenue, but when I trace through the tax mechanics, the correct figure should be approximately £0.53-0.60bn. Why Income Tax Should Be ZeroI tested with a simple case (£50k earner with £5k salary sacrifice → £2k cap): Key finding: Employee pension contributions reduce taxable income, so the income tax effect nets to zero. The only revenue is from NI. Correct Revenue BreakdownUsing the FRS data (£3.60bn total salary sacrifice, £2.63bn excess above £2k cap):
If using full excess (broad-based model): £0.60bn Why Original Showed £1.33bnThe original used £1.33bn / £0.53bn ≈ 2.5x, which matches roughly what we'd see if ~35% marginal income tax was incorrectly included. Comparison to Government Estimate
The discrepancy is likely due to FRS underreporting salary sacrifice. External estimates suggest total SS is ~£20bn (vs our £3.6bn). Scaling up: £0.60bn × (20/3.6) ≈ £3.3bn. Recommendation
I've updated the blog post on the |
Data Calibration NoteThe FRS-based salary sacrifice data significantly undercounts actual salary sacrifice activity:
This explains the revenue gap:
Recommendation: The policyengine-uk-data microdata should be calibrated to external salary sacrifice benchmarks, likely using HMRC's NI relief cost data as a calibration target. This would bring revenue estimates in line with Treasury/external scorekeeper figures. |
|
Filed PolicyEngine/policyengine-uk-data#215 to track the salary sacrifice calibration work. |
- Updates data from new FRS salary sacrifice imputation model - Workers with SS contributions: 1.22M (was 588k) - Total SS contributions: £6.93bn (was £3.60bn) - Revenue estimate: £1.13bn (was £0.60bn) - Updates distributional chart and example calculations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Updated data section: 4.9m workers (15% of employees), £22.7bn total - Updated revenue estimates: £3.2bn (PE) vs £4.9bn static / £4.7bn post-behavioural (OBR) - Updated number above cap: 3.3m workers (68% of SS users) - Policy takes effect April 2029 - Removed outdated £2bn FT estimate, replaced with official OBR figures 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
d1d2361 to
6b91750
Compare
- Revenue by scenario chart showing £3.32bn to £7.58bn range - Distributional impact chart with absolute/relative toggle - Charts hosted on GitHub Pages from uk-salary-sacrifice-analysis repo 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Update revenue estimate from £3.2bn to £3.3bn (matching £3.32bn in chart) - Fix posts.json description: £1.1-2.3bn → £3.3-7.6bn - Remove redundant Table 3 (data now shown in interactive chart) - Correct OBR comparison: 35% → 32% below static estimate - Add explanation of behavioural assumption differences 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
|
Closing - moving to app-v2 repo |
link https://www.ft.com/content/11602ac1-44fc-4b58-8b17-af5e851f5c95