Repository navigation
Require a Pension Credit payment for savings-credit-only receipt - #2373
Merged
Merged
Conversation
in_receipt_of_savings_credit_only now needs pension_credit > 0, on the normal path and under the Pension Credit freeze, as #1987 does for in_receipt_of_guarantee_credit. A reform that stops Pension Credit being paid no longer leaves savings-credit-only families on the Pension Credit assessment for pensioner Council Tax Reduction (SI 2012/2885 Sch 1 para 14) and pension-age Housing Benefit (SI 2006/214 reg 27). Unreformed outputs do not change: pension_credit is the entitlement of a claiming family, so eligible, claiming and savings_credit > 0 already imply a payment. Fixes #2372 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review follow-ups on #2373: - the docstring now says a payment stands in for the award because the model does not withhold awards under 10p a week (SPC Regs 2002 reg 13), and that under disable_simulated_benefits receipt also needs reported Pension Credit; the changelog fragment says the same; - references add SPC Regs 2002 reg 13, SI 2012/2885 Sch 1 para 14 and SI 2006/214 reg 27; - the test's outside-the-age-rule range is 67 to 75: with no sex given the model's savings credit age rule is met in 2026 from age 76. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Delta-review nits on #2373: at age 75 the model reaches State Pension age exactly on the savings credit cutoff, so the outside range is 67 to 74; and reg 13 withholds payment, not the award, so the docstring says so and notes that modelling it would need the flag to test the award. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
marked this pull request as ready for review
October 12, 2026 08:52
MaxGhenis
added a commit
that referenced
this pull request
Oct 13, 2026
Brings in #2119 (UC claims at legacy closure), #2373, #1905, #2177, #2305, #2306, #2325, #2376, #2379, #2380, #2388 and #2364. One conflict, in the UC docs notebook: kept main's new paragraph on claims at legacy closure and this branch's benefit cap sentence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2372
What changes
in_receipt_of_savings_credit_onlynow needs a Pension Credit payment. It computespaid = benunit("pension_credit", period) > 0and requires it:eligible & would_claim & paid & (guarantee_credit <= 0) & (savings_credit > 0);gov.contrib.freeze_pension_credit:paid & baseline....#1987 (still open) uses the same pattern for
in_receipt_of_guarantee_credit. The two PRs edit different files, so they don't conflict.Why. The pensioner Council Tax Reduction schemes (SI 2012/2885 Sch 1 para 14; WSI 2013/3029 Sch 1 para 8; SSI 2012/319 reg 25) and pension-age Housing Benefit (SI 2006/214 reg 27) use the Secretary of State's assessment for someone "who has, or whose partner has, an award of state pension credit comprising only the savings credit".
Take a reform that stops Pension Credit being paid, for example
Scenario(simulation_modifier=lambda sim: sim.tax_benefit_system.neutralize_variable("pension_credit")). On main, a savings-credit-only family kept that assessment, with or without the freeze, even though it no longer has the award. Example, 2026, Maidstone, council tax £2,000:in_receipt_of_savings_credit_onlyThe tenant version of that family on main also kept a pension-age Housing Benefit tariff income of £0 (reg 27(5)), where Housing Benefit's own rule counts £208 a year (
test_known_families_detect_main).Scope of the proxy. A payment stands in for the award. The model does not withhold awards under 10p a week (SPC Regs 2002 reg 13), so every claimed award is paid. Under
disable_simulated_benefits, which setspension_creditto the reported amount, receipt now also needs reported Pension Credit. The docstring and changelog say both.Invariants
Each is stated for model-computed credits and tested in
policyengine_uk/tests/test_savings_credit_only_receipt_properties.py(Hypothesis, generated populations of pension-age, mixed-age and working-age families, owners and council tenants, in England, Wales and Scotland):pension_credit = pension_credit_entitlement * would_claim_pc, and the entitlement is guarantee credit plus savings credit for an eligible family. So eligible, claiming andsavings_credit > 0already imply a payment. Under this PR the flag and every output that reads it (CTR applicable income, capital and award; HB applicable income, tariff income, capital and award) equal main's, which the test runs through main's formula on the same population.pension_credit > 0and excludesin_receipt_of_guarantee_credit. In the unreformed model, the paid award equals the savings credit.pension_creditends receipt for every family, with or without the freeze. This fails on main.in_receipt_of_guarantee_creditdoesn't yet need a payment; Qualify targeted childcare through Pension Credit only on receipt of a guarantee credit #1987 adds that.Tests run
uv run --frozen pytest policyengine_uk/tests/test_savings_credit_only_receipt_properties.py -n 3).test_council_tax_reduction_pension_credit_properties.py,test_housing_benefit_savings_credit_only_properties.pyandtest_council_tax_reduction_carer_income_properties.py, 18 passed.tests/policy/baseline/gov/dwp/pension_credit/, 266 passed.ruff formatandruff checkon the changed files: clean.Enhanced FRS comparison
These are real microsimulation runs on uk-data-private 1.58.0
enhanced_frs_2024_25.h5(61,214 benefit units). One process runs this branch and main's formula, loaded from the file at origin/main 3f174d0, on the same data and compares them. Only aggregates were written. Script and output:flag_compare.py/flag_compare.json(kept locally, not attached: FRS licence).Unreformed, 2025 to 2030: no change (invariant 1). In every year:
pension_credit = pension_credit_entitlement * would_claim_pcholds for every record;Pension Credit stopped (
pension_creditneutralised), 2026. Main still treats 244 records (97.3k weighted benefit units) as having a savings-credit-only award; this branch treats none as having one. These figures describe what the fix changes for that hypothetical reform; they are not a costing of the current system. Fix minus main:Review
Independent reviews ran on Subfleet lanes. No Codex lane admitted them, so they were served by Opus 5.5:
disable_simulated_benefitsare now in the docstring and changelog, the law references are added, and the test's age range is corrected.git diff --stat 61b29a81a 6731dd7c4touches only the two files.axiom: n/a: reform-path behaviour of a model receipt flag; no change to the encoded law
🤖 Generated with Claude Code