Skip to content

Lift the tax credit income test for State Pension Credit - #2034

Draft
MaxGhenis wants to merge 19 commits into
mainfrom
tax-credits-pension-credit-passport
Draft

MaxGhenis wants to merge 19 commits into
mainfrom
tax-credits-pension-credit-passport

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #2032

Summary

tax_credits_applicable_income lifted the tax credit income test for Income Support, income-based JSA and income-related ESA, but not for State Pension Credit, which SI 2002/2008 reg 4(1)(d) also prescribes. This PR adds the Pension Credit passport.

Working tax credit is Pension Credit income, so Pension Credit and the passport depend on each other. The passport is decided on the Pension Credit payable with the passported award counted, calculated in a core branch.

The passport makes the tested income nil, and the two-year-old childcare criteria read that tested income. So this PR also splits out tax_credits_current_year_income, the income before the passport, and the childcare criteria now test that gross figure.

Stacked on #2027 (legacy-award-readers-claimant-partner, merged in at fc1ff55d1), which switched the other passports to the claimant's and partner's awards. #2027 is stacked on #2013 and #2001; #1896 has merged. #2061 and #2057 are stacked on this PR.

Law (fetched verbatim from legislation.gov.uk /data.xml, 2026-10-02)

  • TCA 2002 s.7(2): "Subsection (1) does not apply in relation to the entitlement of a person or persons to a tax credit for so long as the person, or either of the persons, is entitled to any social security benefit prescribed for the purposes of this subsection in relation to the tax credit."

  • SI 2002/2008 reg 4:

    • (1): "Subject to paragraph (2), the following are social security benefits prescribed for the purposes of section 7(2) of the Act in relation to child tax credit and working tax credit— (a) income support ... other than income support to which a person is entitled only by virtue of regulation 6(2) and (3) of the Income Support (General) Regulations 1987; ... (c) an income-based jobseeker's allowance ...; (d) state pension credit within the meaning of the State Pension Credit Act 2002 or the State Pension Credit Act (Northern Ireland) 2002; (e) an income-related employment and support allowance ..."
    • (2): "Paragraph (1) shall not apply in relation to working tax credit during the four-week period described in regulation 7D of the Working Tax Credit (Entitlement and Maximum Rate) Regulations 2002 (ceasing to undertake work or working for less than 16 or 30 hours per week)."
    • Reg 4(1)(d) was added from 26 November 2003 (SI 2003/2815 reg 18), and reg 4(2) from 6 April 2010 (SI 2010/751 reg 17(2)).
  • SPCA 2002 s.1(3): a claimant entitled to state pension credit is entitled "(a) to a guarantee credit ... or (b) to a savings credit ... (or to both ...)".

  • SPCA 2002 s.15(1): "In this Act “income” means income of any of the following descriptions—", with para (b) "working tax credit".

    • Child tax credit is named nowhere in s.15(1), nor among the descriptions SPC Regs 2002 reg 15(5) prescribes for para (j).
    • That working tax credit needs its own paragraph implies tax credits are not "prescribed social security benefits" under para (e). This is an inference, not a quote.
    • So CTC is not Pension Credit income, and in the model Pension Credit reads tax credits only through working_tax_credit.
  • SPCA 2002 s.4(1A), from 15 May 2019: "A claimant is not entitled to state pension credit if he is a member of a couple the other member of which has not attained the qualifying age." SI 2019/37 art. 4 saves it for a mixed-age couple entitled to Pension Credit or Housing Benefit on 14 May 2019, until a day on which they are entitled to neither (art. 4(2)). One qualification: a person moved to Universal Credit under a migration notice keeps the saving if they claim Housing Benefit or Pension Credit within three months, because their days on Universal Credit are disregarded (art. 4(3)-(4)).

  • SI 2014/2147 reg 1(2), "eligible child", as at 1 September 2024. The two-year-old offer covers a child whose parent is entitled to:

    • "child tax credit where that parent is not also entitled to working tax credit ... and has an annual gross income not exceeding £16,190", or
    • working tax credit "by virtue of an award which is based on an annual income not exceeding £16,190".

    SI 2025/1261 omitted these limbs from 1 January 2026.

  • WTC Regs 2002 reg 4(1), Second condition, second variation (a joint claim with no child). "The person" who works must be:

    • "aged at least 25 and undertakes work for not less than 30 hours per week"; or
    • "aged at least 60 and undertakes work for not less than 16 hours per week"; or
    • "aged at least 16 and undertakes work for not less than 16 hours per week and has a physical or mental disability" that puts them at a disadvantage in getting a job.
  • IS Regs 1987 reg 6. As at 6 April 2003, paras (2) and (3) said a lone parent who started remunerative work after 26 weeks on Income Support or income-based JSA "shall not be treated as engaged in remunerative work for the period of 14 days" (the lone parent run-on). SI 2003/1589 reg 2(a)(i) omitted paras (2) and (3) from 25 October 2004.

