Repository navigation
Gate the Child Tax Credit child element on eligibility - #2599
juaristi22 wants to merge 2 commits into
Conversation
Aggregate impact on certified data: passBase Checks: 0 broken by this change, 1 failing on both sides, 0 fixed. Moves flagged for review: 0 (thresholds in Notes
Moves flagged for reviewNone. Spending by benefit and service
Caseloads
Standard reform costings (change in gov_balance)
Standard reforms: change in each reform's target
Household net income by decileNo 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. Checks failing on both base and head (1)
Counted-once checkEach of 84 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. Provenance
Dataset: Receipts by tax head: head levels
Spending by benefit and service: head levels
Caseloads: head levels
Government balance, each component counted once: head levels
Model totals: head levels
Household income totals: head levels
Population: head levels
Poverty rates: head levels
People in poverty: head levels
Inequality: head levels
Mean household net income in each side's own deciles: head levels
Standard reform costings (change in gov_balance): head levels
Standard reforms: change in each reform's target: head levels
|
vahid-ahmadi
left a comment
There was a problem hiding this comment.
@juaristi22 thanks, first-round review at b454cea7f. The fix is right and the tests pin it. One should, in the PR body only, so I'm leaving this as a comment rather than an approval. I'll approve once the axiom line is sorted.
What I checked
- Law, against legislation.gov.uk. Tax Credits Act 2002 s 9(2) puts the elements into the maximum rate "in the case of every person or persons entitled to child tax credit", and s 8(1) makes entitlement depend on a claim plus responsibility for a child. So no element should exist for a family that isn't entitled, and gating the child element on
is_CTC_eligiblematches the Act. The family, disabled child and severely disabled child elements already carry the same gate, so this closes the last gap. The WTC elements are all gated onis_WTC_eligibletoo, so there's no matching WTC leak. - Rates, against HMRC's tax credits rates page: 2024-25 child element £3,455, family element £545, disabled child £4,170, severely disabled child £1,680; 2023-24 child element £3,235 (so the reform fixtures' £6,470 is two children). All the expected values in the new YAML match.
- Code path:
CTC_maximum_rateadds the four elements, so for an ineligible family it is now 0, andchild_tax_credit_pre_minimumandtax_creditsfollow.tax_credits_reductionreadsCTC_maximum_ratefor the CTC-only threshold, but that only matters when WTC is also 0, so nothing else moves. The only readers ofCTC_child_elementareCTC_maximum_rate; nothing in reforms or reporting reads it directly. - Tests in a fresh venv: tax credit YAML, the two edited baseline fixtures and the two-child-limit reform tests, 48 passed;
test_tax_credits_automatic_award_identity.pypassed. WithCTC_child_element.pyreset to the merge base402e7c674, Cases 1, 6 and 9 fail (child element £3,455 and £6,910 instead of £0; HB £4,258.15 instead of £5,200) and the identity test fails. The other seven cases are controls and pass on both. So the tests pin the change. - Fixture edits: the old fixtures asserted a child element for families with no reported CTC and a default UC claim, which is exactly the defect. Giving them a continuing claim and
would_claim_uc: falsekeeps their expected amounts and their purpose. - Aggregate impact: no change in 2025-26 onwards, as expected, since tax credits are closed from April 2025.
- CI at head: all 16 checks pass.
Reproducer:lines andchangelog.d/2594.fixed.mdare present. No other open PR touches these files.
Findings
- should: PR body,
axiom: needed. Same point as on #2595: the template keepsneededfor external contributors, and on a maintainer PR it leaves the parity step with no owner (the Fix evidence check accepts it, which is why CI is green). rulespec-uk has only CTC Regs reg 7 encoded under SI 2002/2007, and TheAxiomFoundation/rulespec-uk#372 already queues TCA 2002 s 9(2)(a) and regs 7 and 9. Adding the s 8(1) and s 9(2) entitlement condition there (no element without entitlement), or opening a newpe-parityissue, would let this readaxiom: <issue> queued. A companion case from the Act: a family with a child but no entitlement has a maximum rate of £0.
Nit: the README says would_claim_CTC "does not establish eligibility", which is right, but is_CTC_eligible is itself a modelling proxy (reported CTC above 0, no UC claim, legacy benefits open) for "continuing award", not the s 8 test. One clause saying so would stop a reader taking it as the statutory rule.
What looks right: a one-line fix in the right place, positive and negative controls for every element, two downstream HB and Welsh CTR cases that show the actual harm, and a property test of the tax_credits identity that would catch the same leak if it came back through another element.
🤖 Generated with Claude Code
vahid-ahmadi
left a comment
There was a problem hiding this comment.
@juaristi22 second round at b454cea7f, approving.
Earlier findings
axiom: needed(should): resolved. The body now readsaxiom: TheAxiomFoundation/rulespec-uk#372 ... queued, and the 24 Oct addendum on #372 queues the entitlement condition with companion cases (no entitlement, all elements and the maximum rate £0). That body edit changed only the axiom line.- README note that
is_CTC_eligibleis a modelling proxy (nit): unchanged, fine to leave.
At head: no code change since the first round, all 16 checks pass, mergeable with no conflicts.
Overlap and merge order: correcting my first round, which said no other open PR touches these files. #2631 (opened after that review) also edits CTC_child_element.py. Git merges the two cleanly, but with this PR's is_CTC_eligible gate, 8 of the cases in #2631's ctc_child_limit_exceptions.yaml give a child element of £0, because they have no continuing-claim premise. The fix belongs on #2631 (add the same premises you gave your fixtures here), so this PR can go first.
🤖 Generated with Claude Code
…imise all same-day ties UC reg 24A(1)(za) and 24B(2A) and CTC reg 9(1)(a)(ii) came into force on 28 November 2018 (SI 2018/1129, SI 2018/1130). Before then adopted children and those in non-parental care kept their place in the order. Same-day ties now put any child with an exception after those without, as UC reg 24B(2) and CTC reg 9(6) require. CTC tests claim tax credits, not UC, so they hold once CTC_child_element is gated on eligibility (#2599). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes #2594
Apply the existing
is_CTC_eligiblegate toCTC_child_element, matching the other three CTC elements. This prevents ineligible families from receiving phantom tax-credit income that reduces Housing Benefit and Council Tax Reduction while their final CTC award is zero. Existing eligibility, take-up, child limits, rates, minimum payments and activation rules stay intact.Add ten household regressions and a generated test of the automatic tax-credit accounting identity. Two existing child-limit boundary cases and two claimant/dependent cases now report continuing CTC claims. Those four cases and five existing reform cases explicitly decline UC, whose separate claim intention defaults to true. All nine retain their children, roles, ages, reform parameters and expected amounts.
Reproducer:
policyengine_uk/tests/policy/baseline/finance/benefit/family/tax_credits/ctc_child_element_eligibility.yamlReproducer:
policyengine_uk/tests/test_tax_credits_automatic_award_identity.py::test_tax_credits_equal_automatic_child_and_working_tax_creditaxiom: TheAxiomFoundation/rulespec-uk#372 (comment) queued
Validation: 313 previously qualified cases remain retained. A separate 11-case YAML run passes, bringing the total to 324 distinct cases (293 YAML cases and 31 pytest tests) across separate executions. The identity property's 12 successful examples count as one pytest test. This was not a single 324-case execution. One whole-repository
make formatpassed with 1,961 files unchanged; subsequent changes only adjusted YAML inputs.Independent code and policy/source review is COMPLETE/APPROVE at
b454cea7f76f1fb57e7a9a0706765ea9f5bb2e85, with no findings or material gaps and 13 official originals verified. Local validation used Python 3.13.14 / Core 3.33.2. No dependency change or population estimate.