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/fixed/state-pension-recorded-amount.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix `person_state_pension` to respect the recorded `state_pension` amount for the new-SP cohort (those below the basic-SP age cutoff). Previously the new-SP branch always returned the full `new_state_pension_weekly × 52`, ignoring any recorded amount and over-stating SP for partial-year and partial-record claimants. Now mirrors the existing old-SP scaling pattern: recorded amounts pass through (scaled by reform-ratio when the new-SP rate changes), with fallback to the parameter rate when no amount is recorded. Closes #59. Shrinks the parity-harness pensioner-couple state-pension diff from £946 → £0.
18 changes: 12 additions & 6 deletions src/engine/simulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ pub struct Simulation {
pub parameters: Parameters,
/// Baseline old basic SP weekly rate for scaling reported amounts under reforms.
pub baseline_old_sp_weekly: f64,
/// Baseline new SP weekly rate for scaling reported amounts under reforms.
pub baseline_new_sp_weekly: f64,
/// Fiscal year (e.g. 2025 for 2025/26) — used for new/basic SP cutoff.
pub fiscal_year: u32,
}
Expand All @@ -125,25 +127,27 @@ impl Simulation {
fiscal_year: u32,
) -> Self {
let baseline_old_sp_weekly = parameters.state_pension.old_basic_pension_weekly;
let baseline_new_sp_weekly = parameters.state_pension.new_state_pension_weekly;
Simulation {
people, benunits, households, parameters,
baseline_old_sp_weekly, fiscal_year,
baseline_old_sp_weekly, baseline_new_sp_weekly, fiscal_year,
}
}

/// Create a simulation with explicit baseline old SP rate (for reform simulations
/// where the baseline rate differs from the reform parameters).
/// Create a simulation with explicit baseline SP rates (for reform simulations
/// where the baseline rates differ from the reform parameters).
pub fn new_with_baseline_sp(
people: Vec<Person>,
benunits: Vec<BenUnit>,
households: Vec<Household>,
parameters: Parameters,
baseline_old_sp_weekly: f64,
baseline_new_sp_weekly: f64,
fiscal_year: u32,
) -> Self {
Simulation {
people, benunits, households, parameters,
baseline_old_sp_weekly, fiscal_year,
baseline_old_sp_weekly, baseline_new_sp_weekly, fiscal_year,
}
}

Expand All @@ -157,10 +161,11 @@ impl Simulation {
// Phase 1a: Calculate each person's state pension under the current policy.
// State pension is taxable income so must be computed before income tax.
let baseline_old_sp = self.baseline_old_sp_weekly;
let baseline_new_sp = self.baseline_new_sp_weekly;
let fiscal_year = self.fiscal_year;
let person_sp: Vec<f64> = self.people.par_iter().map(|p| {
variables::benefits::person_state_pension(
p, &self.parameters, baseline_old_sp, fiscal_year,
p, &self.parameters, baseline_old_sp, baseline_new_sp, fiscal_year,
)
}).collect();

Expand All @@ -184,7 +189,7 @@ impl Simulation {
let hh = &self.households[bu.household_id];
variables::benefits::calculate_benunit(
bu, &self.people, &person_results, hh, &self.parameters,
baseline_old_sp, fiscal_year,
baseline_old_sp, baseline_new_sp, fiscal_year,
)
}).collect();
benunit_results = br;
Expand Down Expand Up @@ -708,6 +713,7 @@ mod tests {
adjusted_people, benunits.clone(), households.clone(),
policy_params.clone(),
baseline_params.state_pension.old_basic_pension_weekly,
baseline_params.state_pension.new_state_pension_weekly,
2025,
);
let dynamic_results = dynamic_sim.run();
Expand Down
3 changes: 2 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,13 +561,14 @@ fn main() -> anyhow::Result<()> {
dataset.people.clone()
};

// Run policy simulation (pass baseline old SP rate so reported amounts scale correctly)
// Run policy simulation (pass baseline old + new SP rates so reported amounts scale correctly)
let policy_sim = Simulation::new_with_baseline_sp(
policy_people,
dataset.benunits.clone(),
dataset.households.clone(),
policy_params.clone(),
baseline_params.state_pension.old_basic_pension_weekly,
baseline_params.state_pension.new_state_pension_weekly,
cli.year,
);
let reformed = policy_sim.run();
Expand Down
Loading