Gap
src/parameters/mod.rs collapses National Insurance into a small NationalInsuranceParams struct with a handful of rates and thresholds, and src/variables/income_tax.rs computes a single aggregate NIC figure.
Python has separate trees for each class:
policyengine_uk/variables/gov/hmrc/national_insurance/class_1/ — employee + employer, primary + secondary thresholds, UEL, contracted-out rates
policyengine_uk/variables/gov/hmrc/national_insurance/class_2/ — flat self-employed
policyengine_uk/variables/gov/hmrc/national_insurance/class_3/ — voluntary contributions
policyengine_uk/variables/gov/hmrc/national_insurance/class_4/ — self-employed profit-based
- Salary-sacrifice NIC interaction variables (employer-side savings)
Why it matters
- Salary-sacrifice cap analysis (existing notebooks:
salary_sacrifice_cap_*.ipynb) — requires Class 1 employee + employer split
- Self-employment reforms — Class 2 abolition (already enacted in 2024/25), Class 4 rate changes
- Employer NIC reforms (Reeves Oct-2024 budget secondary-threshold cut) —
reeves_budget_2025_analysis*.ipynb already needs this
- NIC exemption for disabled employees (
nics-exemption-disabled-employees) — requires per-employee Class 1 modelling
- Without class-level granularity, employer-side NIC scoring is impossible (the policy lever is on secondary thresholds, not aggregate NICs).
What to port
- Split
NationalInsuranceParams into class-specific structs
- Per-class compute functions taking the relevant earnings concept (employment income, self-employment profit, etc.)
- Employer NIC as a separate output, surfaced to net-income calculations correctly (incidence assumption follows current PE convention)
- Parameter tree mirroring the Python directory structure
Effort
Medium. The arithmetic is well-specified by HMRC; the work is mostly fanning out the existing compute_national_insurance into four class functions plus parameter restructuring.
References
- Python:
policyengine_uk/variables/gov/hmrc/national_insurance/
- Python params:
policyengine_uk/parameters/gov/hmrc/national_insurance/
- Rust:
src/variables/income_tax.rs, src/parameters/mod.rs::NationalInsuranceParams
Gap
src/parameters/mod.rscollapses National Insurance into a smallNationalInsuranceParamsstruct with a handful of rates and thresholds, andsrc/variables/income_tax.rscomputes a single aggregate NIC figure.Python has separate trees for each class:
policyengine_uk/variables/gov/hmrc/national_insurance/class_1/— employee + employer, primary + secondary thresholds, UEL, contracted-out ratespolicyengine_uk/variables/gov/hmrc/national_insurance/class_2/— flat self-employedpolicyengine_uk/variables/gov/hmrc/national_insurance/class_3/— voluntary contributionspolicyengine_uk/variables/gov/hmrc/national_insurance/class_4/— self-employed profit-basedWhy it matters
salary_sacrifice_cap_*.ipynb) — requires Class 1 employee + employer splitreeves_budget_2025_analysis*.ipynbalready needs thisnics-exemption-disabled-employees) — requires per-employee Class 1 modellingWhat to port
NationalInsuranceParamsinto class-specific structsEffort
Medium. The arithmetic is well-specified by HMRC; the work is mostly fanning out the existing
compute_national_insuranceinto four class functions plus parameter restructuring.References
policyengine_uk/variables/gov/hmrc/national_insurance/policyengine_uk/parameters/gov/hmrc/national_insurance/src/variables/income_tax.rs,src/parameters/mod.rs::NationalInsuranceParams