Skip to content

Read only the claimant's and partner's Working Tax Credit for reg 60A - #2810

Open
MaxGhenis wants to merge 6 commits into
mainfrom
claude/wtc-reg-60a-uc-53ky4o
Open

MaxGhenis wants to merge 6 commits into
mainfrom
claude/wtc-reg-60a-uc-53ky4o

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #2805
Reproducer: policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/reg_60a_working_tax_credit.yaml::Another adult's Working Tax Credit does not open the reg 60A route for a single claimant aged 70
axiom: TheAxiomFoundation/rulespec-uk#433 queued, cases 60A-F and 60A-G: TheAxiomFoundation/rulespec-uk#433 (comment)

What the code does now

On a closure claim (claims_uc_at_legacy_closure), is_uc_eligible opens the SI 2014/1230 reg 60A route when the claimant or partner (is_claimant_or_partner) reports Working Tax Credit and a claimant meets the minimum age condition. The formula sums working_tax_credit_reported over the claimant and partner only, so either member's report counts for both. That includes a partner who can't be a joint claimant of Universal Credit (UC Regs 2013 reg 3(3)), such as a 17-year-old. A report by a child, a qualifying young person or another adult in the benefit unit no longer opens the route.

council_tax_reduction_pensioner now reads the same reports to decide whether reg 60A applies to the award. On a closure claim where the claimant or partner reports Working Tax Credit, a wholly pension-age family's Universal Credit award counts as a reg 60A award. Councils assess it under the working-age rules in Scotland in any year, in England before 2025-26 and in Wales before 2026-27, and disregard it in England from 2025-26 and in Wales from 2026-27. Where only another member reports, the formula keeps its approximation for a wholly pension-age award awaiting termination or made in error, so the family stays a pensioner family.

The law

SI 2014/1230 reg 60A(1):

Where a qualifying claim is made by— (a) a single claimant who, at the time the migration notice is issued— (i) has reached the qualifying age for state pension credit; (ii) is entitled to an award of working tax credit; and (iii) is not entitled to an award of state pension credit; or (b) joint claimants both of whom satisfy the criteria in sub-paragraph (a)(i) to (iii) at the time the migration notice is issued, then, subject to paragraphs (2) and (3), the condition in section 4(1)(b) of the Act (claimant has not reached the qualifying age for state pension credit) is not to apply for the purposes of determining entitlement to universal credit in respect of the qualifying claim or any award made in respect of that claim.

In the Tax Credits Act 2002 s.3(3), Parliament provides for a joint claim by the members of a couple "both of whom are aged at least sixteen and are in the United Kingdom", and for a single claim only by a person "not entitled to make a claim under paragraph (a)". In s.10(1) it ties Working Tax Credit entitlement to "the person or persons by whom a claim for working tax credit has been made". So both members hold the couple's award, and the claimant holds no part of an award another member claimed.

Councils in England and Wales disregard a Universal Credit award "where regulation 60A ... applies in respect of the award" (SI 2012/2885 reg 3(2)(b), from SI 2025/39 reg 4; WSI 2013/3029 reg 3(2)(b), from WSI 2026/13 reg 4). Scottish councils count a reg 60A award but not an award the claimant "was not entitled to" (SSI 2021/249 reg 3(2)(b)). So every council asks whether reg 60A applies, and the model answers that question with the same reading of whose award counts in is_uc_eligible and council_tax_reduction_pensioner.

Cases from #2805

Case Who reports £1,000 of Working Tax Credit is_uc_eligible (main) is_uc_eligible (this branch) Universal Credit (this branch)
A. Single claimant aged 70 the claimant true true £5,098.80
B. Single claimant aged 70 no one false false nil
C. Single claimant aged 70, adult aged 40 who is neither claimant nor partner the other adult true false nil
D. Single claimant aged 70, dependant aged 17 on post-secondary education the dependant true false nil
E. Couple aged 72 and 70 the partner true true £8,003.64

Invariants

  • P1. On a closure claim, a Working Tax Credit report by a member who is neither claimant nor partner never changes is_uc_eligible.
  • P2. On a closure claim, with capital within the £16,000 limit and a claimant aged 18 or over, a positive report by the claimant or partner makes the family eligible.
  • P3. Without a closure claim, zeroing every member's Working Tax Credit report never changes is_uc_eligible.
  • P4. On a closure claim, moving a Working Tax Credit report between claimant and partner never changes is_uc_eligible.

Tests

  • policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/reg_60a_working_tax_credit.yaml: cases A to E, plus a single claimant aged 70 who reports Working Tax Credit without a closure claim (not eligible), and a claimant aged 70 whose 17-year-old partner reports it (eligible, £5,098.80, the partner not a joint claimant). With main's formula, C and D fail (is_uc_eligible 1, expected 0).
  • policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_reg_60a_award_owner.yaml: five council_tax_reduction_pensioner cases. Without the change, the three cases where only another adult or a dependant reports (Scotland 2026 twice, England 2024) fail (council_tax_reduction_pensioner 0, expected 1); the cases with the claimant's or partner's own report pass either way.
  • policyengine_uk/tests/test_uc_reg_60a_working_tax_credit_properties.py: Hypothesis properties P1 to P4, plus a fixed check that, on a closure claim, zeroing a pension-age claimant's own report closes the route. Partner draws include ages 16 and 17. With main's formula, P1 fails.

At least one test kills each of these mutations of is_uc_eligible:

Mutant Killed by
Sum every member's report (main) YAML C and D; P1
Count Universal Credit claimants only YAML 17-year-old partner case; P4
Count only a claimant or partner who meets the minimum age YAML 17-year-old partner case; P4
Open the reg 60A route without a closure claim YAML no-closure-claim case; P3

Survey data

The Aggregate impact run on this PR's earlier head, which changed is_uc_eligible only, found no change to any household's net income in any year from 2025-26 to 2031-32. claims_uc_at_legacy_closure follows legacy_benefits_closed, which reads only the claimant's and partner's reports. For a family that meets the Pension Credit age conditions, the model closes tax credits only on the claimant's or partner's Working Tax Credit report, and never closes Income Support or income-based Jobseeker's Allowance for a wholly pension-age family. So on a closure claim the model derives itself, a wholly pension-age family already has the claimant's or partner's report. The change reaches a family when a user supplies claims_uc_at_legacy_closure. The change also reaches a derived case: a claimant aged 70 with a 17-year-old partner whose Income Support or Child Tax Credit the model closes, and a third member who reports Working Tax Credit. There main's formula gives is_uc_eligible true and this branch false.