The questions

Any Pension Credit, or only the guarantee credit? Any. Reg 4(1)(d) names "state pension credit within the meaning of" the Act, and s.1(3) makes that a guarantee credit, a savings credit or both. The passport reads pension_credit (both credits, after take-up), not guarantee_credit. A test covers a couple on the savings credit alone.

Entitled, so claimed. There is no entitlement to a benefit without a claim (SSAA 1992 s.1(1), (4)(ab)). pension_credit applies would_claim_pc, so unclaimed Pension Credit gives no passport, as income_support does for Income Support.

Mixed-age couples. A couple claims tax credits jointly, and reg 4 lifts the test if "either of the persons" is entitled to Pension Credit. So the older partner's Pension Credit passports the couple's whole joint award: CTC for their children, and WTC on either partner's work.

  • WTC's own conditions still apply to the person who works. With no child, that person must be at least 60 and work 16 hours, or be at least 25 and work 30 hours, or be at least 16, work 16 hours and have a qualifying disability.
  • With a child, the third variation adds the couple's 24-hour limb (one partner works 16 hours), and a 16-hour limb where the other partner is incapacitated, in hospital, in prison or entitled to Carer's Allowance.
  • The model pools those conditions across the couple: WTC eligibility pools the age, disability and hours conditions across a couple (WTC Regs 2002 reg 4(1)) #2042, found in review.
  • From 15 May 2019, s.4(1A) bars Pension Credit for a mixed-age couple unless the art. 4 saving applies. A couple who lose the saving (a day with neither Pension Credit nor HB, apart from art. 4(3)-(4)'s three-month window after a managed move to Universal Credit) cannot reclaim, so the passport ends and the income test returns.
  • On this base, is_pension_credit_eligible applies s.4(1A) in every year and does not model the art. 4 saving. So the model never gives a mixed-age couple Pension Credit, and so never the passport; a test covers this.
  • Date the mixed-age couple Pension Credit exclusion and model the SI 2019/37 saving #1940 dates s.4(1A) from 15 May 2019 and models the saving. Because this PR reads pension_credit, a couple who get Pension Credit under Date the mixed-age couple Pension Credit exclusion and model the SI 2019/37 saving #1940 get the passport with no further change.
  • Tax credits ended on 5 April 2025, so the interaction is confined to 2024-25 and earlier. The model's tax credit thresholds start in 2016-17.

The reg 4(1)(a) exception (IS Regs 1987 reg 6(2)-(3)). No modelling is needed. It excluded Income Support paid only under the 14-day lone parent run-on. Those paragraphs were omitted from 25 October 2004, so no one has been entitled to Income Support "only by virtue of" them since then. That is long before the model's first tax credit year. The model has no Income Support run-on in any case.

Reg 4(2), the WTC four-week run-on. Not modelled. During the reg 7D run-on, which starts when the claimant stops work or drops below the hours condition, the passport does not apply to WTC (CTC stays passported). The model's WTC is a whole-year award on the year's hours, with no run-on period. working_tax_credit_run_on is a whole-year flag read only by the targeted childcare criteria. Using it to switch the WTC passport off for a whole year would overstate a four-week rule 13-fold. The code comment records this.

The dependency cycle, and which state the model picks

Pension Credit counts working tax credit as income (s.15(1)(b)), and the tax credit income test reads Pension Credit (s.7(2)). The law gives no tie-break. Write Wmax for the passported (maximum) WTC award, Wt for the income-tested one, and PC(W) for Pension Credit computed with WTC W. Then:

Case Consistent states Model
PC(Wmax) > 0 passported, only passport; WTC Wmax, Pension Credit PC(Wmax)
PC(Wt) = 0 income-tested, only no passport
PC(Wmax) = 0 < PC(Wt) none: lifting the test ends Pension Credit, which restores the test no passport; WTC Wt, Pension Credit PC(Wt)

The table assumes Pension Credit never rises with WTC. That holds in law: the guarantee credit falls by the whole of it (s.2(2)), and WTC is not qualifying income for the savings credit (SPC Regs reg 9(a)).

The model's savings credit counts WTC as qualifying income (#1954), so in the model it can rise 20p per £1 of WTC. That adds a fourth, model-only case: PC(Wt) = 0 < PC(Wmax), where both states are consistent and the model takes the passport. In law Pension Credit is nil either way. Reaching it needs income the model excludes from qualifying income (contributory ESA or JSA) alongside WTC above State Pension age. No 2024 Enhanced FRS family has both Pension Credit and tax credits, so none is affected.

"Entitled" is read as payable. At income exactly equal to the minimum guarantee, where no savings credit is payable, a nil guarantee credit gives no passport; this boundary has measure zero.

The rule is: the passport holds when Pension Credit stays payable with the passported award counted. pension_credit_with_passported_tax_credits computes this in a core branch (tax_credits_pension_credit_passport, suffixed if that name is taken) in which tax_credits_applicable_income is set to 0, and removes the branch afterwards. It reads the branch's Pension Credit through its population, so a microsimulation returns an unweighted array. Where the passport holds, the simulation's own WTC, CTC and Pension Credit equal the branch's. So the model never shows a passport alongside nil Pension Credit. The third row is the only case in which Pension Credit is paid without the passport. It needs WTC, since CTC is not Pension Credit income.

Side effects of the rule:

  • Guarantee-credit-only claimants with WTC. Pension Credit withdraws £1 for each £1 of WTC, so the passport moves money from Pension Credit to WTC without changing the total. Pension Credit can't fall below nil, and the rule only passports where it stays payable. A claimant who also gets the savings credit can gain, because the model's savings credit can rise with WTC (below); review r2 found one gaining £158.67.
  • Savings credit claimants. The model's savings credit can rise with WTC (above), so their total can rise.
  • CTC. It is not Pension Credit income, so lifting the test raises CTC with no offset.
  • freeze_pension_credit. With Pension Credit frozen at its baseline, it no longer responds to WTC. A third-row family can then be passported under the reform, so WTC rises although Pension Credit is held fixed. This is consistent with the freeze, but it is a change to tax credits.

Years with no awards. From 2025-26, gov.dwp.tax_credits.active is false and every tax credit is nil, so the passported and income-tested states coincide. pension_credit is read directly, with no branch. To keep that free of a cycle, wtc_entitlement returns nil before reading the income test when tax credits are inactive. Its value is unchanged: it was already nil through tax_credits. A Pension Credit recipient's tax_credits_applicable_income is therefore 0 in those years too. That keeps the variable's meaning the same in every year; no amount changes.

Cost. The branch is created only in years with awards (2024-25 and earlier), so runs for 2025-26 onward pay nothing.

In 2024, measured on a copy of the Enhanced FRS (/usr/bin/time -l, separate processes, base 200a1cdc4 against f2eb82445; the passport code has not changed since):

2024 run core Time, base → branch Peak RSS, base → branch
household_net_income, then marginal_tax_rate 3.32.9 (the lock) 1.4 → 1.8 s, then 2.4 → 2.7 s 3.35 → 4.15 GB
labour-supply reform (elasticities 0.25 / -0.05, personal allowance £13,070) 3.32.9 10.7 → 10.0 s 5.13 → 7.67 GB
the same reform 3.32.12 7.5 → 8.0 s 5.10 → 5.15 GB

The memory comes from core 3.32.9 deep-copying every cached array into each branch. The labour-supply and marginal-tax-rate branches each create a passport branch of their own. policyengine-core 3.32.12 includes PolicyEngine/policyengine-core#556 (branches share arrays and copy on first read), which removes the extra memory.

Changes

  • tax_credits_current_year_income (new): the tax credit income before the passport (TCA 2002 s.7(4); SI 2002/2006 reg 3), moved out of tax_credits_applicable_income unchanged.
  • tax_credits_applicable_income: that income, or nil while a prescribed benefit lifts the test. It now includes the Pension Credit passport (reg 4(1)(d)), with the reasoning above in a docstring. Comments record why the reg 4(1)(a)-(b) exceptions and reg 4(2) are not modelled.
  • meets_child_tax_credit_criteria_for_targeted_childcare_entitlement and meets_working_tax_credit_criteria_for_targeted_childcare_entitlement test tax_credits_current_year_income against £16,190.
    • On the base they read the tested income. That was already nil for IS, JSA and ESA families, but harmlessly so, since those benefits qualify for the offer in their own right.
    • The Pension Credit passport would have let a savings-credit-only family through. The regulation names only "the guaranteed element of state pension credit", so that family has no other route.
  • wtc_entitlement: returns before the income test when tax credits are inactive (no change in value).
  • New parameter gov.dwp.tax_credits.means_test.pension_credit_passport: false from 6 April 2003, true from 26 November 2003. It records the commencement and lets a reform switch the passport off.

Invariants (property-tested, Hypothesis)

For any family of one or two adults aged 40-90 (mixed-age couples included) and up to two children, with earnings, hours, State Pension, private pension, savings, WTC and CTC claims, Pension Credit take-up and income-related ESA:

  1. Differential. In 2024-25, the passport holds exactly when an independent simulation, with tax_credits_applicable_income entered as 0, pays Pension Credit. Otherwise the applicable income equals the value with the parameter switched off.
  2. Consistency.
    • Where Pension Credit gives the passport, the simulation's own WTC, CTC and Pension Credit equal the passported simulation's.
    • Where it does not, they equal the values with the passport switched off.
  3. No harm. Lifting the test never lowers WTC or CTC.
  4. Third row only. Pension Credit is paid without the passport only where the passported WTC exceeds the income-tested WTC. So a family with no WTC is passported whenever it gets Pension Credit.
  5. Order. Results are the same whether Pension Credit, the income test or household net income is requested first. No passport branch is left, at any depth.
  6. No-award years. In 2025-26 tax credits are nil, Pension Credit equals its passport-off value, and the test is lifted exactly when Pension Credit is payable, with no cycle.
  7. Childcare. A met tax credit criterion for the two-year-old offer implies gross income within £16,190.

Property 1 checks the branch against the same rule computed outside the formula. So it catches stale or leaked caches, but not a wrong rule; the YAML cases check the rule against the law.

Unit tests:

  • the passport under tracing, and nested inside the marginal tax rate's own branches;
  • in a Microsimulation, results match a Simulation, and the helper returns an unweighted array.

Income-related ESA is drawn only below State Pension age.

Tests

YAML: 10 cases in tests/policy/baseline/gov/dwp/tax_credits_pension_credit_passport.yaml, each computed by hand from the law and that year's rates, with the arithmetic in comments:

  1. guarantee credit with WTC: passported, with the maximum WTC counted;
  2. 2018-19: guarantee credit with WTC, passported;
  3. the third row;
  4. a pensioner with no Pension Credit;
  5. unclaimed Pension Credit;
  6. the savings credit alone, with CTC;
  7. the same couple with a grandchild aged 2: not eligible for the two-year-old offer, because gross income is £20,200. Their CTC is £3,455, with no family element: that needs a child born before 6 April 2017 (CTC Regs reg 7(2)(a));
  8. a mixed-age couple, with the older partner working the WTC hours;
  9. 2025-26 with no awards, using the statutory £227.10 standard minimum guarantee (SI 2025/295 art. 29(2)(b));
  10. the parameter switched off.

Four intermediate values the model gets wrong for unrelated reasons are entered at their statutory amounts, with comments:

Each pensioner has £300 of savings interest. That makes the model's tax credit income equal the law's, which puts State Pension in step one with the £300 disregard (SI 2002/2006 regs 3, 5(1)(a)).

On the base 200a1cdc4, 6 cases fail and 4 pass (yaml_on_base_r2):

  • the passport cases (1, 2, 6, 9) fail on value;
  • the childcare case (7) fails because its new variable is missing;
  • the switched-off case (10) fails because the parameter is new;
  • the four no-passport cases pass on both.

On the first version of this PR (28eb7d2d4), the reviewer's probe of case 7's household was eligible, which was wrong.

Hypothesis: test_tax_credits_pension_credit_passport_properties.py has 6 tests: 3 properties (20 derandomized examples each), 2 unit tests (tracing and nesting; Microsimulation) and a coverage test.

  • In a derandomized draw of 60 examples of the same strategy (236 families), 55 are passported through Pension Credit (11 with WTC raised) and 1 is a third-row case. No random family has CTC raised.
  • So the YAML households also run as explicit @examples of every property, and test_yaml_families_reach_every_case checks they hit each case.
  • All passed on 28eb7d2d4; the explicit examples and the coverage test pass on 284434ffc.

Full suites on 49e6a51aa: YAML 1,587 passed; pytest 2,086 passed, 45 skipped. Earlier heads also passed: 284434ffc (YAML 1,575; pytest 2,057 passed, 45 skipped) and 29891b0b5 (YAML 1,577).

Enhanced FRS impact

Real Microsimulation runs on a private copy of the Enhanced FRS 2024-25 (sha256 e433e532…), base fc1ff55d1 (#2027's current head) against this branch at 49e6a51aa, years 2024-2030. Both trees were clean. Earlier pairs gave the same results: base 200a1cdc4 against 284434ffc, and against f2eb82445. Tax credits are paid only in 2024 in the model; from 2025 the scheme is inactive.

Money: £0 in every year. All 103 arrays were compared: benefits, household totals including gov_spending and hbai_household_net_income, and poverty rates. The only arrays that change are:

  • tax_credits_applicable_income, now nil for Pension Credit recipients: 2,097 benefit-unit records in 2024, about 1.7 million weighted, 382 of them on the savings credit alone. It changes in every year, but tax credits are nil from 2025, so no amount moves.
  • In 2024, the two childcare tax credit criteria: the CTC criterion turns false for 4 records (93 weighted benefit units) and the WTC criterion for 2 (140).
    • All six are families on IS, JSA or ESA. They are now tested on gross income instead of the passported nil.
    • None was or is eligible for the offer, and targeted_childcare_entitlement_eligible changes for nobody.

Why no amount changes in 2024.

  • 306 benefit units claim tax credits (124 with an award). Only 8 of them have a claimant or partner over State Pension age, and only 2 have both.
  • The 6 with an award and an older member are mixed-age couples. On this base they cannot get Pension Credit (s.4(1A), no art. 4 saving).
  • No tax credit claimant has a Pension Credit entitlement, so no family has both Pension Credit and tax credits. No case on the third row or the model-only fourth row arises.
  • With Date the mixed-age couple Pension Credit exclusion and model the SI 2019/37 saving #1940's art. 4 saving, those six mixed-age couples are the ones that could gain.

The H5 inputs and per-record arrays stay private; the summaries above are aggregates.

Axiom

axiom: TheAxiomFoundation/rulespec-uk#419 queued

TCA 2002 s.7 and SI 2002/2008 reg 4 are not in the corpus (checked axiom-corpus origin/main 2c86dc9af: TCA s.8 and SI 2002/2008 regs 7 and 9 are, as discovery entries), so the encoder path is blocked. rulespec-uk encodes SPCA 2002 ss.1-3 and SPC Regs reg 15, but s.1 defers Pension Credit entitlement. #419 holds the verbatim law, the required outputs, a pasteable review_finding and eight companion tests. Tests 1-6 come from this PR's YAML; tests 7-8 (commencement dates and the reg 4(2) run-on) are law-only. It is linked from #416, whose tax credit item now defers to it.

The childcare change reads SI 2014/2147 reg 1(2)'s tax credit limbs on gross, pre-passport income. TheAxiomFoundation/rulespec-uk#400, which queues that regulation's Universal Credit route, is extended in a comment with:

  • the two tax credit limbs, verbatim;
  • their dates (WTC limb from 8 September 2014, CTC limb from 1 April 2018, both omitted from 1 January 2026);
  • the pre-passport reading;
  • three companion tests.

Related and follow-ups

🤖 Generated with Claude Code

MaxGhenis and others added 6 commits October 1, 2026 18:19
claimant_or_partner_esa_income and claimant_or_partner_jsa_income are the
income-related awards on the claimant's and partner's reported amounts,
after the same capital test as esa_income and jsa_income (the
income_related_esa_award and income_related_jsa_award helpers, byte-identical
to the copies on #2013 and #2025). A directly entered esa_income or
jsa_income is taken to be the claimant's or partner's.

is_on_income_related_esa, is_on_income_based_jsa and is_on_income_support
say whether the award is payable to a person (HB Regs 2006 reg 2(1), (3),
(3A)): the claimant and partner through their couple's award, anyone else
through an award they report themselves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and passports

esa_income and jsa_income sum every benefit-unit member's reported award, so
a member who is neither the claimant, the partner nor their dependant (for
example a non-dependent adult) fed means tests and passports that the law
ties to the claimant and partner:

- HB and CTR income (SSCBA s.136(1), HB Regs 2006 reg 25(1); CTR (PR)
  (England) Regs 2012 Sch 1 para 11) and the working-age CTR passport;
- the tax credit income test (TCA 2002 s.7(2), SI 2002/2008 reg 4);
- Scottish Child Payment (SSI 2020/351 reg 18(e)-(f));
- the benefit cap health exemption (HB Regs 2006 reg 75F(1)(a));
- targeted childcare (SI 2014/2147 reg 2(1));
- would_claim_IS.

The CTR non-dependant exemption ("who is on") and the maintenance loan
benefits proxy now read the person's own award. Household totals (esa,
household_benefits, HBAI, gov_spending, benefit_cap_reduction) are
unchanged: another member's award is still household income.

Tests: 53 YAML cases computed by hand from the regulations, and Hypothesis
properties (adding such a member never changes any reader; the scoped awards
are bounded by, and without other awards equal to, the benefit-unit awards;
they match a direct reference; the person-level flags follow their
definition; Merton's non-dependant deductions are unchanged).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…was input

claimant_or_partner_esa_income and claimant_or_partner_jsa_income took
esa_income / jsa_income as the claimant's or partner's award whenever the
name was in Simulation.input_variables. That list is fixed at construction
and ignores the period: an input for 2024 alone made 2025 read the
benefit-unit total, so another member's 2025 award counted, and an award set
later with set_input or on a branch was ignored. Both now use
entered_directly (policyengine_uk/utils/inputs.py, byte-identical to #2013
and #2025), which reads core's record of each input's variable, branch and
period.

jsa_income.py is re-copied from #2025 (6337f31): the formula returns early
while income-based JSA is inactive, before reading reports.

Tests: YAML cases for an award entered for an earlier year only, and Python
tests for a late set_input, a set_input after the value was cached, a branch
and a late zero entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Takes policyengine_uk/simulation.py and policyengine_uk/utils/inputs.py
byte-identical from 48abd88 on #2025 (is-remunerative-work-jsa-conditions).
In policyengine-core 3.32.9, delete_arrays keeps the deleted arrays'
_user_input_keys entries, and clone shares the record. A formula value could
then look like a direct input, after a deletion or an input on a clone or on
a parent after a branch. The UK Simulation now gives each clone its own copy
of the record and drops the entries for deleted arrays, and entered_directly
asks about the stored value the simulation actually reads.

test_claimant_or_partner_awards_entered_directly.py mirrors #2025's lifecycle
cases on claimant_or_partner_esa_income and claimant_or_partner_jsa_income.
6 of its 12 cases fail without the Simulation changes. #2025's own test file
asserts its s.124(1)(f) JSA bar, which this branch does not have, so it is
not copied.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TCA 2002 s.7(2) lifts the tax credit income test while the claimant or
either joint claimant is entitled to a prescribed benefit, and SI 2002/2008
reg 4(1)(d) prescribes State Pension Credit (from 26 November 2003). The
model passported Income Support, income-based JSA and income-related ESA
but not Pension Credit.

Pension Credit counts working tax credit as income (SPCA 2002 s.15(1)(b)),
so reading Pension Credit from the income test is circular. The passport is
taken from Pension Credit calculated in a core branch in which the income
test is lifted: it holds when Pension Credit stays payable with the
passported award counted, and the simulation's own award and Pension Credit
then equal the branch's. In years with no tax credit awards Pension Credit
is read directly; wtc_entitlement returns before the income test in those
years, so there is no cycle.

Reg 4(1)(d) covers either credit (SPCA 2002 s.1(3)). The reg 4(1)(a)
exception (IS Regs 1987 reg 6(2)-(3), the lone parent run-on) is spent from
25 October 2004, and reg 4(2) (the WTC four-week run-on) has no period in a
whole-year award; both are documented, not modelled.

Adds gov.dwp.tax_credits.means_test.pension_credit_passport, YAML tests
hand-computed from the law, and Hypothesis properties (differential against
a passported simulation, consistency, no-harm, request-order independence,
and the no-award years).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 6 commits October 2, 2026 02:26
Random draws passport through Pension Credit often (55 of 236 families in a
derandomized sample) but never raise CTC and hit the third row once. The
YAML households now run as explicit examples of each property, and a test
checks that they reach every case: WTC and CTC raised by the passport, the
third row, and a mixed-age couple.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#2013 and #2025 replaced entered_directly and the Simulation overrides with a
value rule, after #2025's round-3 review found the record of direct inputs
unsound in policyengine-core 3.32.9:
- a Simulation without inputs has no record;
- the YAML runner and SimulationBuilder bypass the UK Simulation;
- disk-backed clones share files;
- branch names and ETERNITY periods diverge;
- delete_arrays becomes O(keys).

This merge takes their removal of policyengine_uk/utils/inputs.py and their
simulation.py (identical to 63b633c's). claimant_or_partner_esa_income and
claimant_or_partner_jsa_income now mirror the gate. Where esa_income /
jsa_income holds what the reported awards give, either after the capital
test (the formula) or as their plain total (disable_simulated_benefits), they
use the claimant's and partner's reported awards. Otherwise they take the
stored value to be the claimant's or partner's: an award entered directly, or
a reform that replaces or removes it. An entered award equal to either amount
is read through the reports.

test_claimant_or_partner_awards_entered_directly.py gains cases for an
entered award equal to the reports, the raw total with capital (partner
£200, other adult £3,000, savings £10,000: £0), and a neutralised award. The
lifecycle cases (deletion, clone, branches) keep their expectations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Docstring only: jsa_income.py is byte-identical to #2025's ffe3a58, matching
#2013's esa_income.py (44d59d9). No code changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t cap left unscoped

Review r2 of #2027 (subfleet job 20261002-044711) and #2013/#2025's latest
value-rule refinements (0953c8a, 081ec14):

- claimant_or_partner_{esa,jsa}_income: a stored zero is zero. References
  are compared at the stored float32 precision. When the stored award is
  the plain total of the reports (the disable_simulated_benefits reform),
  the claimant's and partner's plain reported total passes through
  unscreened, so a claimant's own £200 at £10,000 capital is no longer
  zeroed. Entering these variables directly is the explicit way to state
  ownership.
- is_on_income_related_esa / _based_jsa: another member's own report counts
  only while the benefit unit's modelled award is positive, so a reform
  that removes the benefit takes the status with it. is_on_income_support:
  likewise only while Income Support is active and not neutralised.
- is_benefit_cap_exempt_health_disability is reverted to the benefit unit's
  esa_income. benefit_cap_reduction (out of scope) still caps every
  member's ESA and JSA, so scoping the exemption alone would cap the
  claimant with another adult's own award. Both go to the benefit-cap
  follow-up.
- The property generator fixes claims_all_entitled_benefits per benefit
  unit (it sums reports across the simulation). SCP comments name the
  kinship route. The childcare citation is reg 1(2), not 2(1). Changelog
  wording matches the paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #2034 (Subfleet job 20261002-020316-tc-pc-passport-review-r1c):

- The two-year-old childcare criteria read tax_credits_applicable_income,
  which the passport zeroes, so a savings-credit-only family with CTC
  passed the £16,190 "annual gross income" limit (SI 2014/2147 reg 1(2))
  whatever its income. Split out tax_credits_current_year_income (TCA 2002
  s.7(4); SI 2002/2006 reg 3); the applicable income is that or nil, and
  both childcare criteria read the gross figure.
- YAML case 6 relied on is_WTC_eligible pooling age and hours across the
  couple (#2042): the older partner now does the work, with the same
  figures.
- Read the branch's Pension Credit through its population, so a
  microsimulation returns an unweighted array, and take a branch name in
  use by no other branch.
- Docstring: the rule's premise (Pension Credit never rises with WTC in
  law), the model-only case its savings credit creates (#1954), and the
  nil-guarantee boundary. Comment covers reg 4(1)(b).
- Tests: a childcare case, a 2018-19 case, a Microsimulation test, a
  household-net-income-first request order, a childcare property, and
  income-related ESA drawn only below State Pension age.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The targeted childcare tax credit criteria now read
tax_credits_current_year_income (the "annual gross income" of SI 2014/2147
reg 1(2)), so their tests enter that instead of the passported
tax_credits_applicable_income. Expectations are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A person is on income-based JSA or income-related ESA on a day it "is
payable to him" (reg 2(3), (3A)), and a person on income support is one "in
receipt of" it (reg 2(1)). A couple's award is paid to the claimant, not the
partner. is_on_income_related_esa, is_on_income_based_jsa and
is_on_income_support now hold, of the claimant and partner, only for the
payee: the one who reports the award, or the claimant where neither does
(is_payee_of_couple_award). Another member's report never moves the payee.
Anyone else is unchanged (their own report while the award is modelled as
paid).

Agreed with #2007, whose round-2 review raised the same point and which
applies the same reading through its is_award_payee helper; the codebase now
reads "who is on" one way.

Effects: in the local working-age CTR schemes a non-dependant couple on one
of these benefits pays the partner's deduction (one deduction per couple, the
higher: Default Scheme Sch para 30(3)); the maintenance-loan ESA proxy follows
the student's own award, not their partner's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

The case "The passport does not bring a family under the childcare gross income limit" (tax_credits_pension_credit_passport.yaml, line 244 at 29891b0b5) has a grandchild aged 2 in 2024-25, so born after 6 April 2017. CTC Regs 2002 reg 7(2)(a), from 6 April 2017, pays the family element only for a child or qualifying young person born before that date. So in law the CTC is the £3,455 child element alone, not CTC_family_element: 545 and child_tax_credit: 4_000. The passport and childcare outcomes the case tests are unchanged.

#2057 (stacked on this) had copied the same input and now enters CTC_family_element: 0 with child_tax_credit: 3_455. #2051 adds the born-before-2017 rule to the model. The case at line 194 (grandchild aged 10) is right as it is.

🤖 Generated with Claude Code

is_on_income_related_esa and is_on_income_based_jsa gated a member outside
the couple on the benefit unit's award over every report. Another member's
report could then lift that award above the tariff income and put them on
it: an excluded student's loan schedule or a Merton non-dependant deduction
changed when another adult was added (review r3's probes on 3803dda).

They now ask whether the award on that member's own report alone is
positive: the report exceeds the tariff income from the benefit unit's
capital, within the capital limit, while the benefit unit's award is
positive. Once the member reports, the capital test reads the household's
capital whoever else reports, so no other report can change the result.

The property generators now give qualifying young persons and an existing
outside adult reports of their own, and the Merton property has savings and
an existing outside adult; both failed on the old code. Two YAML cases are
hand-computed from ESA Regs 2008 reg 118. The maintenance-loan proxy cites
SI 2011/1986 reg 71(1)(h)(iii), reg 61(2)(b) and HB Regs 2006 reg 56(2)(a).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 3 commits October 3, 2026 07:33
Review r4: with "on" payee-only, a student whose partner is the
income-related ESA payee lost the maintenance-loan benefits schedule, even
where the partner's disability benefit puts the disability premium in the
couple's applicable amount. HB Regs 2006 reg 56(2)(c) lifts the student
exclusion for a full-time student "whose applicable amount would ... include
the ... disability premium or severe disability premium", and for a couple
the premium turns on either partner (Sch 3 paras 12(b)(ii), 13(1)(a)).

maintenance_loan_entitled_to_benefits now also qualifies a student who is
the claimant or partner when the benefit unit has the model's disability or
severe disability premium. A dependant's parent's premium does not count.
New YAML cases cover both; the property generator gives adults disability
inputs.

Also from reviews r4 and r3c (wording only): the changelog states the Income
Support own-report condition (active and not neutralised) apart from
ESA/JSA's; the claimant-or-partner awards say values are compared to within
half a penny at stored precision; is_on_income_support says a reform that
removes Income Support must neutralise it or switch it off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The childcare case's grandchild, aged 2, was born after 6 April 2017, so
  there is no CTC family element (CTC Regs 2002 reg 7(2)(a)): CTC is £3,455.
- The 2025-26 case enters the statutory standard minimum guarantee, £227.10
  a week (SPC Regs reg 6(1)(b), SI 2025/295 art. 29(2)(b)); the model's
  value differs (#1937). Guarantee Credit is £3,469.20.
- Docstring: the nil-guarantee boundary applies where no savings credit
  is payable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rtner' into tax-credits-pension-credit-passport
@MaxGhenis
MaxGhenis changed the base branch from legacy-award-readers-claimant-partner to main October 9, 2026 22:23

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tax credit income test omits the State Pension Credit passport (SI 2002/2008 reg 4(1)(d))

1 participant