The education gate (#2346, #2806)

At #2806's head (5961424461ff5ca4b7f87582d37d55314c5411b6), this branch and #2806 conflict only in is_uc_eligible's reference tuple; keep both sides' lines. On a merge that keeps both, uc_receiving_education.yaml, the reg 60A YAML and the Council Tax Reduction YAML pass 54 of 54, and the reg 60A and education property files pass 10 of 10. Once only the claimant and partner count, the education gate on this route can't change a result: a claimant or partner on the couple's award doesn't count as a qualifying young person (SI 2014/1230 reg 28), and under SI 2014/1230 reg 60(1), on a closure claim, every other claimant who receives education need not meet the education condition. Without the gate, the merged formula still passes those files and the Universal Credit and Council Tax Reduction YAML directories, so none of those tests reaches the gate. On merge, the comment on case 35 of uc_receiving_education.yaml ("the model sums reported Working Tax Credit over every member") no longer holds, though its expected values do, and whoever lands second rewrites it. #2806's property reference also sums Working Tax Credit over every member, but its draws give a report only to the claimant and partner, so it still agrees with the merged formula.

🤖 Generated with Claude Code

is_uc_eligible now sums working_tax_credit_reported over the claimant and
partner only, so a child's or another adult's report no longer opens the
reg 60A route on a closure claim. Adds YAML cases A to E from #2805 and
Hypothesis properties.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6JcN54KSxCfD7zav9D
@MaxGhenis

MaxGhenis commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator Author

Ready for hub review

Head: b442dcbdf79377a18285185e7465dfe483b9ab13 on claude/wtc-reg-60a-uc-53ky4o (the harness pins pushes to this branch), based on main at 2da212abcf2086337fc088a4a1236f4ae7b6af63. Nobody had commented on #2805 before I started, and the branch didn't exist on the remote. I posted the pickup comment on #2805.

Items

  1. Read only the claimant's and partner's reports. policyengine_uk/variables/gov/dwp/universal_credit/is_uc_eligible.py:82-97: on_working_tax_credit now sums working_tax_credit_reported * is_claimant_or_partner with benunit.sum. A partner's report still counts for both members. The comment at lines 82-88 cites TCA 2002 s.3(3)(a) and (b). The documentation string gains one sentence, and reference adds TCA 2002 s.3.
  2. Other readers on a closure route. One has the same fault, and I left it unchanged: policyengine_uk/variables/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner.py:84-88. It sets pension_age_tax_credit_migrant from claims_uc_at_legacy_closure & (add(benunit, period, ["working_tax_credit_reported"]) > 0) & ~working_age_applicant, so every member's report counts. legacy_benefits_closed and person_legacy_benefits_closed already read only the award owners' reports. The other working_tax_credit_reported readers (is_WTC_eligible, would_claim_WTC, tax_credit_award, claims_legacy_benefits, claims_all_entitled_benefits, tax-free childcare and winter heating) don't sit on the reg 60A closure route. I didn't audit them for this question.

Issue script on main (2da212a, is_in_full_time_education line removed from case D)

A single 70, own WTC 1,000: is_uc_eligible=True universal_credit=5098.80 claimants=[True] pension_age=[True]
B single 70, no WTC: is_uc_eligible=False universal_credit=0.00 claimants=[True] pension_age=[True]
C single 70; adult 40 in the benefit unit, not claimant or partner, WTC 1,000: is_uc_eligible=True universal_credit=5098.80 claimants=[True, False] pension_age=[True, False]
D single 70; dependant 17 (full-time A levels) reports WTC 1,000: is_uc_eligible=True universal_credit=9321.36 claimants=[True, False] pension_age=[True, False]
E couple 72 and 70, the 70-year-old partner reports WTC 1,000: is_uc_eligible=True universal_credit=8003.64 claimants=[True, True] pension_age=[True, True]

Tests run

  • New YAML policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/reg_60a_working_tax_credit.yaml, cases A to E, asserting is_uc_eligible and universal_credit (£5,098.80, nil, nil, nil, £8,003.64): 5 passed.
  • New policyengine_uk/tests/test_uc_reg_60a_working_tax_credit_properties.py, 3 Hypothesis properties at 10 derandomised examples each, plus one fixed sanity test: 4 passed in 115 s with -n 4.
  • YAML suites .../family/universal_credit/, .../family/housing_benefit/ and policyengine_uk/tests/policy/baseline/gov/: 4,287 passed.
  • test_mixed_age_couple_properties.py and test_housing_benefit_pension_age_properties.py, which also read is_uc_eligible: 5 passed.
  • policyengine_uk/tests/code_health: 3,087 passed.
  • ruff@0.17.2 format --check ., ruff check ., ruff check --select F811,F821 policyengine_uk and git diff --check are all clean.

Revert checks (formula stashed back to main, new tests kept)

  • YAML: cases C and D fail, each with is_uc_eligible@2026: [1.] differs from 0.0. A, B and E pass.
  • Properties: P1 (test_other_members_working_tax_credit_never_changes_closure_eligibility) fails. Hypothesis minimised it to a single claimant aged 67 with a member aged 0, who is neither claimant nor partner, reporting £1 of Working Tax Credit, at capital 0. is_uc_eligible reads true with the report and false without. P2 and P3 pass on main, as expected: they guard against over-correcting, not the bug. The fixed reference test fails on main because it asserts the model's new behaviour.
  • At first, P1 drew its generator uniformly, and 10 examples didn't find the bug on main. I then aimed it: half the adult ages fall in 67 to 100, couple reports are mostly 0, and there is always at least one other member with a positive report. After that it fails on main as shown above.

Skipped

Judgment calls

  • Case D drops is_in_full_time_education, as the brief says. With the fix, D's universal_credit is nil, so the child element plays no part.
  • P2 sets "meets the other conditions" as: a closure claim, capital of at most £15,999 (the limit is £16,000, from gov.dwp.universal_credit.means_test.capital.limit), and a claimant aged 18 or over. The test sets capital through uc_reported_capital.
  • P3 compares against the main formula, copied into the test as a reform, with claims_uc_at_legacy_closure false. A fixed test asserts that the reference differs from the model on a closure claim, so the comparison can fail.
  • I set max_examples=10 to match the repository's other property files. At 25 the file took about 4.5 minutes.
  • The Reproducer: line names YAML case C.

CI (one check of b442dcbd, about 25 minutes after opening)

Passed: Test / YAML, Fix evidence, Changelog fragments, Lint, Documentation build, Install + smoke-import (py3.11 to py3.14), Release build records the commit, Changes. Still in progress at the check: Test / Python 1/6 to 6/6, Aggregate impact (and so Test / Result). No failure has appeared so far, and I've pushed nothing since opening.


Generated by Claude Code

@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Aggregate impact on certified data: pass

Base acba5efc1f against head 18ed650df9, both on enhanced_frs_2024_25.h5 (policyengine-uk-data 1.58.1, sha256 056e80fd8e91), fiscal years 2025-26 to 2031-32. Each year is a full microsimulation run on each side.

Checks: 0 broken by this change, 1 failing on both sides, 0 fixed. Moves flagged for review: 0 (thresholds in report_spec.yaml; a flag does not fail the job).

Workflow run and full report

Notes

  • In the years a figure from fewer than 10 records is suppressed (spending.disabled_students_allowance), every total containing it, and the decile incomes, are rebuilt from their other components, so no published total includes it. Those totals are marked †. A change is withheld where the two sides leave out different figures and can't be lined up.

Moves flagged for review

None.

Spending by benefit and service

Measure 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Disabled Students' Allowance suppressed suppressed suppressed suppressed suppressed suppressed suppressed

Caseloads

Measure 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Disabled Students' Allowance suppressed suppressed suppressed suppressed suppressed suppressed suppressed

Household net income by decile

No household's net income changes in any year.

No change in any year: receipts by tax head; government balance, each component counted once; model totals; household income totals; population; poverty rates; people in poverty; inequality; mean household net income in each side's own deciles; standard reform costings (change in gov_balance); standard reforms: change in each reform's target.

Checks failing on both base and head (1)
  • VAT excluding private school fees is never negative (sign:vat): 2025-26: 76 units below zero, a weighted £-53,888,684 in total; 2026-27: 76 units below zero, a weighted £-55,777,260 in total; 2027-28: 76 units below zero, a weighted £-57,727,917 in total
Counted-once check

Each of 92 components was raised by £1 per unit in 2026-27, and every head of its totals was read household by household: its own head must rise by exactly £1, no other tax head may move, no other benefit may rise, and the model's own total must move by what its heads moved. A head that breaks a rule is measured again twice: with every other head held at its baseline value, and with every other head held at its value after the first £1 while the component rises again. It fails where either still shows the response. 0 failed; 0 were skipped.

  • widowed_parents_allowance: pension_credit responds only through other heads in fewer than 10 households (other heads that moved there: carers_allowance; gov_spending; not a failure)
  • widowed_parents_allowance: pension_credit responds only through other heads in fewer than 10 households (other heads that moved there: carers_allowance; household_benefits; not a failure)
Provenance
Side Commit Runtime Environment hash Partition hash Time
base main acba5efc1f uk 2.174.2 (files 50346e2bf8ca), core 3.34.1, py 3.13.18 aarch64 b97ad1ec1621 7cb61324a46b 2168.28s
head #2810 merged into main 18ed650df9 uk 2.174.2 (files bd094ba00cef), core 3.34.1, py 3.13.18 aarch64 b97ad1ec1621 7cb61324a46b 2244.28s

Dataset: hf://policyengine/policyengine-uk-data-private/enhanced_frs_2024_25.h5@2526edbbb687a3b54dbb11272e5389e4b62d2ac2, sha256 056e80fd8e9151d78f432a25cde863340baee81304c6216a37fb575ce8563784 (verified on both sides), policyengine-uk-data 1.58.1.

Receipts by tax head: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Final charge on cash interest in non-cash ISAs £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Lifetime ISA withdrawal charge £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Income tax £294.46bn £315.23bn £335.82bn £351.28bn £366.96bn £385.36bn £400.00bn
National Insurance (employee and self-employed) £51.70bn £54.14bn £56.13bn £57.73bn £59.76bn £61.64bn £63.51bn
National Insurance (employer) £148.71bn £155.37bn £160.88bn £165.09bn £172.06bn £177.36bn £182.57bn
Employer NI change borne by capital £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Employer NI change borne by consumers £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Capital gains tax £12.60bn £13.15bn £13.60bn £14.11bn £14.67bn £15.24bn £15.80bn
Student loan repayments £7.82bn £8.13bn £8.39bn £8.58bn £8.79bn £9.04bn £9.29bn
VAT excluding private school fees £249.37bn £256.87bn £266.33bn £272.70bn £278.97bn £285.24bn £291.59bn
Change in VAT from its baseline £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
VAT on private school fees £1.95bn £2.01bn £2.09bn £2.14bn £2.20bn £2.26bn £2.31bn
Change in private school VAT from its baseline £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Fuel duties £24.71bn £24.13bn £26.00bn £26.83bn £26.51bn £25.78bn £24.63bn
Alcohol duties £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Tobacco duties £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Vehicle excise duties £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Betting and gaming duties £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
TV licence fee £4.26bn £4.40bn £4.41bn £4.42bn £4.43bn £4.44bn £4.45bn
Council tax £49.21bn £52.16bn £54.89bn £57.95bn £61.16bn £64.47bn £67.91bn
High value council tax surcharge £0.00bn £0.00bn £0.00bn £0.48bn £0.49bn £0.50bn £0.51bn
Northern Ireland domestic rates £0.55bn £0.58bn £0.60bn £0.63bn £0.66bn £0.69bn £0.72bn
Business rates £34.68bn £36.20bn £38.00bn £39.46bn £42.27bn £43.25bn £44.29bn
Stamp duty land tax on the household's own purchases £6.88bn £7.32bn £7.66bn £8.06bn £8.47bn £8.91bn £9.35bn
Stamp duty land tax paid by companies £4.72bn £4.57bn £5.29bn £6.03bn £6.37bn £6.92bn £7.45bn
Land transaction tax (Wales) £0.07bn £0.08bn £0.08bn £0.09bn £0.10bn £0.10bn £0.11bn
Land and buildings transaction tax (Scotland) £0.31bn £0.32bn £0.33bn £0.35bn £0.36bn £0.38bn £0.40bn
Unspecified tax change borne by capital £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Unspecified tax change borne by consumers £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Wealth tax £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Wealth tax excluding the main residence £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Land value tax £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Carbon tax £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Spending by benefit and service: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Lifetime ISA bonus £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
State Pension £121.68bn £125.92bn £126.72bn £129.49bn £132.99bn £136.66bn £140.42bn
Pension Credit £6.21bn £6.46bn £6.68bn £6.82bn £6.89bn £7.07bn £7.22bn
Winter Fuel Payment £1.86bn £1.85bn £1.79bn £1.77bn £1.78bn £1.78bn £1.78bn
Pension Age Winter Heating Payment (Scotland) £0.19bn £0.20bn £0.20bn £0.21bn £0.21bn £0.22bn £0.22bn
Universal Credit £75.48bn £80.52bn £82.95bn £84.96bn £86.11bn £87.61bn £88.21bn
Housing Benefit £8.56bn £8.89bn £9.23bn £9.46bn £9.69bn £9.99bn £10.27bn
Council Tax Reduction £2.07bn £2.20bn £2.32bn £2.45bn £2.59bn £2.73bn £2.87bn
Employment and Support Allowance (income-related) £0.79bn £0.82bn £0.84bn £0.86bn £0.88bn £0.90bn £0.92bn
Employment and Support Allowance (contribution-based) £5.20bn £5.37bn £5.56bn £5.69bn £5.82bn £5.95bn £6.09bn
Jobseeker's Allowance (income-based) £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Jobseeker's Allowance (contribution-based) £0.29bn £0.30bn £0.31bn £0.31bn £0.32bn £0.33bn £0.34bn
Income Support £0.11bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Working Tax Credit £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Child Tax Credit £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Incapacity Benefit £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Personal Independence Payment £26.95bn £28.03bn £29.05bn £30.09bn £30.75bn £31.51bn £32.21bn
Disability Living Allowance £7.49bn £7.79bn £8.07bn £8.36bn £8.55bn £8.76bn £8.95bn
Attendance Allowance £8.68bn £9.03bn £9.36bn £9.69bn £9.90bn £10.15bn £10.38bn
Carer's Allowance £4.48bn £4.66bn £4.83bn £5.00bn £5.11bn £5.27bn £5.42bn
Carer Support Payment (Scotland) £0.31bn £0.32bn £0.33bn £0.34bn £0.35bn £0.36bn £0.37bn
Carer's Allowance Supplement (Scotland) £0.00bn £0.04bn £0.04bn £0.05bn £0.05bn £0.05bn £0.05bn
Severe Disablement Allowance £0.03bn £0.03bn £0.03bn £0.03bn £0.03bn £0.03bn £0.03bn
Industrial Injuries Disablement Benefit £0.50bn £0.52bn £0.54bn £0.55bn £0.56bn £0.58bn £0.59bn
Armed Forces Compensation Scheme £0.61bn £0.63bn £0.65bn £0.66bn £0.68bn £0.69bn £0.71bn
War Widow's or Widower's Pension £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Child Benefit £16.19bn £16.82bn £17.39bn £18.00bn £18.39bn £18.84bn £19.25bn
Scottish Child Payment £0.49bn £0.52bn £0.53bn £0.55bn £0.56bn £0.57bn £0.56bn
Two Child Limit Payment (Scotland, counterfactual) £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Healthy Start vouchers £0.05bn £0.05bn £0.05bn £0.05bn £0.05bn £0.05bn £0.05bn
Maternity Allowance £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Statutory Maternity Pay £3.30bn £3.41bn £3.54bn £3.62bn £3.70bn £3.78bn £3.87bn
Statutory Paternity Pay £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Statutory Sick Pay £1.12bn £1.16bn £1.20bn £1.23bn £1.26bn £1.29bn £1.32bn
Sure Start Maternity Grant £0.01bn £0.01bn £0.01bn £0.01bn £0.01bn £0.01bn £0.01bn
Bereavement Support Payment £0.67bn £0.69bn £0.71bn £0.73bn £0.75bn £0.76bn £0.78bn
Widowed Parent's Allowance £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Tax-Free Childcare £0.56bn £0.57bn £0.57bn £0.58bn £0.60bn £0.61bn £0.59bn
Extended childcare entitlement £2.99bn £3.50bn £3.59bn £3.71bn £3.78bn £3.86bn £3.93bn
Universal childcare entitlement £2.06bn £2.22bn £2.29bn £2.37bn £2.43bn £2.48bn £2.53bn
Targeted childcare entitlement £0.50bn £0.51bn £0.52bn £0.54bn £0.55bn £0.57bn £0.56bn
Childcare Offer for Wales £0.26bn £0.28bn £0.28bn £0.29bn £0.30bn £0.31bn £0.32bn
Care to Learn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Childcare Grant £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Parents' Learning Allowance £0.20bn £0.20bn £0.20bn £0.20bn £0.20bn £0.20bn £0.20bn
Adult Dependants' Grant £0.06bn £0.06bn £0.04bn £0.04bn £0.04bn £0.04bn £0.04bn
Travel Grant £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Disabled Students' Allowance suppressed suppressed suppressed suppressed suppressed suppressed suppressed
16 to 19 Bursary Fund £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
NHS spending £203.89bn £204.30bn £204.56bn £204.91bn £205.34bn £205.85bn £206.35bn
State education spending £0.02bn £0.02bn £0.02bn £0.02bn £0.02bn £0.02bn £0.02bn
Transport subsidy spending £25.05bn £25.10bn £25.14bn £25.18bn £25.23bn £25.30bn £25.36bn
Cost-of-living support payment £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Energy Bills Rebate £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Household Energy Payment £0.00bn £2.11bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Energy Price Guarantee subsidy £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Basic income £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Disability basic income £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Other public spending budget change £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Caseloads: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Lifetime ISA bonus 0k 0k 0k 0k 0k 0k 0k
State Pension 11,264k 11,145k 10,819k 10,700k 10,723k 10,750k 10,776k
Pension Credit 1,489k 1,484k 1,476k 1,454k 1,452k 1,457k 1,466k
Winter Fuel Payment 7,844k 7,783k 7,473k 7,375k 7,391k 7,409k 7,427k
Pension Age Winter Heating Payment (Scotland) 803k 802k 800k 797k 799k 801k 802k
Universal Credit 6,342k 6,347k 6,336k 6,297k 6,292k 6,271k 6,223k
Housing Benefit 1,249k 1,245k 1,244k 1,227k 1,227k 1,229k 1,232k
Council Tax Reduction 3,180k 3,200k 3,206k 3,219k 3,234k 3,245k 3,252k
Employment and Support Allowance (income-related) 71k 71k 71k 71k 71k 71k 71k
Employment and Support Allowance (contribution-based) 719k 720k 721k 722k 724k 726k 728k
Jobseeker's Allowance (income-based) 0k 0k 0k 0k 0k 0k 0k
Jobseeker's Allowance (contribution-based) 67k 67k 67k 67k 67k 68k 68k
Income Support 25k 0k 0k 0k 0k 0k 0k
Working Tax Credit 0k 0k 0k 0k 0k 0k 0k
Child Tax Credit 0k 0k 0k 0k 0k 0k 0k
Incapacity Benefit 0k 0k 0k 0k 0k 0k 0k
Personal Independence Payment 3,567k 3,575k 3,579k 3,585k 3,593k 3,602k 3,611k
Disability Living Allowance 1,291k 1,294k 1,296k 1,298k 1,300k 1,304k 1,307k
Attendance Allowance 1,695k 1,698k 1,700k 1,703k 1,707k 1,711k 1,715k
Carer's Allowance 1,034k 1,037k 1,038k 1,040k 1,042k 1,060k 1,062k
Carer Support Payment (Scotland) 71k 71k 71k 72k 72k 72k 72k
Carer's Allowance Supplement (Scotland) 0k 71k 71k 72k 72k 72k 72k
Severe Disablement Allowance 4k 4k 4k 4k 4k 4k 4k
Industrial Injuries Disablement Benefit 137k 137k 137k 138k 138k 138k 139k
Armed Forces Compensation Scheme 93k 93k 94k 94k 94k 94k 94k
War Widow's or Widower's Pension 0k 0k 0k 0k 0k 0k 0k
Child Benefit 8,123k 8,120k 8,120k 8,130k 8,145k 8,161k 8,178k
Scottish Child Payment 351k 352k 352k 353k 350k 348k 337k
Two Child Limit Payment (Scotland, counterfactual) 0k 0k 0k 0k 0k 0k 0k
Healthy Start vouchers 200k 200k 200k 201k 201k 201k 202k
Maternity Allowance 0k 0k 0k 0k 0k 0k 0k
Statutory Maternity Pay 333k 333k 334k 334k 335k 336k 337k
Statutory Paternity Pay 0k 0k 0k 0k 0k 0k 0k
Statutory Sick Pay 181k 182k 182k 182k 182k 183k 183k
Sure Start Maternity Grant 26k 26k 26k 26k 26k 26k 26k
Bereavement Support Payment 98k 98k 98k 98k 98k 99k 99k
Widowed Parent's Allowance 0k 0k 0k 0k 0k 0k 0k
Tax-Free Childcare 1,043k 1,027k 1,014k 1,009k 1,011k 1,009k 993k
Extended childcare entitlement 795k 800k 796k 797k 798k 798k 792k
Universal childcare entitlement 1,071k 1,072k 1,072k 1,073k 1,076k 1,079k 1,074k
Targeted childcare entitlement 165k 156k 154k 154k 155k 155k 150k
Childcare Offer for Wales 39k 39k 39k 39k 39k 39k 39k
Care to Learn 0k 0k 0k 0k 0k 0k 0k
Childcare Grant 0k 0k 0k 0k 0k 0k 0k
Parents' Learning Allowance 98k 98k 98k 99k 99k 99k 99k
Adult Dependants' Grant 18k 18k 12k 12k 12k 12k 12k
Travel Grant 0k 0k 0k 0k 0k 0k 0k
Disabled Students' Allowance suppressed suppressed suppressed suppressed suppressed suppressed suppressed
16 to 19 Bursary Fund 0k 0k 0k 0k 0k 0k 0k
Cost-of-living support payment 0k 0k 0k 0k 0k 0k 0k
Energy Bills Rebate 0k 0k 0k 0k 0k 0k 0k
Household Energy Payment 0k 21,065k 0k 0k 0k 0k 0k
Energy Price Guarantee subsidy 0k 0k 0k 0k 0k 0k 0k
Basic income 0k 0k 0k 0k 0k 0k 0k
Disability basic income 0k 0k 0k 0k 0k 0k 0k
Government balance, each component counted once: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Government receipts, each component once £892.00bn £934.66bn £980.50bn £1,015.93bn £1,054.24bn £1,091.56bn £1,124.89bn
Government spending £528.93bn † £545.10bn † £550.16bn † £558.85bn † £566.49bn † £575.19bn † £582.79bn †
Government balance, each receipt once £363.07bn † £389.56bn † £430.34bn † £457.07bn † £487.75bn † £516.37bn † £542.10bn †
Benefits in household_benefits but not in gov_spending £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Model totals: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
gov_tax £892.00bn £934.66bn £980.50bn £1,015.93bn £1,054.24bn £1,091.56bn £1,124.89bn
household_tax £491.97bn £520.41bn £551.21bn £576.01bn £601.00bn £626.70bn £648.42bn
pre_budget_change_household_tax £484.15bn £512.28bn £542.82bn £566.95bn £591.72bn £617.16bn £638.61bn
gov_spending £528.93bn † £545.10bn † £550.16bn † £558.85bn † £566.49bn † £575.19bn † £582.79bn †
household_benefits £528.93bn † £545.10bn † £550.16bn † £558.85bn † £566.49bn † £575.19bn † £582.79bn †
gov_balance £363.07bn † £389.56bn † £430.34bn † £457.07bn † £487.75bn † £516.37bn † £542.10bn †
Household income totals: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Household market income £1,637.96bn £1,702.77bn £1,757.35bn £1,806.41bn £1,855.97bn £1,912.43bn £1,970.44bn
Household net income £1,636.24bn † £1,687.26bn † £1,714.85bn † £1,746.84bn † £1,777.99bn † £1,816.26bn † £1,858.88bn †
Household net income (HBAI definition) £1,449.13bn £1,499.27bn £1,530.26bn £1,564.52bn £1,597.18bn £1,634.84bn £1,675.81bn
Population: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
People 69,245k 69,383k 69,473k 69,592k 69,738k 69,912k 70,080k
Benefit units 35,110k 35,181k 35,226k 35,286k 35,360k 35,449k 35,534k
Households 31,046k 31,108k 31,149k 31,201k 31,267k 31,345k 31,420k
Poverty rates: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Absolute poverty, before housing costs: everyone 16.3% 15.5% 16.4% 16.3% 16.5% 16.5% 16.6%
Absolute poverty, before housing costs: children 24.7% 22.1% 23.3% 22.9% 23.1% 23.2% 23.5%
Absolute poverty, before housing costs: working-age adults 14.1% 13.8% 14.7% 14.7% 14.8% 14.8% 15.0%
Absolute poverty, before housing costs: pensioners 13.7% 13.4% 14.0% 13.8% 13.9% 13.9% 13.9%
Absolute poverty, after housing costs: everyone 21.6% 21.0% 22.0% 22.6% 22.9% 23.1% 23.4%
Absolute poverty, after housing costs: children 33.3% 31.3% 32.3% 32.5% 32.9% 33.4% 34.2%
Absolute poverty, after housing costs: working-age adults 19.9% 19.8% 20.8% 21.6% 21.9% 22.0% 22.3%
Absolute poverty, after housing costs: pensioners 12.7% 12.4% 13.1% 13.2% 13.3% 13.4% 13.6%
Relative poverty, before housing costs: everyone 17.0% 16.0% 16.4% 16.3% 16.4% 16.3% 16.6%
Relative poverty, before housing costs: children 25.9% 22.9% 23.3% 22.9% 23.0% 22.9% 23.5%
Relative poverty, before housing costs: working-age adults 14.5% 14.1% 14.6% 14.7% 14.7% 14.7% 15.0%
Relative poverty, before housing costs: pensioners 14.5% 14.0% 13.9% 13.8% 13.8% 13.9% 13.9%
Relative poverty, after housing costs: everyone 21.5% 21.0% 21.3% 21.3% 21.3% 21.5% 21.7%
Relative poverty, after housing costs: children 33.1% 31.1% 31.2% 31.0% 31.1% 31.2% 31.8%
Relative poverty, after housing costs: working-age adults 19.9% 19.8% 20.2% 20.4% 20.5% 20.6% 20.8%
Relative poverty, after housing costs: pensioners 12.5% 12.4% 12.2% 11.7% 11.7% 11.8% 12.0%
People in poverty: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Absolute poverty, before housing costs: everyone 11,277k 10,778k 11,402k 11,364k 11,475k 11,512k 11,650k
Absolute poverty, before housing costs: children 3,688k 3,314k 3,496k 3,445k 3,480k 3,502k 3,549k
Absolute poverty, before housing costs: working-age adults 5,965k 5,893k 6,308k 6,362k 6,420k 6,430k 6,521k
Absolute poverty, before housing costs: pensioners 1,624k 1,571k 1,597k 1,558k 1,575k 1,580k 1,580k
Absolute poverty, after housing costs: everyone 14,944k 14,599k 15,310k 15,721k 15,936k 16,140k 16,426k
Absolute poverty, after housing costs: children 4,975k 4,682k 4,837k 4,888k 4,945k 5,040k 5,179k
Absolute poverty, after housing costs: working-age adults 8,463k 8,461k 8,971k 9,344k 9,491k 9,584k 9,706k
Absolute poverty, after housing costs: pensioners 1,506k 1,456k 1,501k 1,489k 1,501k 1,517k 1,541k
Relative poverty, before housing costs: everyone 11,750k 11,084k 11,387k 11,364k 11,416k 11,416k 11,654k
Relative poverty, before housing costs: children 3,872k 3,423k 3,496k 3,445k 3,466k 3,454k 3,551k
Relative poverty, before housing costs: working-age adults 6,159k 6,013k 6,301k 6,362k 6,389k 6,389k 6,523k
Relative poverty, before housing costs: pensioners 1,719k 1,648k 1,590k 1,557k 1,561k 1,573k 1,580k
Relative poverty, after housing costs: everyone 14,864k 14,552k 14,777k 14,809k 14,872k 15,012k 15,232k
Relative poverty, after housing costs: children 4,944k 4,660k 4,673k 4,663k 4,679k 4,707k 4,806k
Relative poverty, after housing costs: working-age adults 8,431k 8,440k 8,711k 8,823k 8,873k 8,967k 9,062k
Relative poverty, after housing costs: pensioners 1,489k 1,452k 1,392k 1,323k 1,321k 1,338k 1,364k
Inequality: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Gini coefficient, equivalised HBAI income before housing costs 0.3078 0.3050 0.3056 0.3055 0.3060 0.3066 0.3082
Mean household net income in each side's own deciles: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Decile 1: mean household_net_income per household £17,681 † £17,998 † £17,915 † £18,152 † £18,308 † £18,531 † £18,717 †
Decile 2: mean household_net_income per household £27,942 † £29,026 † £28,716 † £29,017 † £29,280 † £29,695 † £30,157 †
Decile 3: mean household_net_income per household £34,316 † £35,481 † £36,069 † £36,607 † £37,195 † £37,733 † £38,183 †
Decile 4: mean household_net_income per household £38,934 † £40,684 † £41,726 † £42,729 † £43,331 † £44,130 † £44,432 †
Decile 5: mean household_net_income per household £43,235 † £45,581 † £46,012 † £46,961 † £47,713 † £48,725 † £50,296 †
Decile 6: mean household_net_income per household £47,931 † £49,202 † £50,891 † £51,936 † £52,936 † £53,820 † £54,664 †
Decile 7: mean household_net_income per household £55,659 † £56,569 † £57,437 † £57,642 † £58,733 † £59,661 † £61,087 †
Decile 8: mean household_net_income per household £68,784 † £70,802 † £71,864 † £73,512 † £73,886 † £75,319 † £77,177 †
Decile 9: mean household_net_income per household £78,889 † £81,012 † £80,859 † £82,645 † £85,463 † £86,945 † £89,508 †
Decile 10: mean household_net_income per household £116,861 † £120,161 † £124,545 † £126,420 † £125,753 † £128,368 † £130,693 †
Standard reform costings (change in gov_balance): head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Raise basic rate by 1pp £6.41bn £6.66bn £6.63bn £6.85bn £7.03bn £7.25bn £7.49bn
Raise higher rate by 1pp £3.61bn £3.87bn £4.00bn £4.22bn £4.44bn £4.71bn £4.83bn
Raise personal allowance by ~800GBP/year £-3.81bn £-3.93bn £-3.99bn £-4.05bn £-4.11bn £-4.24bn £-1.95bn
Raise child benefit by 25GBP/week per additional child £-1.99bn £-1.75bn £-1.55bn £-1.38bn £-1.30bn £-1.18bn £-1.07bn
Reduce Universal Credit taper rate to 20% £-20.77bn £-21.32bn £-21.75bn £-22.00bn £-22.35bn £-22.75bn £-22.94bn
Raise Class 1 main employee NICs rate to 10% £10.89bn £11.30bn £11.71bn £12.01bn £12.31bn £12.62bn £13.00bn
Raise VAT standard rate by 2pp £24.89bn £25.71bn £26.63bn £27.24bn £27.87bn £28.50bn £29.14bn
Raise additional rate by 3pp £2.90bn £3.15bn £3.22bn £3.41bn £3.61bn £3.85bn £4.14bn
Raise the Universal Credit standard allowance by 10% £-3.06bn £-3.18bn £-3.26bn £-3.35bn £-3.44bn £-3.49bn £-3.50bn
Raise the State Pension by 10% £-7.76bn £-8.00bn £-8.22bn £-8.45bn £-8.80bn £-8.53bn £-8.87bn
Standard reforms: change in each reform's target: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Raise basic rate by 1pp: change in income_tax £6.55bn £6.86bn £6.79bn £7.00bn £7.20bn £7.44bn £7.66bn
Raise higher rate by 1pp: change in income_tax £3.61bn £3.92bn £4.01bn £4.23bn £4.45bn £4.72bn £4.84bn
Raise personal allowance by ~800GBP/year: change in income_tax £-3.93bn £-4.07bn £-4.13bn £-4.18bn £-4.22bn £-4.40bn £-1.75bn
Raise child benefit by 25GBP/week per additional child: change in child_benefit £2.33bn £2.14bn £1.94bn £1.76bn £1.65bn £1.52bn £1.40bn
Reduce Universal Credit taper rate to 20%: change in universal_credit £20.74bn £21.31bn £21.79bn £22.05bn £22.37bn £22.78bn £22.99bn
Raise Class 1 main employee NICs rate to 10%: change in national_insurance £11.15bn £11.63bn £12.00bn £12.29bn £12.61bn £12.94bn £13.31bn
Raise VAT standard rate by 2pp: change in vat £24.69bn £25.51bn £26.42bn £27.03bn £27.65bn £28.28bn £28.91bn
Raise additional rate by 3pp: change in income_tax £2.90bn £3.15bn £3.22bn £3.42bn £3.62bn £3.86bn £4.12bn
Raise the Universal Credit standard allowance by 10%: change in universal_credit £3.06bn £3.19bn £3.28bn £3.37bn £3.43bn £3.49bn £3.51bn
Raise the State Pension by 10%: change in state_pension £10.68bn £11.17bn £11.28bn £11.60bn £12.03bn £12.47bn £12.97bn

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Picking this up for the UK hub. Reply here if you're mid-change and I'll stop.


Generated by Claude Code

council_tax_reduction_pensioner now recognises a reg 60A award only where
the claimant or partner reports Working Tax Credit, as is_uc_eligible does.
Adds Council Tax Reduction cases for Scotland 2026 and England 2024, a UC
case with no closure claim and a UC case with a 17-year-old partner's
report. Restates P3 as an invariant that needs no reference formula and
widens partner draws to ages 16 and 17. Corrects the Tax Credits Act
citations and adds reg 60A(1)(a)(iii) to the headers and docstring.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6KMhHstAXQyqiYRAcW
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

PR_TITLE.txt

Read only the claimant's and partner's Working Tax Credit for reg 60A

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

PR_BODY.md

Fixes #2805
Reproducer: policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/reg_60a_working_tax_credit.yaml::Another adult's Working Tax Credit does not open the reg 60A route for a single claimant aged 70
axiom: hub fills this line

## What the code does now

On a closure claim (`claims_uc_at_legacy_closure`), `is_uc_eligible` opens the SI 2014/1230 reg 60A route when the claimant or partner (`is_claimant_or_partner`) reports Working Tax Credit and a claimant meets the minimum age condition. The formula sums `working_tax_credit_reported` over the claimant and partner only, so either member's report counts for both. That includes a partner who can't be a joint claimant of Universal Credit (UC Regs 2013 reg 3(3)), such as a 17-year-old. A report by a child, a qualifying young person or another adult in the benefit unit no longer opens the route.

`council_tax_reduction_pensioner` now reads the same reports to decide whether reg 60A applies to the award. Where the claimant or partner reports Working Tax Credit, a wholly pension-age family's Universal Credit award counts as a reg 60A award: Scotland in any year, England before 2025-26 and Wales before 2026-27 assess it under the working-age rules, and England and Wales disregard it after those dates. Where only another member reports, the formula keeps its approximation for a wholly pension-age award awaiting termination or made in error, so the family stays a pensioner family.

## The law

[SI 2014/1230 reg 60A(1)](https://www.legislation.gov.uk/uksi/2014/1230/regulation/60A), as quoted in #2805:

> Where a qualifying claim is made by— (a) a single claimant who, at the time the migration notice is issued— (i) has reached the qualifying age for state pension credit; (ii) is entitled to an award of working tax credit; and (iii) is not entitled to an award of state pension credit; or (b) joint claimants both of whom satisfy the criteria in sub-paragraph (a)(i) to (iii) at the time the migration notice is issued, then, subject to paragraphs (2) and (3), the condition in section 4(1)(b) of the Act (claimant has not reached the qualifying age for state pension credit) is not to apply ...

Under the [Tax Credits Act 2002 s.3(3)](https://www.legislation.gov.uk/ukpga/2002/21/section/3), a couple both aged 16 or over and in the UK must claim a tax credit together, and [s.10(1)](https://www.legislation.gov.uk/ukpga/2002/21/section/10) ties entitlement to "the person or persons by whom a claim ... has been made". So both members hold the couple's award, and the claimant holds no part of an award another member claimed.

Council Tax Reduction in England and Wales disregards a Universal Credit award "where regulation 60A ... applies in respect of the award" ([SI 2012/2885 reg 3(2)(b)](https://www.legislation.gov.uk/uksi/2012/2885/regulation/3), from [SI 2025/39 reg 4](https://www.legislation.gov.uk/uksi/2025/39/regulation/4); [WSI 2013/3029 reg 3(2)(b)](https://www.legislation.gov.uk/wsi/2013/3029/regulation/3), from [WSI 2026/13 reg 4](https://www.legislation.gov.uk/wsi/2026/13/regulation/4)). In Scotland, [SSI 2021/249 reg 3(2)(b)](https://www.legislation.gov.uk/ssi/2021/249/regulation/3) counts a reg 60A award but not an award the claimant "was not entitled to". Both tests turn on whether reg 60A applies, so the same reading of whose award counts decides both.

## Cases from #2805

| Case | Who reports £1,000 of Working Tax Credit | `is_uc_eligible` (`main`) | `is_uc_eligible` (this branch) | Universal Credit (this branch) |
|---|---|---|---|---:|
| A. Single claimant aged 70 | the claimant | true | true | £5,098.80 |
| B. Single claimant aged 70 | no one | false | false | nil |
| C. Single claimant aged 70, adult aged 40 who is neither claimant nor partner | the other adult | true | false | nil |
| D. Single claimant aged 70, dependant aged 17 on post-secondary education | the dependant | true | false | nil |
| E. Couple aged 72 and 70 | the partner | true | true | £8,003.64 |

## Invariants

- P1. On a closure claim, a Working Tax Credit report by a member who is neither claimant nor partner never changes `is_uc_eligible`.
- P2. On a closure claim, with capital within the £16,000 limit and a claimant aged 18 or over, a positive report by the claimant or partner makes the family eligible.
- P3. Without a closure claim, zeroing every member's Working Tax Credit report never changes `is_uc_eligible`.

## Tests

- `policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/reg_60a_working_tax_credit.yaml`: cases A to E, plus a single claimant aged 70 who reports Working Tax Credit without a closure claim (not eligible), and a claimant aged 70 whose 17-year-old partner reports it (eligible, £5,098.80, the partner not a joint claimant). With `main`'s formula, C and D fail (`is_uc_eligible` 1, expected 0).
- `policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_reg_60a_award_owner.yaml`: five `council_tax_reduction_pensioner` cases. Without the change, the three cases where only another adult or a dependant reports (Scotland 2026 twice, England 2024) fail (`council_tax_reduction_pensioner` 0, expected 1); the claimant's and partner's own reports pass either way.
- `policyengine_uk/tests/test_uc_reg_60a_working_tax_credit_properties.py`: Hypothesis properties P1 to P3, plus a fixed check that, on a closure claim, zeroing a pension-age claimant's own report closes the route. Partner draws include ages 16 and 17. With `main`'s formula, P1 fails.

Mutation checks on `is_uc_eligible`, each killed by at least one test:

| Mutant | Killed by |
|---|---|
| Sum every member's report (`main`) | YAML C and D; P1 |
| Count Universal Credit claimants only | YAML 17-year-old partner case |
| Count only a claimant or partner who meets the minimum age | YAML 17-year-old partner case |
| Open the reg 60A route without a closure claim | YAML no-closure-claim case; P3 |

## Survey data

The Aggregate impact run on this PR's earlier head, which changed `is_uc_eligible` only, found no change to any household's net income in any year from 2025-26 to 2031-32. `claims_uc_at_legacy_closure` follows `legacy_benefits_closed`, which reads only the claimant's and partner's reports. For a family that meets the Pension Credit age conditions, the model closes tax credits only on the claimant's or partner's Working Tax Credit report, and never closes Income Support or income-based Jobseeker's Allowance for a wholly pension-age family. So on a closure claim the model derives itself, a wholly pension-age family already has the claimant's or partner's report. The change reaches a family when a user supplies `claims_uc_at_legacy_closure`, or in a contrived derived case: a claimant aged 70 with a 17-year-old partner moved off Income Support and a third member who reports Working Tax Credit, where `main`'s formula gives `is_uc_eligible` true and this branch false.

## Note on the education gate (#2346, PR #2806)

This branch and #2806 conflict only in `is_uc_eligible`'s `reference` tuple; keep both sides' lines. With that resolved, `uc_receiving_education.yaml`, the reg 60A YAML and the Council Tax Reduction YAML pass 47 of 47, and the property file passes 4 of 4. Once only the claimant and partner count, the education gate on this route can't change a result: a claimant or partner on the couple's award doesn't count as a qualifying young person (reg 28), and under reg 60(1), on a closure claim, every other claimant who receives education need not meet the education condition. No test then reaches the gate. On merge, the comment on case 35 of `uc_receiving_education.yaml` ("the model sums reported Working Tax Credit over every member") no longer holds, though its expected values do, and whoever lands second rewrites it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

AXIOM_ISSUE.md

Title: uksi/2014/1230 reg 60A: whose Working Tax Credit award meets reg 60A(1)(a)(ii)

Labels: pe-parity

## Module and corpus

- Module: `uk/regulations/uksi/2014/1230/60A.yaml`, the module rulespec-uk#433 queues (cases 60A-A to 60A-E). This issue extends #433 with cases 60A-F and 60A-G.
- Corpus: SI 2014/1230 reg 60A(1) (https://www.legislation.gov.uk/uksi/2014/1230/regulation/60A); Tax Credits Act 2002 s.3(3) (https://www.legislation.gov.uk/ukpga/2002/21/section/3) and s.10(1) (https://www.legislation.gov.uk/ukpga/2002/21/section/10).
- PolicyEngine: PolicyEngine/policyengine-uk#2805, fixed by PolicyEngine/policyengine-uk#2810 (`is_uc_eligible`, `council_tax_reduction_pensioner`).

## The law

SI 2014/1230 reg 60A(1):

> Where a qualifying claim is made by— (a) a single claimant who, at the time the migration notice is issued— (i) has reached the qualifying age for state pension credit; (ii) is entitled to an award of working tax credit; and (iii) is not entitled to an award of state pension credit; or (b) joint claimants both of whom satisfy the criteria in sub-paragraph (a)(i) to (iii) at the time the migration notice is issued, then, subject to paragraphs (2) and (3), the condition in section 4(1)(b) of the Act (claimant has not reached the qualifying age for state pension credit) is not to apply for the purposes of determining entitlement to universal credit in respect of the qualifying claim or any award made in respect of that claim.

Tax Credits Act 2002 s.10(1) ties entitlement to "the person or persons by whom a claim ... has been made". Under s.3(3), a couple both aged 16 or over and in the UK must claim a tax credit together (paraphrase; the encoder quotes s.3(3) from the corpus).

## Required outputs

For each claimant on a qualifying claim, at the time the migration notice is issued:

- `holds_working_tax_credit_award`: `holds` where the claimant made, alone or jointly with a partner, the claim under which the Working Tax Credit award was made (s.10(1)); `not_holds` otherwise, including where only another member of the household made the claim.
- `reg_60a_waiver_applies`: true where reg 60A(1)(a) holds for the single claimant, or (a)(i) to (iii) hold for both joint claimants; false otherwise. Paragraphs (2) and (3) stay out of scope here.

## Companion cases

Worked by hand from the law above.

| Case | Facts at the time the migration notice is issued | `holds_working_tax_credit_award` | `reg_60a_waiver_applies` | Why |
|---|---|---|---|---|
| 60A-F | Single claimant aged 70, past the qualifying age for State Pension Credit, entitled to no State Pension Credit and party to no tax credit claim. Another adult aged 40 in the household, who is not the claimant's partner, made a Working Tax Credit claim alone and holds the award. | `not_holds` | false | The claimant made no claim, so s.10(1) gives the claimant no entitlement, and (a)(ii) fails. |
| 60A-G | Joint claimants aged 72 and 70, both past the qualifying age, neither entitled to State Pension Credit. They claimed Working Tax Credit together and hold the joint award. | `holds` for each | true | Both made the claim, so s.10(1) gives each the entitlement, and both meet (a)(i) to (iii), as (b) requires. |

### review_finding (paste as-is)

```yaml
review_finding:
  source: PolicyEngine/policyengine-uk#2805
  fix: PolicyEngine/policyengine-uk#2810
  provision: uksi/2014/1230/regulation/60A/1
  related_provisions:
    - ukpga/2002/21/section/3/3
    - ukpga/2002/21/section/10/1
  question: Whose Working Tax Credit award meets reg 60A(1)(a)(ii)?
  finding: >-
    Only an award made on a claim by the claimant, alone or jointly with a
    partner, meets reg 60A(1)(a)(ii). An award another household member
    claimed does not.
  policyengine_before: >-
    is_uc_eligible and council_tax_reduction_pensioner summed
    working_tax_credit_reported over every benefit-unit member.
  policyengine_after: >-
    Both sum working_tax_credit_reported over the claimant and partner
    (is_claimant_or_partner) only.
  cases:
    - id: 60A-F
      holds_working_tax_credit_award: not_holds
      reg_60a_waiver_applies: false
    - id: 60A-G
      holds_working_tax_credit_award: holds
      reg_60a_waiver_applies: true
```

## Completion boundary

An approved follow-up must:

- Ingest: SI 2014/1230 reg 60A in full, and Tax Credits Act 2002 s.3(3) and s.10(1), from the corpus.
- Encode: `holds_working_tax_credit_award` per claimant from s.3(3) and s.10(1), and `reg_60a_waiver_applies` from reg 60A(1)(a) and (b), in `uk/regulations/uksi/2014/1230/60A.yaml` alongside #433's cases.
- Prove: cases 60A-F and 60A-G pass with the outputs above, cases 60A-A to 60A-E still pass, and PolicyEngine's `is_uc_eligible` agrees with the encoding on both new cases.

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Ready for hub review

Head: c643315a002107e6ddaffd4e0134a4a493914355 on claude/fix-ctr-pensioner-wtc-urcygv, one commit on top of #2810's b442dcbdf79377a18285185e7465dfe483b9ab13. No PR is open for it and #2810's branch is untouched. Before starting, I checked #2810 and #2805: the last push was at 2026-11-01 19:21 UTC, more than 6 hours earlier, and no comment said anyone was mid-change.

Findings

  • F1 (CTR reads every member's report): fixed. council_tax_reduction_pensioner.py:86-105 now sums working_tax_credit_reported over is_claimant_or_partner only. The documentation string (lines 20-22) says it reads the same reports as is_uc_eligible, and the reference tuple gains reg 60A and TCA 2002 ss.3 and 10 (lines 44-46). I added the reviewer's 5 cases as council_tax_reduction/ctr_reg_60a_award_owner.yaml, rewriting the header for F8.
  • F2 (axiom: line): wrote AXIOM_ISSUE.md, posted above. It extends rulespec-uk#433 with cases 60A-F (not_holds, waiver false) and 60A-G (holds, waiver true), worked by hand from reg 60A(1) and TCA s.10(1). The body keeps axiom: hub fills this line, as the job asked.
  • F3 (P3 can't fail; no test of "no route without a closure claim"):
    • Added the YAML case at reg_60a_working_tax_credit.yaml:136.
    • Restated P3 (test_uc_reg_60a_working_tax_credit_properties.py:141-150) as "without a closure claim, zeroing every member's report never changes is_uc_eligible". It draws a claimant or partner report and caps capital within the limit.
    • Removed the copied reference formula and its reform.
    • Replaced the old fixed test with one showing that zeroing a pension-age claimant's own report closes the route on a closure claim (line 153).
  • F4 (17-year-old partner): added the YAML case at line 158. Also widened partner draws to include ages 16 and 17 (PARTNER_AGE, line 42), and P2 now requires a claimant aged 18 or over. The claimant is always drawn at 18 or over.
  • F5 (Survey data): rewrote the section, posted above. It cites the Aggregate impact result (no household's net income changes, 2025-26 to 2031-32). It explains the derived-closure path from legacy_benefits_closed and legacy_award_is_closed, both of which I read. I executed the reviewer's derived_path.yaml: it passes on this branch, and with main's is_uc_eligible it gives is_uc_eligible 1 against 0 expected. I left out the policyengine-uk-data claims (which variables the dataset supplies) because I couldn't read that repository.
  • F6 (internal process): the body ends with the required 🤖 Generated with ... line. A grep for hub, session, reviewer, harness and Claude across every changed file finds nothing. I didn't touch the earlier Read only the claimant's and partner's Working Tax Credit for reg 60A #2810 and Read the claimants' Working Tax Credit, not every benefit-unit member's, on the reg 60A Universal Credit route #2805 comments.
  • F7 (Apply the Universal Credit education condition #2806):
    • git merge-tree against Apply the Universal Credit education condition #2806's head a5d16626 still conflicts only in is_uc_eligible.py's reference tuple.
    • In a scratch worktree with both sides kept, run from inside that tree: uc_receiving_education.yaml, the reg 60A YAML and the CTR YAML pass 47 of 47, and the property file passes 4 of 4 under pytest.
    • The body names the conflict and the case 35 comment, which whoever lands second rewrites.
  • F8 (statute wording):
    • The is_uc_eligible.py comment (lines 84-94) now says a couple both aged 16 or over and in the UK must claim together (s.3(3)), cites s.10(1), names the reg 3(3) partner, and says another member claims "without the claimant".
    • The docstring, both YAML headers and the property module docstring now include reg 60A(1)(a)(iii).
    • s.10 is added to is_uc_eligible's reference tuple.
    • The changelog uses the review's wording, extended to the CTR test.
  • F9 (title): Read only the claimant's and partner's Working Tax Credit for reg 60A (69 characters). The review's suggestion runs to 88, past the 70-character limit.

Tests run

Run Result
reg_60a_working_tax_credit.yaml 7 of 7
ctr_reg_60a_award_owner.yaml 5 of 5
Whole CTR YAML directory 336 of 336
UC YAML directory (finance/benefit/family/universal_credit) 570 of 570
The other YAML files that mention reg 60A (benefit_cap_by_scheme, child_amount_tax_credit_award, benefit_cap_pension_age) 40 of 40
pytest: code_health, test_uc_legacy_closure_properties.py and the reg 60A property file 3,095 passed
ruff 0.17.2 format --check, check, check --select F811,F821; git diff --check clean (format fixed one file before the commit)

Revert and mutation checks

  • CTR revert: with council_tax_reduction_pensioner.py restored to b442dcb, CTR cases 1-3 fail (council_tax_reduction_pensioner [0.] differs from 1.0, Scotland 2026 twice and England 2024). Cases 4-5 pass.
  • Mutants on is_uc_eligible: the control passes 7 of 7 YAML cases and 4 of 4 properties. Each mutant:
Mutant YAML Properties
M1, main's any-member sum 2 fail (C and D, [1.] differs from 0.0) P1 fails
M2, UC claimants only 1 fails ([0.] differs from 1.0, the 17-year-old partner case) all pass
M10, route open without a closure claim 1 fails ([1.] differs from 0.0, the no-closure case) P3 fails
M12, claimant or partner meeting the minimum age only 1 fails (the 17-year-old partner case) all pass

I identified which case failed from the direction of the failure: only that case can move under that mutant.

Skipped

Judgment calls

  • The CTR comment cites TCA s.3(3) and s.10(1) instead of the review's "s.3(3)(a)", following F8.
  • The F4 YAML comment cites UC Regs 2013 "reg 3(3)" rather than "reg 3(3)(a)", because I don't have that paragraph's text.
  • I widened partner draws to 16 and 17. Even so, P2's 10 draws don't kill M2 or M12; the YAML case does.
  • The survey section states only what I read in the code or the Aggregate impact comment.

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Ready for hub review

Verdict: REQUEST_CHANGES at c643315a002107e6ddaffd4e0134a4a493914355 (branch claude/fix-ctr-pensioner-wtc-urcygv, one commit on b442dcbdf79377a18285185e7465dfe483b9ab13).

The code needs no change, and the head can move to #2810's branch. Every focused test, mutant and merge check I reran agrees with the hand-off. The changes I'm asking for are in AXIOM_ISSUE.md, which needs them before the hub files it (P2-1, P2-2). The rest are P3 text fixes and one optional property.

Setup: a detached worktree at the head, uv sync --frozen --extra dev, with HUGGING_FACE_TOKEN and POLICYENGINE_UK_DEFAULT_DATASET unset. For mutants I made git archive copies of the head, edited each copy and ran it through PYTHONPATH; the head tree was never edited. main is at 46a60678ff52d829253572393abdcc6a03ceb6a7. It is 17 commits past the base and git merge-tree --write-tree origin/main c643315a0 merges cleanly.

Findings

P2-1. AXIOM_ISSUE.md: the packet adds a second output name for #433's reg 60A judgment, with a different value vocabulary

Where: AXIOM_ISSUE.md, "Required outputs", the companion-case table and review_finding.cases.

The clash: rulespec-uk#433 already names this module's output upper_age_condition_disapplied_for_qualifying_claim. Its cases 60A-A to 60A-E use holds/not_holds (#433, "Required outputs (Person or Family, Day, with proof excerpts)"). The packet names the same judgment reg_60a_waiver_applies and gives it true/false. If the encoder works from both issues, it would write two outputs for one judgment in uk/regulations/uksi/2014/1230/60A.yaml. The case ids don't collide: #433 has 60A-A to 60A-E, so 60A-F and 60A-G are free.

Replacement for the second "Required outputs" bullet:

  • upper_age_condition_disapplied_for_qualifying_claim (Person or Family, Day), the output rulespec-uk#433 names for this module: holds where reg 60A(1)(a) holds for the single claimant, or (a)(i) to (iii) hold for both joint claimants; not_holds otherwise. Add tax credits validation page #433's cases 60A-D and 60A-E cover paragraphs (2) and (3).

Make the matching changes elsewhere:

  • Rename the table column, and the key in review_finding.cases, to upper_age_condition_disapplied_for_qualifying_claim.
  • Change 60A-F's value to not_holds and 60A-G's to holds.
  • Add "(Person, Day)" after holds_working_tax_credit_award.
  • In the Completion boundary, change "and reg_60a_waiver_applies from reg 60A(1)(a) and (b)" to "and upper_age_condition_disapplied_for_qualifying_claim from reg 60A(1)(a) and (b)".

P2-2. AXIOM_ISSUE.md: cases 60A-F and 60A-G leave out the qualifying claim and migration notice, so 60A-F doesn't isolate (a)(ii)

Where: the companion-case table.

The law: reg 60A(1) waives the condition only "Where a qualifying claim is made", and tests each limb "at the time the migration notice is issued". Under reg 44(1), the Secretary of State issues a migration notice to "a person who is entitled to an award of an existing benefit" (quoted in #433). In 60A-F, the claimant is "party to no tax credit claim" and holds no other benefit. Read that way, no migration notice and no qualifying claim exist, so not_holds follows whatever reg 60A(1)(a)(ii) says. The case then can't fail an encoding that gets (a)(ii) wrong. #433's own 60A-A states "qualifying claim" outright.

Working each case by hand from the quoted law, with the facts added:

  • 60A-F: the claimant is past the qualifying age, so (a)(i) holds. They have no State Pension Credit, so (a)(iii) holds. They made no Working Tax Credit claim, so s.10(1) ("the person or persons by whom a claim ... has been made") gives them no entitlement, and (a)(ii) fails. Expected values: not_holds and not_holds.
  • 60A-G: both members made the claim, so both hold the award. Both meet (a)(i) to (iii), as (b) requires. Expected values: holds for each, and holds.

Replacement facts:

  • 60A-F: "Single claimant aged 70, past the qualifying age for State Pension Credit and entitled to no State Pension Credit. Entitled to Housing Benefit and party to no tax credit claim. Issued a migration notice; makes a qualifying claim. Another adult aged 40 in the household, who is not the claimant's partner, made a Working Tax Credit claim alone and holds the award."
  • 60A-G: "Joint claimants aged 72 and 70, both past the qualifying age, neither entitled to State Pension Credit. They claimed Working Tax Credit together and hold the joint award. Issued a migration notice; they make a qualifying claim."

Housing Benefit is an existing benefit under reg 2(1), which #433 quotes.

Replacement "Why" for 60A-F:

The claimant made no Working Tax Credit claim, so s.10(1) gives the claimant no entitlement and (a)(ii) fails, though (a)(i), (a)(iii) and the qualifying claim hold.

P3-1. AXIOM_ISSUE.md: the "Corpus" line gives URLs, not corpus rows

The brief asks for a corpus citation, and #433 cites by corpus id: uk/regulation/uksi/2014/1230/60A, and uk/statute/ukpga/2012/5/33 for an Act.

Replace the "Corpus:" bullet with:

  • Corpus: uk/regulation/uksi/2014/1230/60A (on Add tax credits validation page #433's ingest list); uk/statute/ukpga/2002/21/3 and uk/statute/ukpga/2002/21/10 (status unchecked; ingest them if absent).

Then change the Completion boundary's Ingest line to name the same three rows.

P3-2. PR_BODY.md, "Survey data": the derived case reads as the only one, but a Child Tax Credit variant also exists

Where: "...or in a contrived derived case: a claimant aged 70 with a 17-year-old partner moved off Income Support and a third member who reports Working Tax Credit..."

The code: legacy_award_is_closed (legacy_benefits_closed.py) closes tax credits on the owners' Child Tax Credit report. For a 70-and-17 couple, meets_pension_credit_age_conditions is false, so pension_credit_route doesn't stop that closure.

What I ran: a three-person household for 2026 in the North East: claimant 70, partner 17, and a 40-year-old who is neither claimant nor partner and reports £1,000 of Working Tax Credit. I ran it with a £1,000 owner report of income_support_reported, then of child_tax_credit_reported:

Tree meets_pension_credit_age_conditions legacy_benefits_closed claims_uc_at_legacy_closure is_uc_eligible
Head, either variant False True True False
M1 (main's any-member sum), either variant False True True True

Replacement:

The change also reaches contrived derived cases: a claimant aged 70 with a 17-year-old partner whose Income Support or Child Tax Credit the model closes, and a third member who reports Working Tax Credit. There main's formula gives is_uc_eligible true and this branch false.

The rest of the section matches the code I read:

  • tax credits stay open for a Pension Credit-age family with no owner Working Tax Credit report;
  • wholly_pension_age stops Income Support and income-based JSA closing;
  • the function never closes ESA.

P3-3. PR_BODY.md, "What the code does now": "after those dates" is off by a year, and nations act

Where: "...Scotland in any year, England before 2025-26 and Wales before 2026-27 assess it under the working-age rules, and England and Wales disregard it after those dates."

The code: council_tax_reduction_pensioner.py:110-112 disregards the award from 2025 in England and from 2026 in Wales. Those are the first scheme years.

Replacement:

Councils assess it under the working-age rules in Scotland in any year, in England before 2025-26 and in Wales before 2026-27, and disregard it in England from 2025-26 and in Wales from 2026-27.

P3-4. changelog.d/2805.fixed.md: a test as actor, and the CTR effect unnamed

Replacement:

The model now opens the reg 60A Universal Credit route on a legacy closure claim only when the claimant or partner reports Working Tax Credit, and the formula for the pension-age Council Tax Reduction test reads the same reports; a report by a child or another adult in the benefit unit no longer opens the route or makes the award a reg 60A award.

P3-5. test_uc_reg_60a_working_tax_credit_properties.py:154-155: the fixed test's docstring is vague

Current: "On a closure claim, zeroing a pension-age claimant's own report closes the route, so the comparison in P3 can tell the two claims apart."

Replacement:

On a closure claim, zeroing a pension-age claimant's own report closes the route, so the zeroing that P3 applies without a closure claim can change is_uc_eligible.

P3-6 (optional). A property can kill M2 and M12; here is one that does

Should a property kill them? Yes. The law gives an invariant that is broader than the 17-year-old YAML case: the couple's award belongs to both members (TCA 2002 s.3(3), s.10(1)). So on a closure claim, moving a Working Tax Credit report from the claimant to the partner, or back, never changes is_uc_eligible.

Why P1-P3 miss them:

  • P2 kills only on one kind of draw: a pension-age claimant who reports nothing and a 16- or 17-year-old partner who reports.
  • families() adds a partner on only half its draws, and the simplest draw (no partner) comes first.
  • I reran the file under M2 and M12: P1-P3 and the fixed test pass 4 of 4 under each, as the hand-off says.

The property below always draws a partner. Results:

Tree Result
Head passes
M2 fails at the assert (assert True == False)
M12 fails at the assert (assert True == False)
M1, M10 passes, so it adds nothing for them

It reuses the module's helpers, so it can sit in the same file. Command: pytest policyengine_uk/tests/test_uc_reg_60a_working_tax_credit_properties.py <this file> -q. Ten derandomised examples, like the others.

@st.composite
def couples(draw):
    """A claimant and a partner, one of whom reports Working Tax Credit."""
    people = {
        "claimant": {
            "age": draw(ADULT_AGE),
            "is_claimant_or_partner": True,
            "working_tax_credit_reported": 0,
        },
        "partner": {
            "age": draw(PARTNER_AGE),
            "is_claimant_or_partner": True,
            "working_tax_credit_reported": 0,
        },
    }
    people[draw(st.sampled_from(["claimant", "partner"]))][
        "working_tax_credit_reported"
    ] = draw(POSITIVE_REPORT)
    for index in range(draw(st.integers(0, 1))):
        people[f"other_{index}"] = {
            "age": draw(OTHER_AGE),
            "is_claimant_or_partner": False,
            "working_tax_credit_reported": 0,
        }
    return {"people": people, "capital": WITHIN_LIMIT}


def swapped(family):
    people = {name: dict(person) for name, person in family["people"].items()}
    claimant, partner = people["claimant"], people["partner"]
    claimant["working_tax_credit_reported"], partner["working_tax_credit_reported"] = (
        partner["working_tax_credit_reported"],
        claimant["working_tax_credit_reported"],
    )
    return {**family, "people": people}


@PROPERTY_SETTINGS
@given(couples())
def test_moving_report_between_claimant_and_partner_never_changes_closure_eligibility(
    family,
):
    assert eligible(family, closure_claim=True) == eligible(
        swapped(family), closure_claim=True
    )

If you add it:

  • add to the module docstring "P4 On a closure claim, moving a Working Tax Credit report between claimant and partner never changes is_uc_eligible.";
  • add a matching line to the body's Invariants;
  • add "P4" to the M2 and M12 rows of the body's mutation table.

Cost: the file took 293 s for 4 tests alone and 640 s for 5 with this property, but the 640 s run shared 4 cores with two other runs.

Previous findings

Finding Status Evidence
F1, CTR reads every member's report Closed See "F1 in detail" below.
F2, axiom: line Partly closed AXIOM_ISSUE.md exists, and the body keeps axiom: hub fills this line, as the author's brief asked. P2-1, P2-2 and P3-1 remain.
F3, P3 can't fail; no test of "no route without a closure claim" Closed M10 fails the YAML case at line 136 (is_uc_eligible@2026: [1.] differs from 0.0) and P3 (test_working_tax_credit_never_changes_eligibility_without_closure_claim, line 148, assert True == False; 1 failed, 4 passed). The copied formula and its reform are gone.
F4, 17-year-old partner Closed by YAML M2 and M12 each fail only the line-158 case (is_uc_eligible@2026: [0.] differs from 1.0), and the properties pass 4 of 4 under each. The P3-6 property would also kill both.
F5, Survey data Partly closed The Aggregate impact comment (run 41342732915, head_sha b442dcbdf) says "No household's net income changes in any year", 0 broken, 0 fixed and 1 failing on both sides. That matches the body. The derived-case sentence is incomplete (P3-2).
F6, internal process Closed Body: see the "Writing rules" check below. Code: a grep for hub|session|review|harness|claude across the 6 changed files finds nothing.
F7, #2806 merge Closed See "F7 rerun" below.
F8, statute wording Closed s.3(3)(a) and s.3(3)(b) are gone. s.10(1) is cited in the code comment, YAML headers and docstring, and s.10 is in both reference tuples. (a)(iii) appears in both YAML headers and the property docstring.
F9, title Closed Read only the claimant's and partner's Working Tax Credit for reg 60A is 69 characters (wc -c) and names the right set.

F1 in detail

The code: council_tax_reduction_pensioner.py:94-104 sums working_tax_credit_reported × is_claimant_or_partner, which matches is_uc_eligible.py:96-103. The extra term is & ~working_age_applicant.

CTR revert: I put council_tax_reduction_pensioner.py back to its b442dcb version. Three cases fail (council_tax_reduction_pensioner@2026: [0.] differs from 1.0, the same at @2024):

  • "Another adult's ... Scottish pensioner's";
  • "A dependant's ... Scottish";
  • the English 2024 case.

The partner case and the claimant's-own case pass.

Expected values, worked from the quoted law:

  • Cases 1-3: the claimant made no Working Tax Credit claim, so s.10(1) gives them no award, reg 60A(1)(a)(ii) fails and reg 60A doesn't apply.
    • In Scotland the award is one the claimant "was not entitled to" (WRA s.4(1)(b) still bars them), which SSI 2021/249 reg 3(2)(b) excludes. That leaves a pensioner: true.
    • England 2024 predates SI 2025/39. The pre-2025 SI 2012/2885 reg 3(2) text isn't quoted in this round's inputs, so case 3's true rests on the formula's existing run-on/error approximation, as the YAML header says.
  • Cases 4-5: the claimant, or both joint claimants, hold the award, so reg 60A applies. SSI 2021/249 counts a reg 60A award, so the family isn't a pensioner family: false.

The hand-off's line references match the file: 86-105, documentation 20-22, reference 44-46.

F7 rerun

#2806's head: GET /repos/PolicyEngine/policyengine-uk/pulls/2806 gives a5d1662666253304de5d3245903f097791b91950, the same commit as before.

Conflict: git merge-tree --write-tree --name-only a5d16626... c643315a0 exits 1. It has one conflict hunk, in is_uc_eligible.py's reference tuple:

Merged tree: I merged in a scratch worktree, kept both sides and ran from that tree:

  • uc_receiving_education.yaml, the reg 60A YAML and the CTR award-owner YAML pass 47 of 47;
  • test_uc_reg_60a_working_tax_credit_properties.py with test_uc_receiving_education_properties.py passes 7 of 7.

Case 35: its comment on #2806 (uc_receiving_education.yaml:918) still reads "Working Tax Credit over every member", so the body's note stands.

Judgment calls

  1. The CTR comment cites s.3(3) and s.10(1), not "s.3(3)(a)": sound. It follows F8.
  2. UC Regs 2013 "reg 3(3)" with no sub-paragraph: keep it as is. Nobody quoted reg 3, so a sub-paragraph pin would be a guess. The repository already cites the same point at paragraph level in about ten places, including is_uc_eligible's own documentation string (line 14) and uc_member_of_couple_claims_as_single_person.py:11. A paragraph-level citation can't be wrong about which sub-paragraph applies.
  3. Widening partner draws to 16 and 17: harmless. As the author found, it doesn't kill M2 or M12 (I confirmed this); P3-6 does.
  4. The survey section states only what the author read: sound, apart from the gap in P3-2. Leaving out the policyengine-uk-data claims is right, since this round couldn't read that repository.

Checked and sound

My reruns of the hand-off's numbers at the head:

Run Result
reg 60A YAML plus CTR award-owner YAML 12 of 12
Whole CTR YAML directory 336 of 336
UC YAML directory 570 of 570
benefit_cap_by_scheme, child_amount_tax_credit_award, benefit_cap_pension_age 40 of 40
Property file 4 of 4 (293 s)
code_health with test_uc_legacy_closure_properties.py (-n 4) 3,091; with the property file's 4, the hand-off's 3,095
uvx ruff@0.17.2 format --check . "2165 files already formatted"
ruff check . "All checks passed!"
git diff --check b442dcbdf HEAD clean

Mutants: M1 (add over every member), M2 (* claimant), M10 (| reg_60a outside the closure claim) and M12 (* claimant_or_partner * meets_minimum_age).

Mutant YAML Properties
M1 fails cases C and D ([1.] differs from 0.0) P1 fails (line 129)
M2 fails the 17-year-old case 4 of 4 pass
M10 fails the no-closure case P3 fails
M12 fails the 17-year-old case 4 of 4 pass

This matches the hand-off and the body's mutation table. I took the failing case names from the test output, not from the direction of failure.

The delta's code:

  • is_uc_eligible: the formula is unchanged. Only the comment, documentation and reference tuple changed.
  • CTR formula: the new sum uses is_claimant_or_partner, as legacy_benefits_closed and is_uc_eligible do. universal_credit_award keeps ~head_applies_alone, so a lone head applicant isn't affected.

The new tests:

  • P3 caps capital and forces a claimant or partner report, so it can now fail (M10 shows it).
  • The fixed test asserts both directions.
  • The reg 3(3) YAML case expects is_uc_single_or_joint_claimant [true, false]. That passes on the head, so the household really reaches the reg 3(3) boundary.

PR body:

  • Fixes #2805 is the first line.
  • Reproducer: names an existing case, the one M1 fails.
  • The CTR test bullet ("three cases ... fail; the claimant's and partner's own reports pass either way") matches the revert.
  • 12 × £424.90 = £5,098.80 and 12 × £666.97 = £8,003.64; both cases pass.

Packet:

  • Line 1 is Title: and line 3 is Labels: pe-parity.
  • Its quote of reg 60A(1) matches Add tax credits validation page #433's quote word for word.
  • 60A-F and 60A-G don't clash with Add tax credits validation page #433's ids.
  • policyengine_before is right for main: main's CTR formula uses add(benunit, period, ["working_tax_credit_reported"]), and its is_uc_eligible does the same.

Writing rules:

  • The body ends with the required 🤖 Generated with [Claude Code](https://claude.com/claude-code) line.
  • None of the 6 changed files names a hub, session, reviewer or harness.
  • The comments describe the code as it is now.

What I couldn't check

  • Unquoted law:

    • UC Regs 2013 reg 3(3) and its sub-paragraphs;
    • TCA 2002 s.3(3) beyond its paraphrase;
    • UC Regs 2013 regs 28 and 60(1), which the body's education note cites;
    • SI 2012/2885 reg 3(2) before SI 2025/39, behind CTR case 3;
    • the rest of SSI 2021/249 reg 3(2) beyond "was not entitled to".

    legislation.gov.uk doesn't resolve from this session, so every legal reading above rests on text quoted in the brief, Read the claimants' Working Tax Credit, not every benefit-unit member's, on the reg 60A Universal Credit route #2805, Read only the claimant's and partner's Working Tax Credit for reg 60A #2810 or Add tax credits validation page #433.

  • Corpus status of the TCA 2002 rows (P3-1): rulespec-uk and axiom-corpus are outside this session's access.

  • CI at this head: no run exists until the hub moves the branch. The full YAML and Python suites weren't run.

  • The CTR change on survey data: I ran no survey dataset. The Aggregate impact result covers b442dcbdf only, and the CTR change has its first aggregate run when the branch moves.

  • The previous round's workspace witnesses (derived_path.yaml, the batch harness): not on this machine. I rebuilt the derived case myself (P3-2) instead.


Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Picking this up for the UK hub. Reply here if you're mid-change and I'll stop.


Generated by Claude Code

…ges reg 60A eligibility

Add property P4: on a closure claim, moving a Working Tax Credit report
between the claimant and partner never changes is_uc_eligible, since both
members hold the couple's award. Name the CTR formula in the changelog
fragment and make the fixed test's docstring say what P3 needs from it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N2tyHTWc6VfYZtLyAQvnrU
… the reg 60A tests

The draws set no carer or limited capability input, so a partner aged 16 or
17 meets the minimum age condition only beside a member under 16. Reword
the fixed test's docstring so it doesn't read as contradicting P3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N2tyHTWc6VfYZtLyAQvnrU
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Picking this up for the UK hub. Reply here if you're mid-change and I'll stop.


Generated by Claude Code

1 similar comment
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Picking this up for the UK hub. Reply here if you're mid-change and I'll stop.


Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Picking this up for the UK hub as brief 778, which replaces brief 693. Reply here if you're mid-change and I'll stop.


Generated by Claude Code

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head b442dcbdf79377a18285185e7465dfe483b9ab13. Review COMPLETE. 31 focused checks and the final UC/household-income composition checks passed in the matched locked environment. The claimant/partner ownership mask is consistent with the reviewed statutory award unit.

C1 — Complete the required Axiom parity record. The actual description still says axiom: hub fills this line. The repository's PR requirements require a supported encoded/encoded-correct/queued line, with a dispatch-ready record for a queued policy change. The documented external-contributor fallback is axiom: needed; the current placeholder satisfies neither route.

The actual rulespec-uk #433 body and all three comments cover the general reg 60A route, but do not contain the proposed #2805/#2810 ownership extension, its Tax Credits Act corroboration or companion cases. The AXIOM_ISSUE.md comment remains a proposal, and the c643315 follow-up branch is not this PR's head.

Post the ownership corroboration to the actual queue record (or complete a supported encoded alternative), including the operative sources, qualifying-claim/notice facts, required outputs, source-derived companion judgments and signed-encoder blocker. Then replace the placeholder with the supported line and link. This is an explicit repository completion blocker, so I am requesting changes.

For the 2026 examples, retain the stated annual closure/report or continuing migrated-award interpretation and its historical notice/no-SPC/no-cessation assumptions; those cases do not establish fresh 2026 WTC receipts. The review covers the adopted b442 tree and its affected dependencies; proposed follow-up changes remain separate.

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Picking this up for the UK hub as brief 1018, which replaces brief 778. Reply here if you're mid-change and I'll stop.


Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

PR_TITLE.txt

Read only the claimant's and partner's Working Tax Credit for reg 60A

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

PR_BODY.md

Fixes #2805
Reproducer: policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/reg_60a_working_tax_credit.yaml::Another adult's Working Tax Credit does not open the reg 60A route for a single claimant aged 70
axiom: hub fills this line

## What the code does now

On a closure claim (`claims_uc_at_legacy_closure`), `is_uc_eligible` opens the SI 2014/1230 reg 60A route when the claimant or partner (`is_claimant_or_partner`) reports Working Tax Credit and a claimant meets the minimum age condition. The formula sums `working_tax_credit_reported` over the claimant and partner only, so either member's report counts for both. That includes a partner who can't be a joint claimant of Universal Credit (UC Regs 2013 reg 3(3)), such as a 17-year-old. A report by a child, a qualifying young person or another adult in the benefit unit no longer opens the route.

`council_tax_reduction_pensioner` now reads the same reports to decide whether reg 60A applies to the award. On a closure claim where the claimant or partner reports Working Tax Credit, a wholly pension-age family's Universal Credit award counts as a reg 60A award. Councils assess it under the working-age rules in Scotland in any year, in England before 2025-26 and in Wales before 2026-27, and disregard it in England from 2025-26 and in Wales from 2026-27. Where only another member reports, the formula keeps its approximation for a wholly pension-age award awaiting termination or made in error, so the family stays a pensioner family.

## The law

[SI 2014/1230 reg 60A(1)](https://www.legislation.gov.uk/uksi/2014/1230/regulation/60A), as quoted in #2805:

> Where a qualifying claim is made by— (a) a single claimant who, at the time the migration notice is issued— (i) has reached the qualifying age for state pension credit; (ii) is entitled to an award of working tax credit; and (iii) is not entitled to an award of state pension credit; or (b) joint claimants both of whom satisfy the criteria in sub-paragraph (a)(i) to (iii) at the time the migration notice is issued, then, subject to paragraphs (2) and (3), the condition in section 4(1)(b) of the Act (claimant has not reached the qualifying age for state pension credit) is not to apply for the purposes of determining entitlement to universal credit in respect of the qualifying claim or any award made in respect of that claim.

Under the [Tax Credits Act 2002 s.3(3)](https://www.legislation.gov.uk/ukpga/2002/21/section/3), a couple both aged 16 or over and in the UK must claim a tax credit together, and in [s.10(1)](https://www.legislation.gov.uk/ukpga/2002/21/section/10) Parliament ties entitlement to "the person or persons by whom a claim ... has been made". So both members hold the couple's award, and the claimant holds no part of an award another member claimed.

Councils in England and Wales disregard a Universal Credit award "where regulation 60A ... applies in respect of the award" ([SI 2012/2885 reg 3(2)(b)](https://www.legislation.gov.uk/uksi/2012/2885/regulation/3), from [SI 2025/39 reg 4](https://www.legislation.gov.uk/uksi/2025/39/regulation/4); [WSI 2013/3029 reg 3(2)(b)](https://www.legislation.gov.uk/wsi/2013/3029/regulation/3), from [WSI 2026/13 reg 4](https://www.legislation.gov.uk/wsi/2026/13/regulation/4)). Scottish councils count a reg 60A award but not an award the claimant "was not entitled to" ([SSI 2021/249 reg 3(2)(b)](https://www.legislation.gov.uk/ssi/2021/249/regulation/3)). Both tests turn on whether reg 60A applies, so the same reading of whose award counts decides both.

## Cases from #2805

| Case | Who reports £1,000 of Working Tax Credit | `is_uc_eligible` (`main`) | `is_uc_eligible` (this branch) | Universal Credit (this branch) |
|---|---|---|---|---:|
| A. Single claimant aged 70 | the claimant | true | true | £5,098.80 |
| B. Single claimant aged 70 | no one | false | false | nil |
| C. Single claimant aged 70, adult aged 40 who is neither claimant nor partner | the other adult | true | false | nil |
| D. Single claimant aged 70, dependant aged 17 on post-secondary education | the dependant | true | false | nil |
| E. Couple aged 72 and 70 | the partner | true | true | £8,003.64 |

## Invariants

- P1. On a closure claim, a Working Tax Credit report by a member who is neither claimant nor partner never changes `is_uc_eligible`.
- P2. On a closure claim, with capital within the £16,000 limit and a claimant aged 18 or over, a positive report by the claimant or partner makes the family eligible.
- P3. Without a closure claim, zeroing every member's Working Tax Credit report never changes `is_uc_eligible`.
- P4. On a closure claim, moving a Working Tax Credit report between claimant and partner never changes `is_uc_eligible`.

## Tests

- `policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/reg_60a_working_tax_credit.yaml`: cases A to E, plus a single claimant aged 70 who reports Working Tax Credit without a closure claim (not eligible), and a claimant aged 70 whose 17-year-old partner reports it (eligible, £5,098.80, the partner not a joint claimant). With `main`'s formula, C and D fail (`is_uc_eligible` 1, expected 0).
- `policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_reg_60a_award_owner.yaml`: five `council_tax_reduction_pensioner` cases. Without the change, the three cases where only another adult or a dependant reports (Scotland 2026 twice, England 2024) fail (`council_tax_reduction_pensioner` 0, expected 1); the claimant's and partner's own reports pass either way.
- `policyengine_uk/tests/test_uc_reg_60a_working_tax_credit_properties.py`: Hypothesis properties P1 to P4, plus a fixed check that, on a closure claim, zeroing a pension-age claimant's own report closes the route. Partner draws include ages 16 and 17. With `main`'s formula, P1 fails.

Mutation checks on `is_uc_eligible`, each killed by at least one test:

| Mutant | Killed by |
|---|---|
| Sum every member's report (`main`) | YAML C and D; P1 |
| Count Universal Credit claimants only | YAML 17-year-old partner case; P4 |
| Count only a claimant or partner who meets the minimum age | YAML 17-year-old partner case; P4 |
| Open the reg 60A route without a closure claim | YAML no-closure-claim case; P3 |

## Survey data

The Aggregate impact run on this PR's earlier head, which changed `is_uc_eligible` only, found no change to any household's net income in any year from 2025-26 to 2031-32. `claims_uc_at_legacy_closure` follows `legacy_benefits_closed`, which reads only the claimant's and partner's reports. For a family that meets the Pension Credit age conditions, the model closes tax credits only on the claimant's or partner's Working Tax Credit report, and never closes Income Support or income-based Jobseeker's Allowance for a wholly pension-age family. So on a closure claim the model derives itself, a wholly pension-age family already has the claimant's or partner's report. The change reaches a family when a user supplies `claims_uc_at_legacy_closure`. The change also reaches contrived derived cases: a claimant aged 70 with a 17-year-old partner whose Income Support or Child Tax Credit the model closes, and a third member who reports Working Tax Credit. There `main`'s formula gives `is_uc_eligible` true and this branch false.

## Note on the education gate (#2346, PR #2806)

At #2806's head (`5961424461ff5ca4b7f87582d37d55314c5411b6`), this branch and #2806 conflict only in `is_uc_eligible`'s `reference` tuple; keep both sides' lines. With that resolved, `uc_receiving_education.yaml`, the reg 60A YAML and the Council Tax Reduction YAML pass 54 of 54, and the reg 60A and education property files pass 10 of 10. Once only the claimant and partner count, the education gate on this route can't change a result: a claimant or partner on the couple's award doesn't count as a qualifying young person (SI 2014/1230 reg 28), and under SI 2014/1230 reg 60(1), on a closure claim, every other claimant who receives education need not meet the education condition. Without the gate, the merged formula still passes those files and the Universal Credit and Council Tax Reduction YAML directories, so none of those tests reaches the gate. On merge, the comment on case 35 of `uc_receiving_education.yaml` ("the model sums reported Working Tax Credit over every member") no longer holds, though its expected values do, and whoever lands second rewrites it. #2806's property reference also sums Working Tax Credit over every member, but its draws give a report only to the claimant and partner, so it still agrees with the merged formula.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

AXIOM_ISSUE.md

Title: uksi/2014/1230 reg 60A: whose Working Tax Credit award meets reg 60A(1)(a)(ii)

Labels: pe-parity

## Module and corpus

- Module: `uk/regulations/uksi/2014/1230/60A.yaml`, the module rulespec-uk#433 queues (cases 60A-A to 60A-E). This issue extends #433 with cases 60A-F and 60A-G.
- Corpus: `uk/regulation/uksi/2014/1230/60A` (on #433's ingest list); `uk/statute/ukpga/2002/21/3` and `uk/statute/ukpga/2002/21/10` (status unchecked; ingest them if absent).
- PolicyEngine: PolicyEngine/policyengine-uk#2805, fixed by PolicyEngine/policyengine-uk#2810 (`is_uc_eligible`, `council_tax_reduction_pensioner`).

## The law

SI 2014/1230 reg 60A(1):

> Where a qualifying claim is made by— (a) a single claimant who, at the time the migration notice is issued— (i) has reached the qualifying age for state pension credit; (ii) is entitled to an award of working tax credit; and (iii) is not entitled to an award of state pension credit; or (b) joint claimants both of whom satisfy the criteria in sub-paragraph (a)(i) to (iii) at the time the migration notice is issued, then, subject to paragraphs (2) and (3), the condition in section 4(1)(b) of the Act (claimant has not reached the qualifying age for state pension credit) is not to apply for the purposes of determining entitlement to universal credit in respect of the qualifying claim or any award made in respect of that claim.

In Tax Credits Act 2002 s.10(1), Parliament ties entitlement to "the person or persons by whom a claim ... has been made". Under s.3(3), a couple both aged 16 or over and in the UK must claim a tax credit together (paraphrase; the encoder quotes s.3(3) from the corpus).

The cases below also rest on two provisions that #433 quotes. SI 2014/1230 reg 44(1), corpus `uk/regulation/uksi/2014/1230/44`:

> 44.—(1) The Secretary of State may, at any time, issue a notice (“a migration notice”) to a person who is entitled to an award of an existing benefit— (a) informing the person that all awards of any existing benefits to which they are entitled are to terminate and that they will need to make a claim for universal credit; and (b) specifying a day (“the deadline day”) by which a claim for universal credit must be made.

SI 2014/1230 reg 2(1), corpus `uk/regulation/uksi/2014/1230/2`, in the original instrument:

> “existing benefit” means income-based jobseeker’s allowance, income-related employment and support allowance, income support, housing benefit and child tax credit and working tax credit under the 2002 Act, but see also regulation 25(2);

The Secretary of State later inserted "paragraph (3) and" before "regulation 25(2)" (SI 2019/1152 reg 3(2)(a)(ii)). We have not read reg 2(3), reg 25(2) or the definition of "qualifying claim", so each case supplies the qualifying claim as a fact.

## Required outputs

For each claimant on a qualifying claim, "at the time the migration notice is issued" (reg 60A(1)):

- `holds_working_tax_credit_award` (Person, Day): `holds` where the claimant made, alone or jointly with a partner, the claim behind the Working Tax Credit award (s.10(1)); `not_holds` otherwise, including where only another member of the household made the claim.
- `upper_age_condition_disapplied_for_qualifying_claim` (Person or Family, Day), the output rulespec-uk#433 names for this module: `holds` where reg 60A(1)(a) holds for the single claimant, or (a)(i) to (iii) hold for both joint claimants; `not_holds` otherwise. #433's cases 60A-D and 60A-E cover paragraphs (2) and (3).

## Companion cases

We worked each value by hand from the law above. Each case gives the facts "at the time the migration notice is issued", and the qualifying claim that follows the notice.

| Case | Facts | `holds_working_tax_credit_award` | `upper_age_condition_disapplied_for_qualifying_claim` | Why |
|---|---|---|---|---|
| 60A-F | Single claimant aged 70, past the qualifying age for State Pension Credit and entitled to no State Pension Credit. Entitled to Housing Benefit and party to no tax credit claim. Issued a migration notice; makes a qualifying claim. Another adult aged 40 in the household, who is not the claimant's partner, made a Working Tax Credit claim alone and holds the award. | `not_holds` | `not_holds` | 1. Notice and claim: in reg 2(1), "existing benefit" includes "housing benefit", so the claimant is "a person who is entitled to an award of an existing benefit", and the Secretary of State may issue them a migration notice (reg 44(1)). The facts supply the qualifying claim. 2. (a)(i): at 70, the claimant "has reached the qualifying age for state pension credit". 3. (a)(iii): the claimant "is not entitled to an award of state pension credit". 4. (a)(ii): the claimant made no Working Tax Credit claim. In s.10(1), Parliament ties entitlement to "the person or persons by whom a claim ... has been made", so the claimant has no entitlement and (a)(ii) fails, though (a)(i), (a)(iii) and the qualifying claim hold: `not_holds`. The other adult made the claim alone, so the award belongs to the other adult alone. 5. With (a)(ii) failing, (a) fails, and the claimant claims alone, so (b) can't apply: `not_holds`. |
| 60A-G | Joint claimants aged 72 and 70, both past the qualifying age, neither entitled to State Pension Credit. They claimed Working Tax Credit together and hold the joint award. Issued a migration notice; they make a qualifying claim. | `holds` for each | `holds` | 1. Notice and claim: in reg 2(1), "existing benefit" includes "working tax credit", so each claimant is "a person who is entitled to an award of an existing benefit", and the Secretary of State may issue them a migration notice (reg 44(1)). The facts supply the qualifying claim. 2. (a)(ii): both made the claim, and in s.10(1) Parliament ties entitlement to "the person or persons by whom a claim ... has been made", so each has the entitlement: `holds` for each. 3. (a)(i): at 72 and 70, each "has reached the qualifying age for state pension credit". 4. (a)(iii): neither "is entitled to an award of state pension credit". 5. Both meet (a)(i) to (iii), as (b) requires of "joint claimants both of whom satisfy the criteria": `holds`. |

### review_finding (paste as-is)

```yaml
review_finding:
  source: PolicyEngine/policyengine-uk#2805
  fix: PolicyEngine/policyengine-uk#2810
  provision: uksi/2014/1230/regulation/60A/1
  related_provisions:
    - ukpga/2002/21/section/3/3
    - ukpga/2002/21/section/10/1
    - uksi/2014/1230/regulation/2/1
    - uksi/2014/1230/regulation/44/1
  question: Whose Working Tax Credit award meets reg 60A(1)(a)(ii)?
  finding: >-
    Only an award made on a claim by the claimant, alone or jointly with a
    partner, meets reg 60A(1)(a)(ii). An award another household member
    claimed does not.
  policyengine_before: >-
    is_uc_eligible and council_tax_reduction_pensioner summed
    working_tax_credit_reported over every benefit-unit member.
  policyengine_after: >-
    Both sum working_tax_credit_reported over the claimant and partner
    (is_claimant_or_partner) only.
  cases:
    - id: 60A-F
      holds_working_tax_credit_award: not_holds
      upper_age_condition_disapplied_for_qualifying_claim: not_holds
    - id: 60A-G
      holds_working_tax_credit_award: holds
      upper_age_condition_disapplied_for_qualifying_claim: holds
```

## Completion boundary

An approved follow-up must:

- Ingest: `uk/regulation/uksi/2014/1230/60A`, `uk/statute/ukpga/2002/21/3` and `uk/statute/ukpga/2002/21/10`, where the corpus lacks them.
- Encode: `holds_working_tax_credit_award` per claimant from s.3(3) and s.10(1), and `upper_age_condition_disapplied_for_qualifying_claim` from reg 60A(1)(a) and (b), in `uk/regulations/uksi/2014/1230/60A.yaml` alongside #433's cases.
- Prove: cases 60A-F and 60A-G pass with the outputs above, cases 60A-A to 60A-E still pass, and PolicyEngine's `is_uc_eligible` agrees with the encoding on both new cases.

#433's signed-encoder blocker still applies: no one has run the encoder for cases 60A-F and 60A-G or written their RuleSpec by hand.

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Ready for hub review

Head: 8afd8c7fc1f0528024f85eb43b0d688c06dcc5ae on claude/reg-60a-review-apply-6fcrf5. That's three commits on c643315a0: brief 608's ba7b57344 and 21900e3d5, then my 8afd8c7fc. I pushed nothing to #2810's branch and opened no PR. The three comments above hold the hub documents: PR_TITLE.txt (unchanged), PR_BODY.md and AXIOM_ISSUE.md.

Before I started

Brief 608's commits

  • ba7b57344 covers P3-6 (the property and the docstring's P4 line), P3-4 and P3-5. Each holds:
    • the property matches the review's block byte for byte (a diff of lines 176-220), and ruff format leaves the file unchanged;
    • the changelog fragment is the review's text word for word;
    • the property file passes 5 of 5 at my head (219 s).
  • 21900e3d5 rewrote two things:
    • The P3-5 docstring: it replaced the review's text with its own wording, so P3-5 no longer held. 8afd8c7fc restores the review's text (judgment call 2).
    • The PARTNER_AGE comment (lines 42-46): no job item asks for this, and it matches the code, so I kept it.
      • is_child_for_universal_credit means under 16.
      • meets_uc_minimum_age_condition admits someone aged 16 or 17 only with limited capability for work, caring, or responsibility for a child who isn't a claimant.
      • I ran a couple aged 70 and 17. The partner meets the minimum age, and becomes a joint claimant, beside a member aged 10 or 15. Beside a member aged 16 or 40, or with no one else, they do neither.

Findings and what I did

P2-1 (AXIOM_ISSUE.md). I checked the review's facts against #433:

  • its "Required outputs" for uk/regulations/uksi/2014/1230/60A.yaml name upper_age_condition_disapplied_for_qualifying_claim;
  • its cases 60A-A to 60A-E use holds and not_holds, so 60A-F and 60A-G are free.

The packet now:

  • uses the review's bullet for the output;
  • renames the table column and the cases keys;
  • gives 60A-F not_holds and 60A-G holds;
  • adds "(Person, Day)" to holds_working_tax_credit_award;
  • names the new output in the Completion boundary's Encode line.

P2-2 (AXIOM_ISSUE.md). The facts for 60A-F and 60A-G are the review's, word for word. The Why column works each value in numbered steps. The steps use only law someone quoted: reg 60A(1) (#2805 and #433), reg 44(1) and reg 2(1) (#433, now quoted in the packet's law section) and the s.10(1) fragment (this PR's body).

  • 60A-F:
    • Housing Benefit makes the claimant "a person who is entitled to an award of an existing benefit", so the notice can issue, and the facts supply the qualifying claim.
    • (a)(i) and (a)(iii) hold.
    • (a)(ii) fails because the claimant made no claim, so holds_working_tax_credit_award is not_holds.
    • (b) can't apply to a single claimant, so the waiver output is not_holds.
  • 60A-G:
    • Working Tax Credit is an existing benefit, so the notice can issue.
    • Both members made the joint claim, so each gets holds.
    • Both meet (a)(i) to (iii), as (b) requires, so the waiver output is holds.

P3-1. The Corpus bullet is the review's text, and the Ingest line names the same three rows. uk/regulation/uksi/2014/1230/60A is on #433's list ("Corpus rows to ingest in addition"). The two Tax Credits Act rows follow #433's form for an Act (uk/statute/ukpga/2012/5/33). Their status stays unchecked, as the bullet says.

P3-2. I reran the review's household: 2026, North East, a claimant aged 70 and a partner aged 17 (both is_claimant_or_partner), and a 40-year-old who isn't, with £1,000 of Working Tax Credit. I gave £1,000 of income_support_reported, then of child_tax_credit_reported, first to the claimant and then to the partner.

Tree meets_pension_credit_age_conditions legacy_benefits_closed claims_uc_at_legacy_closure is_uc_eligible
Head, all four variants False True True False
M1, all four variants False True True True

The body's Survey data section uses the review's replacement sentence, which this table supports.

P3-3. council_tax_reduction_pensioner.py:110-112 sets migrant_award_disregarded for England from model year 2025 and for Wales from 2026; lines 106-109 say "Model years represent those scheme years". Lines 116-123 count the award wherever the formula doesn't disregard it. The body uses the review's replacement sentence (judgment call 4).

P3-4. changelog.d/2805.fixed.md holds the review's text, from ba7b57344. Each claim matches the code:

  • the reg 60A route needs a closure claim and a report by the claimant or partner (is_uc_eligible.py:95-107);
  • the CTR formula reads the same reports (council_tax_reduction_pensioner.py:94-104);
  • main sums every member's report in both formulas (add(benunit, period, ["working_tax_credit_reported"])), so "no longer" holds.

P3-5. test_uc_reg_60a_working_tax_credit_properties.py:159-161 holds the review's text again, from 8afd8c7fc.

P3-6. The property sits at lines 176-220, and the module docstring's P4 line at 23-24 (from ba7b57344). From the runs below, the body adds P4 to its Invariants and to the M2 and M12 rows of the mutation table.

Main. main sits at 9b456bda65f6f01daddd89b02a77954f6a9114ad, the brief's SHA. git merge-tree --write-tree origin/main HEAD exits 0, so I didn't merge main.

#2806. gh api gives #2806's head as 5961424461ff5ca4b7f87582d37d55314c5411b6, which moved since the review's a5d16626. git merge-tree --write-tree exits 1 with one hunk, again the reference tuple. In a scratch worktree I kept both sides. Git auto-merges the formula into this branch's claimant-and-partner sum with #2806's education gate on reg_60a. The merged tree passes:

Run on the merged tree Result
uc_receiving_education.yaml + reg 60A YAML + CTR award-owner YAML 54 of 54 (42 + 7 + 5)
gov/dwp/universal_credit, finance/benefit/family/universal_credit and the CTR YAML directory 964 of 964
reg 60A and education property files 10 of 10 (207 s)

With the gate removed from reg_60a (claimant & meets_minimum_age), the same three directories still pass 964 of 964 and the two property files 10 of 10. The reason is in #2806's code: is_qualifying_young_person_for_uc_education reads the claimant's and partner's tax credit reports together for reg 28, and uc_is_excepted_from_education_condition excepts every claimant on a closure claim who isn't a qualifying young person.

Case 35's comment still says "the model sums reported Working Tax Credit over every member". #2806's property file still copies main's formula and holds a reference implementation that sums every member's report. Its draws give a report only to the claimant and partner, so both still agree with the merged formula. The body's note now cites this head and these counts.

Tests at the head

Run Result
reg 60A YAML + CTR award-owner YAML 12 of 12
Whole CTR YAML directory 336 of 336
UC YAML directory (finance/benefit/family/universal_credit) 570 of 570
test_uc_reg_60a_working_tax_credit_properties.py (-n 4) 5 of 5 (219 s)
pytest policyengine_uk/tests/code_health -n 4 3,087 of 3,087 (285 s)
.github/check_fix_pr.py on the final title and body (main's copy, with --head-sha) PASS, "Changed executable tests: 3"
uvx ruff@0.17.2 format --check . "2165 files already formatted"
uvx ruff@0.17.2 check . "All checks passed!"
uvx ruff@0.17.2 check --select F811,F821 policyengine_uk "All checks passed!"
git diff --check, merge base with main to head, and b442dcbdf to head clean

The writing grep over PR_BODY.md finds only quoted law.

Mutants and reverts

I made each mutant in a git archive copy of the head and ran it through PYTHONPATH; each run printed the copy's policyengine_uk/__init__.py.

Mutant reg 60A + CTR award-owner YAML Property file
M1, sum every member (main) 2 failed: C and D (is_uc_eligible@2026: [1.] differs from 0.0) P1 fails at line 134 (assert True == False; claimant 67, a member aged 0 who reports £1). The other four pass, P4 included.
M2, * claimant 1 failed: the 17-year-old partner case ([0.] differs from 1.0) P4 fails at line 218 (assert True == False; claimant 90 reports £1, partner 16). The other four pass.
M10, | reg_60a outside the closure claim 1 failed: the no-closure-claim case ([1.] differs from 0.0) P3 fails at line 153 (claimant 67 reports £1). The other four pass, P4 included.
M12, * claimant_or_partner * meets_minimum_age 1 failed: the 17-year-old partner case ([0.] differs from 1.0) P4 fails at line 218, with the same example as M2. The other four pass.

The CTR award-owner YAML passes 5 of 5 under every mutant, since none of them touches the CTR formula.

CTR revert: I put the head's council_tax_reduction_pensioner.py back to its b442dcbdf version, which matches main's. The CTR award-owner YAML then fails 3 and passes 2:

  • fail (council_tax_reduction_pensioner@2026: [0.] differs from 1.0, the same at @2024):
    • the other-adult case in Scotland 2026;
    • the dependant case in Scotland 2026;
    • the other-adult case in England 2024.
  • pass: the claimant's and the partner's own-report cases.

Skipped

  • Survey data tests: this session has no Hugging Face data. The CTR change gets its first Aggregate impact run when the hub moves the branch. I reread the existing comment (run 41342732915, head_sha b442dcbdf): "No household's net income changes in any year", for 2025-26 to 2031-32.
  • Full YAML and Python suites: I left those to CI. No CI run exists at this head.
  • make documentation: I didn't run it, since no docs changed.

Judgment calls

  1. juaristi22's review. The brief says to stop for anything after 06:45Z that touches this job's files or names its target, and the review names c643315 and AXIOM_ISSUE.md. I went on because the rule looks for a writer:

    • the review comes from another account, pushes nothing and says no one is mid-change;
    • read literally, the rule would also stop on the five branches above, which belong to other jobs.

    Its C1 asks for the ownership corroboration on rulespec-uk#433, with the qualifying-claim and notice facts, required outputs, hand-worked cases and the signed-encoder blocker, and then a supported axiom: line. The packet now carries each of these, and the body keeps axiom: hub fills this line for the hub to fill once it files the packet. Its last paragraph asks to keep the annual closure-report reading of the 2026 examples; I changed nothing there.

  2. P3-5. I restored the review's text over 21900e3d5's. That commit's wording avoids a reading of the review's text that contradicts P3: "On a closure claim, zeroing a pension-age claimant's own report closes the route. So the zeroing that P3 applies can change is_uc_eligible, and P3 checks that it never does without a closure claim." If the hub prefers it, it's a three-line swap.

  3. Packet changes beyond the review:

    • the reg 44(1) and reg 2(1) quotes in the law section, and their rows in related_provisions;
    • a "Facts" column header, with "at the time the migration notice is issued" moved to the intro sentence, since the facts now include the claim that follows the notice;
    • Parliament or the Secretary of State as the actor where the old text and the review's Why made a provision act (the Why for 60A-F keeps the review's substance);
    • "the claim behind the Working Tax Credit award" in place of the passive "the claim under which the Working Tax Credit award was made";
    • a note that we haven't read reg 2(3), reg 25(2) or the definition of "qualifying claim";
    • a closing line recording Add tax credits validation page #433's signed-encoder blocker.
  4. Body changes beyond the review:

    • "On a closure claim" before "where the claimant or partner reports" in the CTR paragraph, since the formula needs the closure claim;
    • actors in "The law": Parliament for s.10(1), councils for the disregard, and Scottish councils for the count;
    • "SI 2014/1230" before regs 28 and 60(1) in the education note, since Apply the Universal Credit education condition #2806's code cites those Regulations rather than UC Regs 2013;
    • the education note rewritten for Apply the Universal Credit education condition #2806's new head;
    • "none of those tests reaches the gate" in place of "No test then reaches the gate".
  5. P3-2. I ran the owner report on the partner as well as on the claimant; all four variants agree.

What I couldn't check


Generated by Claude Code

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed adopted head 8afd8c7fc1f0528024f85eb43b0d688c06dcc5ae. COMPLETE — C1 remains open; one additional nonblocking description finding (A1).

C1 — Complete the actual queued parity record. The actual description still says axiom: hub fills this line; the scoped extension to the filed Axiom record has not been adopted. The proposed AXIOM_ISSUE.md in a PR comment is useful preparation, but the required record must be filed with its operative law, module/corpus targets, outputs and externally sourced companions, and linked from the actual PR. Pending billed encoding is a separate, legitimate queued blocker.

A1 — Update the actual description for this adopted code. It still says council_tax_reduction_pensioner reads every member's WTC and this PR leaves it unchanged. The new head changes that mask to claimant/partner ownership. The actual property/test description also retains the old any-member oracle and omits the added CTR cases/P4. Apply the corrected description currently sitting in the proposed PR_BODY.md comment.

All 28 repository checks passed. The computed UC/household-income case for the excluded 17-year-old UC joint claimant passed. A controlled supplied-award CTR/household-income check passed after its claim-preference setup was corrected; the original diagnostic log is retained and repository tests were not rerun. That CTR case retains its supplied-award/run-on/error assumptions. Official ownership, migration and regional CTR source premises were checked independently. Current-head CI is still running.

Requesting changes for C1; no new wrong-cash result was established.

@MaxGhenis MaxGhenis changed the title Read the claimants' WTC on the reg 60A UC route Read only the claimant's and partner's Working Tax Credit for reg 60A Nov 3, 2026
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Thanks for the re-review (review).

We changed no code: the head stays 8afd8c7fc.

@MaxGhenis
MaxGhenis requested a review from juaristi22 November 3, 2026 20:44

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed 8afd8c7fc1f0528024f85eb43b0d688c06dcc5ae after the actual description and filed record were updated. COMPLETE — C1 and A1 RESOLVED; no open findings or material evidence gaps.

The actual Axiom #433 addendum now supplies the operative law, module/corpus ingestion targets, both outputs and companion cases 60A-F/G. These were independently checked against the official legislation. The actual PR title/description now covers the CTR ownership mask, national rules, P1–P4 and added CTR cases.

The head is unchanged. The prior 28 passing repository checks, computed UC/household-income case and corrected supplied-award CTR proof remain valid; their artifacts and runtime/dependency pins were verified without rerunning tests. The original external-fixture failure and its correction remain qualified in the report. Current-head CI is green.

Approval is withheld because the PR is still a draft. The workflow time targets were exceeded; the original elapsed time is recorded and head, description, review activity, source evidence and CI are refreshed before this publication.

@MaxGhenis
MaxGhenis marked this pull request as ready for review November 3, 2026 23:20
@MaxGhenis
MaxGhenis requested a review from juaristi22 November 3, 2026 23:20

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving current head 8afd8c7fc1f0528024f85eb43b0d688c06dcc5ae now that this PR is ready. The previous review stands: COMPLETE, C1 and A1 resolved, no open findings or material evidence gaps.

The code, adopted description, dependency pins and filed source evidence are unchanged. I verified the retained validation artifacts (28 passing repository checks plus the native final-result checks) without repeating the code review. The corrected CTR proof remains an explicitly supplied existing-award case, not a fresh UC eligibility proof. Applicable current-head checks pass.

@juaristi22
juaristi22 added this pull request to the merge queue Nov 3, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Nov 4, 2026
#2806 added DWP's Advice for Decision Making E2 to is_uc_eligible's
references, and this branch added Tax Credits Act 2002 ss. 3 and 10 at
the same place. The merge keeps all three.

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

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed current head 467b51d560eea579a45a988265731259dfcf07dc after the merge from main. COMPLETE — C1 and A1 remain resolved; no open findings or material gaps.

The conflict resolution preserves both sets of references, the claimant/partner Working Tax Credit mask and the pensioner CTR classification. The current education-condition integration is covered. All 70 selected repository tests and two native final-result checks passed in the matching Core 3.34.1 environment. The separate existing-award CTR example retains its supplied-award qualification; it is not a fresh UC eligibility proof.

Approval is pending the current head's remaining CI checks. The completed review can be retained for that CI-only follow-up.

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving current head 467b51d560eea579a45a988265731259dfcf07dc now that its CI has passed. COMPLETE — C1 and A1 remain resolved; no open findings or material evidence gaps.

The completed review stands: the head, description, dependency pins and source evidence are unchanged, with no new substantive human feedback. I verified the retained 72 passing checks (70 repository cases and two native final-result checks) and the source/artifact bindings without repeating the code review. The existing-award CTR proof keeps its supplied-award qualification. Applicable current-head checks pass.

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.

Read the claimants' Working Tax Credit, not every benefit-unit member's, on the reg 60A Universal Credit route

3 participants