Repository navigation
Conversation
…-qyp-school-leaver-routes
…eavers Child Benefit (General) Regulations 2006 regs 4, 5 and 7 were not modelled: is_qualifying_young_person_for_child_benefit was reg. 3 (education or training) alone, so a 16-year-old who had left school was not a qualifying young person for Child Benefit, nor a young person for Housing Benefit, the legacy benefits or Council Tax Reduction (SSCBA 1992 s.142). - Reg. 4: until the 31 August after the 16th birthday, read from is_before_first_september_following_16th_birthday. - Reg. 5: the 20-week extension period for a 16- or 17-year-old not in remunerative work, from the new input is_in_child_benefit_extension_period. - Reg. 7: until the terminal date after leaving, from the new input is_before_child_benefit_terminal_date. - Reg. 7(3): no Child Benefit for a young person who qualifies through reg. 7 alone and works 24 hours or more a week (is_child_benefit_payable_for_person); they stay a qualifying young person. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…vers Child Tax Credit Regulations 2002 reg. 4 makes a person a qualifying young person from their 16th birthday until the 31 August that next follows, with no education condition, and reg. 5(3)(b) adds the 20 weeks after leaving for an under-18 registered for work or training. The model had only the education condition (reg. 5(3)(a), (ab)). - Reg. 4 reads is_before_first_september_following_16th_birthday. - Reg. 5(3)(b) reads the new input is_in_child_tax_credit_extension_period. - Reg. 5(4)(a): a young person who has left education or training and works 24 hours a week or more is not a qualifying young person through either. Tax credits ended on 5 April 2025, so this changes years to 2024-25. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…p-terminal-date-19
UC Regs 2013 reg. 5(1)(b) and SPC Regs 2002 reg. 4A(1)(b) keep a young person in education or training a qualifying young person up to, but not including, the 1 September following their 19th birthday. - Universal Credit read the date from an input that defaulted to false, so a 19-year-old at school was not a qualifying young person in a household calculation, while the microdata sets the input true for every 19-year-old in education. - Pension Credit did not model the date at all. Add is_before_first_september_following_19th_birthday, which counts a year that starts before the date, as the 16th-birthday fact does. is_before_universal_credit_qualifying_young_person_terminal_date now follows it unless set, and Pension Credit's new terminal date condition reads it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SPC Regs 2002 reg. 4A(5), Child Benefit (General) Regulations 2006 reg. 8(2)(a) and CTC Regs 2002 reg. 5(4)(c) each say a person receiving income support is not a qualifying young person. The own-right benefits input covers Universal Credit, Employment and Support Allowance and Jobseeker's Allowance, which is Universal Credit's list (reg. 5(5)). Add receives_income_support_in_own_right: the person's own reported Income Support while Income Support is in payment (to 2025-26), settable directly. It does not read the benefit unit's calculated award, which depends on who the family's young persons are. The three programmes' qualifying young person tests exclude it; Universal Credit's does not. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…school leaver A disabled 16-year-old outside education is now a young person until the 31 August after their 16th birthday (Child Benefit reg. 4; HB reg 19(1)), so HB reg 28(6) counts them. Keep the original point, that the disability age extension does not itself create young-person status, as a second case with the reg. 4 period ended. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-qyp-school-leaver-routes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nefit reg. 4 period test_excluded_member_never_changes_is_eligibility adds a member aged 16 or over who is not in education, on the premise that they are not a qualifying young person. With reg. 4 a 16-year-old who has left education is one until the 31 August after their 16th birthday, so the generator now puts the member past that date, as #2279 does for the same reason in two other property tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-routes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…p-terminal-date-19 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…xclusion Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A mutation that opened the leaver routes to a student who fails the entry condition (reg. 5(3A)) passed every test: the grid fixed the entry age at 17. The grid now also draws a course begun at 19, with the date fact set directly, and asserts that such a student never qualifies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A mutation that read a 19th birthday on 1 September as its own "1 September following" was caught by the calendar property test only. Case 11 pins the edge in YAML too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o ctc-qyp-school-leaver-routes Brings in #2285's review round 2 head through the item 1 branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to qyp-income-support-exclusion Brings in the item 2 grid fix and #2285's review round 2 head. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ncome-support-exclusion Brings in the 1 September YAML case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e education Review round 1 of #2301: the formula took failing the non-advanced education test as having left education, so a 16-year-old in full-time advanced education working 24 hours a week lost the reg. 4 period. Reg. 5(4)(a) bars work only for a person "having ceased to receive full-time education or approved training", and full-time education at a school or college counts at any level (reg. 5(5)). Reg. 4(2) lifts the first condition only. The 20 weeks of reg. 5(3)(b) are for a person who has ceased. The property oracle had the same conflation and is fixed with it; the grid now draws a course begun at 19, as its comment says. YAML Cases 15 and 16 pin the advanced student. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r 20 Review round 1 of #2300: setting the 19th-birthday fact for one person gave everyone else in the situation false (the default), so another 19-year-old student silently lost the Pension Credit and Universal Credit status. The formula gives true for everyone under 20 on 6 October, which is everyone the age limit lets be a qualifying young person, so true is now the default for the fact and for the two terminal-date variables that read it. A partial setting then leaves everyone else where the formula puts them. Tested from age alone for ages 0 to 25 and all months, and in a mixed household (property test and YAML Case 12). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review round 1 of #2302: receives_income_support_in_own_right stayed true under a reform that neutralizes income_support, so a young person's report still excluded them from the Pension Credit, Child Benefit and CTC qualifying young person status. It now also needs Income Support not to be neutralized, as is_on_income_support already does for another member's own claim. New test: the same student is excluded with Income Support and qualifies for all three once a reform removes it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Case 3's parent, not set, now takes the default (true): harmless, since every reader is behind the qualifying young person age limit. The older child_qualifying_young_person.yaml case left its after-terminal-date person unset and relied on the old false default; it now sets the input explicitly. The docstrings now say the default is the formula's value under 20 and that older people are excluded before it is read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Picking this up for the UK hub. Reply here if you're mid-change and I'll stop. Generated by Claude Code |
The fragment said Child Benefit "is not paid" for a young person who qualifies only through the terminal date and works 24 hours or more a week. It now says the model pays none (reg. 7(3)). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H3DAwwvSTEwBJa5rD7bHvZ
No conflicts. main now holds #2279's head c5b9850 (merged as 4499481) and #2855, which starts the cost-of-living payments in 2022. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H3DAwwvSTEwBJa5rD7bHvZ
No conflicts. main now holds #2279's head c5b9850 (merged as 4499481) and #2855, which starts the cost-of-living payments in 2022. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H3DAwwvSTEwBJa5rD7bHvZ
No conflicts. It brings the Child Benefit changelog wording (dd8cd3e) and main 95dfc62 (f5fd079). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H3DAwwvSTEwBJa5rD7bHvZ
No conflicts, and no change to the tree: this branch already holds ee0482e (merged at f7e5fde) and main 95dfc62 (through #2301's head). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H3DAwwvSTEwBJa5rD7bHvZ
|
Picking this up for the UK hub. Reply here if you're mid-change and I'll stop. Generated by Claude Code |
No conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6HKeDniUizUaZcFw4Q
No conflicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6HKeDniUizUaZcFw4Q
is_on_income_support gives the benefit unit's calculated award only to whichever of the claimant and partner receives it, so the fragment says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LwQq6HKeDniUizUaZcFw4Q
|
Generated by Claude Code |
|
Generated by Claude Code |
|
Generated by Claude Code |
|
Generated by Claude Code |
|
Generated by Claude Code |
|
Generated by Claude Code |
|
Generated by Claude Code |
|
Ready for hub review HeadsAll three sit on
No Before starting and before each push and post I checked: Review of 828's thirteen commits,
|
| Commit | Steps and findings | Holds? |
|---|---|---|
892911c81 |
Step 1: the gate in is_qualifying_young_person_for_child_benefit.py (formula and comment identical to 6db2b6d47) and receives_income_support_in_own_right.py (formula identical). Its documentation names only readers at that head: the CB test (and through it HB and the legacy young person), and PC through is_on_income_support (git grep at 892911c81: PC, the HB and CTR non-dep deductions and _legacy.py read is_on_income_support; only the CB test reads the new variable). It also carries 816 f3 / A3 (the active parameter) and 815 P3-2 wording. Changelog adds the IS limb. |
yes |
d15f64d32 |
Step 2: CB YAML Cases 19-26 and tests/income_support_reforms.py (a Reform the YAML reforms: key loads). Case 19 is juaristi22's 2018 case; Case 25 uses 2026-27, and I confirmed parameters(period) for a YEAR period reads active on 30 April (utils/dated_reforms.py, utils/parameters.py: 2025 → true, 2026 → false). The 2018 cases pin the cost-of-living payment (S1). |
yes |
bec8d91bb |
Step 3 property test_own_income_support_ends_the_status_on_every_route, 2016/2019/2024; invariants 6 and 7 in the file docstring. |
yes |
3d5ef701e |
815 P2-2: the review's oracle diff, verbatim. | yes |
3eb64dfc4 |
815 P2-4: Cases 27 and 28 (numbered after Step 2's); 815 P3-6 docstring sentence. | yes |
ad5dc0bf0 |
Step 4: merges 3eb64dfc4 into #2301's 1eb9e075d; no conflicts. |
yes |
817ee7d45 |
815 P3-2 and 816 f3 / A3 in the CTC docstring; CTC named as a reader in the new variable's documentation. | yes |
77f6cdc5a |
815 P2-3 / 816 f2 / S1 and 815 P3-3: CTC Cases 18 and 19 pin the payment; with the CB gate Case 18 gives £6,188.30 and Case 19 £10,589.70, as the brief expected. | yes |
dd8cd3e8e |
changelog actor wording. | yes |
ee8ca3024 |
Step 4: merges 77f6cdc5a into #2302; three conflicts (the new variable, add/add: one copy with the incoming documentation, which names CB, PC and CTC as readers; CB docstring: incoming sentence kept; CTC Cases 18/19: incoming values). |
yes |
f7e5fdedc |
Step 4: merges ee0482e75; the scope-note conflict resolved as 816 shows. |
yes |
c21e35b26 |
S1: IS YAML Case 8 pins the payment, £14,805.70; header states 815 P3-2's reading. | yes |
05095a161 |
S1 reproducer: household net income less the payment, £15,219.10; 816 f5: neutralised grid check. | yes |
812131cdb |
816 f7 changelog. | yes, but see 62f5fcad2 |
596bf4f18, f5fd07931, 87e2d1cdf, 66a200e28 |
main 95dfc62f8 merges and #2302's re-merges; --remerge-diff lists no file for any. |
yes |
62f5fcad2: #2302's fragment said PC and CTC read "the Income Support the model calculates for a claimant or partner"; it now says "the benefit unit's calculated Income Support for whichever of the claimant and partner receives it", per 815 P3-2.
Item 2: main merges
main sat at 47a2817e2 throughout (holds #2279 and #2855). 25cb0070e and 78d4d5070 each merge it, and 919cc37e8 then 0d934a836 merge those into #2302's line. No conflicts in any of the four. git merge-tree --write-tree --name-only HEAD origin/main: clean at all three heads.
Step 4 file check. I compared each old PR head merged with main 47a2817e2 (git merge-tree --write-tree) against my head:
- Add CB and CTC qualifying young person routes for school leavers #2301 (
1eb9e075d+ main vs78d4d5070): 9 files, all from 828's Add Child Benefit qualifying young person routes for school leavers #2299 and Add CB and CTC qualifying young person routes for school leavers #2301 commits: the CB changelog,income_support_reforms.py, CTC YAML (Cases 18/19, 815 P3-3), CB YAML (Cases 19-28), the benefit cap oracle (815 P2-2), the CB property file, the CTC and CB variables' documentation (815 P3-2, 816 f3, P3-6) and gate, and the new variable. - Test PC, CB and CTC QYP exclusion of young Income Support recipients #2302 (
6db2b6d47+ main vs0d934a836): 16 files: the 9 above,ee0482e75's files (terminal-date YAML Case 15, its property file, its changelog, the scope note), the IS YAML and property file (c21e35b26,05095a161), and the two other changelog fragments (812131cdb,62f5fcad2). Lines that differ fromee0482e75's and the Step 1 commits' own changes: the S1 pins and their comments, the neutralised grid check, the docstring wording above. - Place the UC and Pension Credit QYP terminal date from the birth date #2300 (
ee0482e75+ main vs25cb0070e): no difference.
Checks
- Step 1 cycles at
f5fd07931(same Child Benefit, Income Support and CTC code as78d4d5070):child_benefit,household_net_income,income_supportandis_qualifying_young_person_for_child_benefit, each calculated first and alone in a fresh simulation, in 2016, 2018, 2019 and 2024, for (a) CB Case 19's household and (b) a lone parent claiming Income Support (income_support_reported,claims_all_entitled_benefits) with a child of 4 and a 16-year-old school leaver who reports their own Income Support: 0CycleErrorin 32 calculations. In (b) the parent's Income Support is £3,801.20 (2016-2019) and £4,706 (2024), Child Benefit pays for the 4-year-old only (£1,076.40; £1,331.20 in 2024), and the 16-year-old is not a QYP. - Benefit cap oracle (815 P2-2): a probe built from the file's own
blank,set_circumstance,situationand references (claimant 40 + one dependant + a 30-year-old non-dependant, 2025; dependantyoung_person16 or 17 orsixteen; ESA income, ESA contrib, JSA income or JSA contrib, with or without DLA; both schemes): 828's oracle 0 mismatches of 48 atf5fd07931;1eb9e075d's oracle on the same model 12 of 48.pytest -n 4on the file: 46 passed at each final head. - Fix evidence (
.github/check_fix_pr.pyfrommain, aspr_fix_evidence.yamlruns it, no labels, changes fromgit diff --name-status --no-renames -zagainst the merge base withmain): Place the UC and Pension Credit QYP terminal date from the birth date #2300 PASS, 4 changed executable tests; Add CB and CTC qualifying young person routes for school leavers #2301 PASS, 10; Test PC, CB and CTC QYP exclusion of young Income Support recipients #2302 PASS, 15. uvx ruff@0.17.2 format --check .,ruff check .,ruff check --select F811,F821 policyengine_uk: clean at all three heads.git diff --check origin/main...HEAD: clean at all three.git merge-tree --write-tree --name-only HEAD origin/main: clean at all three.- The passive-voice grep from the brief over the four documents: hits only in quoted law.
Mutations
Each in a scratch worktree, applied alone, then reverted.
| Where | Mutation | YAML that fails | Properties that fail | Result |
|---|---|---|---|---|
f5fd07931 |
CB Income Support gate removed (Step 3) | CB Cases 19, 21, 22, 23 (4 of 28); CTC Case 18 (1 of 20); qualifying_young_person_reported_own_awards.yaml 23/23 and qualifying_young_person_no_education_route.yaml 14/14 pass |
test_own_income_support_ends_the_status_on_every_route (CB file 1 of 5); legacy readers 20/20 pass |
killed |
f5fd07931 |
815 M3: reports exclude only off the education route | CB Case 27 (1 of 28) | none | killed |
f5fd07931 |
815 M4: esa_contrib_reported dropped |
CB Case 27 (1 of 28) | none | killed |
0d934a836 |
816 M4: (not removed) dropped from is_on_income_support's own_award |
not run | test_income_support_ends_three_statuses_and_not_universal_credit (120 of 512 statuses differ) |
killed |
juaristi22's case (CB Case 19) and the Step 3 property both fail without the gate. Cases 20, 24, 25 and 26 pass without it, as they should: none holds a report the gate would count.
Tests at the final heads
From clean runs, one file at a time; no skip, xfail, XPASS, failure or timeout anywhere. YAML: every test YAML the branch changes against main 47a2817e2 plus every baseline YAML naming qualifying_young_person, income_support_reported or receives_income_support_in_own_right, with policyengine-core test. Python: pytest -n 4, each capped at 40 minutes (the slowest took 5m44s).
#2300 25cb0070e |
#2301 78d4d5070 |
#2302 0d934a836 |
|
|---|---|---|---|
| YAML | 53 files, 897 passed | 55 files, 981 passed | 57 files, 1,004 passed |
test_benefit_cap_specified_benefits_properties.py |
46 | 46 | 46 |
test_child_and_adult_definitions_properties.py |
21 | 21 | 21 |
test_child_benefit_school_leaver_routes_properties.py |
n/a | 5 | 5 |
test_child_tax_credit_school_leaver_routes_properties.py |
n/a | 6 | 6 |
test_income_support_eligibility_properties.py |
4 | 4 | 4 |
test_legacy_award_readers_properties.py |
20 | 20 | 20 |
test_means_test_income_properties.py |
2 | 2 | 2 |
test_pension_credit_young_person_income_support.py |
10 | 10 | 10 |
test_qualifying_young_person_income_support_properties.py |
n/a | n/a | 5 |
test_qualifying_young_person_terminal_date_properties.py |
8 | n/a | 8 |
policyengine_uk/tests/code_health |
3,165 | 3,174 | 3,177 |
At #2300's head, its own files on their own: qualifying_young_person_terminal_date.yaml 15 passed, child_qualifying_young_person.yaml 8; its Python files (test_qualifying_young_person_terminal_date_properties.py, test_child_and_adult_definitions_properties.py) are in the table. At #2302's head, qualifying_young_person_income_support.yaml 8 passed. #2855 sits in main 47a2817e2, which each head carries, so these are the runs on a merge with #2855: CTC Cases 18 and 19, IS Case 8 and the reproducer pass there.
Findings, and where each now stands
- C1 (
REVIEW.md, Add Child Benefit qualifying young person routes for school leavers #2299; kept open at 15:09Z): closed at Add CB and CTC qualifying young person routes for school leavers #2301's head by892911c81(is_qualifying_young_person_for_child_benefit.py:88at78d4d5070,receives_income_support_in_own_right.py). CB Case 19: QYP false, Child Benefit £0, household net income £6,188.30; Case 20: £1,076.40 and £7,264.70. The gate mutation fails Case 19. The CB property's draws include the education route. - 815 P1-1 / juaristi22 15:09Z point 2: Add CB and CTC qualifying young person routes for school leavers #2301 body, Summary paragraph on reg. 8 now names the education route and reg. 8(1); the impact intro carries the review's replacement sentence verbatim. Cases 23 and 27 test the education route.
- 815 P2-1, 816 f1, A2 / juaristi22's Add CB and CTC qualifying young person routes for school leavers #2301 point 2 and Add Child Benefit qualifying young person routes for school leavers #2299 point 3: each "Aggregate impact report (CI)" section rebuilt from the replacement text, naming the commit CI last ran at (
1eb9e075dfor Add CB and CTC qualifying young person routes for school leavers #2301,6db2b6d47for Test PC, CB and CTC QYP exclusion of young Income Support recipients #2302,ee0482e75for Place the UC and Pension Credit QYP terminal date from the birth date #2300); the "two flags" paragraph is gone; local runs are labelled by commit. Add CB and CTC qualifying young person routes for school leavers #2301's poverty sentence now reads the report's people-in-poverty rows; Test PC, CB and CTC QYP exclusion of young Income Support recipients #2302's names the income tax line's cause (the Child Benefit charge, as Add CB and CTC qualifying young person routes for school leavers #2301's local runs show) because the report matches Add CB and CTC qualifying young person routes for school leavers #2301's line for line. - 815 P2-2 / juaristi22's oracle point (eight exemptions, two caps):
3d5ef701e; my probe above shows 0 mismatches against 12 for the old oracle on the same model. - 815 P2-3, 816 f2, S1:
77f6cdc5a(CTC 18/19),c21e35b26(IS Case 8),05095a161(reproducer subtractscost_of_living_support_payment),d15f64d32(CB 2018 cases). The bodies no longer describe the backdated payment as model behaviour. Start cost-of-living payments in 2022, per benefit unit and person #2855 is inmain47a2817e2, which all three final heads carry, so the final-head runs are the runs on a merge with Start cost-of-living payments in 2022, per benefit unit and person #2855. - 815 P2-4: CB Cases 27 and 28 (
3eb64dfc4); M3 and M4 recorded in Add CB and CTC qualifying young person routes for school leavers #2301's body. - 815 P3-1: Add CB and CTC qualifying young person routes for school leavers #2301 body, "The other own-benefit gate", replacement applied.
- 815 P3-2: CTC docstring (
817ee7d45), new variable's documentation, IS YAML header and property docstring, Test PC, CB and CTC QYP exclusion of young Income Support recipients #2302 changelog (62f5fcad2), Add CB and CTC qualifying young person routes for school leavers #2301 and Test PC, CB and CTC QYP exclusion of young Income Support recipients #2302 bodies. - 815 P3-3: CTC Case 18 comment (
77f6cdc5a) and Add CB and CTC qualifying young person routes for school leavers #2301 body row 18. - 815 P3-4: Add CB and CTC qualifying young person routes for school leavers #2301 body, CTC property bullet.
- 815 P3-5: branch name dropped; "before the formula took its current form".
- 815 P3-6: CB docstring (
3eb64dfc4) and Add CB and CTC qualifying young person routes for school leavers #2301 body. - 816 f3, A3:
receives_income_support_in_own_rightdocumentation (892911c81), CTC docstring (817ee7d45), IS property invariant 3 (05095a161), "What a reform must do" in Test PC, CB and CTC QYP exclusion of young Income Support recipients #2302's body and in Add CB and CTC qualifying young person routes for school leavers #2301's Child Benefit section. - 816 f4: third reason added to Test PC, CB and CTC QYP exclusion of young Income Support recipients #2302's differential.
- 816 f5:
05095a161; 816 M4 killed at0d934a836. - 816 f6: covered by f3; no other change.
- 816 f7:
812131cdb, refined by62f5fcad2. - 816 f8: "(removed at 4e1e017)" added;
is_qualifying_young_person_for_child_tax_creditwritten out. - 816 f9: "the branches below this PR" dropped; the base now reads "local merge 565b29c04 (on
maine01f2f5 with Count 16-year-olds outside education as UC and Pension Credit qualifying young persons until the 1 September after their 16th birthday #2279 and Count only the claimant's and partner's income in the legacy means tests #2387)". I can't see 565b29c04, so I can't name what else it holds. - 816 f10: Test PC, CB and CTC QYP exclusion of young Income Support recipients #2302 retitled "Test PC, CB and CTC QYP exclusion of young Income Support recipients" (68 characters): after Step 4 its own diff adds tests, one code comment and the changelog fragment, nothing that changes a formula.
- 816 f11: nothing.
ee0482e75scope note: resolved inf7e5fdedcas 816 shows.
Sentences that carry CI figures (for the hub to refresh)
PR_2300_BODY.md, "Aggregate impact report (CI)": "CI last ran it at ee0482e: with ee0482e merged intomain52b3080 (526188e), the report passes: ..." through "... so this PR's own change moves nothing;main52b3080 did not yet hold Count 16-year-olds outside education as UC and Pension Credit qualifying young persons until the 1 September after their 16th birthday #2279."PR_2301_BODY.md, "Microsimulation impact" first sentence ("The CI report ran at 1eb9e07, ...") and the whole "Aggregate impact report (CI)" subsection: the paragraph starting "[The report]", the four-row table, the caseload and poverty paragraph, and the taper paragraph.PR_2302_BODY.md, "Aggregate impact report (CI)": the single paragraph, from "[The report]" to "which Count 16-year-olds outside education as UC and Pension Credit qualifying young persons until the 1 September after their 16th birthday #2279's own report also shows."
I expect the taper line to drop out of all three once CI reruns against a main that holds #2279; I have not run that.
Skipped
- Survey-data runs: no private data access. Every body labels its earlier local figures by commit.
- The full suite; CI covers it. No CI ran on my heads: I opened no PR and moved no PR branch.
- A YAML run for the 816 M4 mutation (I ran the one property test that the brief's finding names).
- rulespec-uk#356 and Simulate PIP #361: outside this session's GitHub scope, so I could not check their current text;
AXIOM_356.mdbuilds only on Add CB and CTC qualifying young person routes for school leavers #2301's body and the YAML at78d4d5070. shard_durations.toml: no test renamed or removed.
Judgment calls
- No code fix. I found nothing wrong in 828's commits beyond the changelog wording, so the three heads differ from 828's only by
62f5fcad2and themainmerges. - Test PC, CB and CTC QYP exclusion of young Income Support recipients #2302's changelog type. Test PC, CB and CTC QYP exclusion of young Income Support recipients #2302's own diff now adds tests, a comment and the fragment. I kept the fragment as
fixed(which keeps the Fix evidence check andFixes #2292consistent) and its "Tested that ..." wording; say if you'd rather make itchanged. - Add CB and CTC qualifying young person routes for school leavers #2301 reproducer. One
Reproducer:line with two ids, the CB Income Support property and the CTC Income Support property, one per issue it fixes. The check accepts both. - Place the UC and Pension Credit QYP terminal date from the birth date #2300 body order. I moved its
Reproducer:andaxiom:lines up underFixes #2291, per the repository's body order; their text is unchanged. - Test PC, CB and CTC QYP exclusion of young Income Support recipients #2302's case table. The row for the zero-formula reform at 98a4739 now reads "not rerun" for household net income: its earlier £12,894.86 included the backdated payments, and I did not rerun 98a4739 with the payment removed.
- Earlier-commit figures. I kept every earlier local or mutation figure that the bodies already labelled by commit, and wrote new numbers only where I ran them.
Generated by Claude Code
juaristi22
left a comment
There was a problem hiding this comment.
Review status: COMPLETE at 0d934a836984a20447f1c3e0f02a9b30dc7b8f35. All prior findings are resolved; no new findings or material evidence gaps.
C1 and A1 remain resolved: the calculated claimant/payee Income Support reader for PC/CTC and Child Benefit's acyclic own-report reader retain their distinct documented scopes. The current final-PC regression computes the award rather than supplying it.
A2 resolved: the impact narrative now matches the dated primary CI report. A3 resolved: reform instructions include the programme's active = false option as well as neutralisation. S1 resolved: the affected income assertions isolate inherited cost-of-living payments.
13/13 focused checks passed at this exact head on lock-matched Core 3.34.1, with valid unchanged proof retained and the inherited fixes traced to the separately tested #2300/#2301 heads. Ancestry confirms this head contains both current parents, so the stated combined-delivery alternative is preserved. Across the three actual snapshots, the single bounded campaign passed 156 checks; those are not a hypothetical merge run or a full-suite claim.
The independent source review supports the programme-specific exclusion and the filed queued Axiom records. Annual/report approximations and historical aggregate qualifications remain explicit. No approval is issued while this PR is a draft; pending CI can be checked later without repeating this review.
juaristi22
left a comment
There was a problem hiding this comment.
Review status: COMPLETE — approved at 0d934a836984a20447f1c3e0f02a9b30dc7b8f35. No findings or material evidence gaps remain.
The code head is unchanged from the completed review. I verified the retained code/source evidence and resolved findings, and assessed the current description and its primary CI provenance. No tests or model calculations were repeated for this readiness change; the historical validation and documented annual/reporting limitations retain their original qualifications.
The PR is now ready, and applicable required checks pass at this exact head. The head, description, review activity, source guards and checks are refreshed again before this approval.
Fixes #2292
Reproducer: policyengine_uk/tests/test_qualifying_young_person_income_support_properties.py::test_a_reform_paying_no_income_support_restores_the_severe_disability_addition
axiom: SPC Regs 2002 reg 4A(5) TheAxiomFoundation/rulespec-uk#360 queued (its Case F and addendum cases A3 and A4 cover income support); Child Benefit (General) Regulations 2006 reg 8 TheAxiomFoundation/rulespec-uk#356 queued (addendum); CTC Regs 2002 reg 5(4)(c) TheAxiomFoundation/rulespec-uk#361 queued (addendum, Case J). Each states its blocker: rulespec-uk's corpus pin holds SPC reg 4A's and CTC reg 5's rows and no row for Child Benefit reg 8, and a billed encoder run needs approval.
Stack. The merge order is #2300, #2301, then #2302. This branch carries both: 919cc37 merges #2301's head 78d4d50, which lands the Child Benefit commits from the closed #2299, and 0d934a8 merges #2300's head 25cb007. So landing this PR lands both. #2279 and #2387 have merged into
main, which both merged heads carry at 47a2817. Until #2300 and #2301 merge, the diff here also shows their commits. This PR's own commits:Summary
Pension Credit, Child Benefit and Child Tax Credit law each excludes a young person who receives Income Support in their own right from qualifying young person (QYP) status. Universal Credit's does not. The model's own-right input,
receives_benefits_in_own_right, covers Universal Credit, Employment and Support Allowance and Jobseeker's Allowance, the benefits Universal Credit's own rule lists.The exclusions themselves now reach
mainfrom the PRs below this one: #2279 gave Pension Creditis_on_income_support, #2301 gives CTC the same reader, and #2301 also brings the Child Benefit gate andreceives_income_support_in_own_rightfrom #2299's commits. This PR's own change narrows to tests that the three programmes exclude and Universal Credit does not, in the baseline and under reforms that remove Income Support, a comment in the Pension Credit test, and its changelog fragment.How each programme reads receipt.
is_on_income_support(#2279)is_on_income_support(#2301)receives_income_support_in_own_right(#2301, from #2299's commits)What a reform must do. A reform that sets
gov.dwp.income_support.activeto false, or neutralisesincome_support, ends every programme's exclusion for everyone. A reform that only replacesincome_support's formula with one returning zero ends the Pension Credit and Child Tax Credit exclusion for a claimant or partner, because both read the calculated award. For any other member, and for Child Benefit, that reform leaves a reported award standing.Why Child Benefit reads the report. The benefit unit's Income Support depends on which young people count for the family's Child Benefit. In fresh simulations in 2016, 2019 and 2024 of a parent claiming Income Support with a 17-year-old at school reporting their own, reading
is_on_income_supportfrom the Child Benefit test raised aCycleErroron calculatingchild_benefitfirst:The case the reproducer pins. In 2019, a pensioner aged 70 on PIP daily living with £5,000 of State Pension shares a household with an unrelated 18-year-old in their own benefit unit: an orphan with no parental substitute, in qualifying full-time non-advanced education, with an existing Income Support claim (IS Regs 1987 reg. 13(2)(c)), caring for the pensioner 35 hours a week. Neither claims Carer's Allowance or Universal Credit. The household net income column leaves out cost-of-living payments, which DWP first paid in 2022:
income_support's formula with zero, at 98a4739income_supportneutralised, at this headOnce the student receives no Income Support, they count as a qualifying young person (reg. 4A(5) no longer applies), DWP does not count them as residing with the pensioner (Schedule I para. 2(2)(f)), and the pensioner gets the severe disability addition, £65.85 × 52 = £3,424.20: £167.25 × 52 = £8,697 − £5,000 + £3,424.20 = £7,121.20. Household net income: State Pension £5,000 + PIP £58.70 × 52 = £3,052.40 + Pension Credit + Income Support + winter fuel payment £200 − TV licence £154.50.
The law
Change
is_qualifying_young_person_for_pension_credit: a comment says when a claimant or partner receives Income Support for reg. 4A(5) (while the model pays their benefit unit an award). The formula stays as Count 16-year-olds outside education as UC and Pension Credit qualifying young persons until the 1 September after their 16th birthday #2279 and Place the UC and Pension Credit QYP terminal date from the birth date #2300 leave it.is_qualifying_young_person_for_pension_creditandis_qualifying_young_person_for_child_tax_creditreadis_on_income_support;is_qualifying_young_person_for_child_benefitreadsreceives_income_support_in_own_right;is_qualifying_young_person_for_universal_creditreads neither. Their docstrings note two gaps: Child Benefit reg. 8 also lists incapacity benefit and tax credits, and CTC reg. 5(4)(c) lists only the income-related and income-based allowances, where the own-right input also catches the contributory ones.Invariants
receives_income_support_in_own_rightholds when the person reports Income Support of their own while Income Support runs (to 2025-26) and no reform neutralises it, and not otherwise.income_support, no Pension Credit, Child Tax Credit or Child Benefit status depends on reported Income Support. Under a reform that replacesincome_support's formula with zero, no Pension Credit or Child Tax Credit status of a claimant or partner depends on it; another member's report and the Child Benefit reader still exclude, as their documentation says.Tests
test_qualifying_young_person_income_support_properties.py:income_supportgives every programme's status without the report (invariant 3 for a member who is not the claimant or partner);qualifying_young_person_income_support.yaml, eight cases hand-computed:receives_income_support_in_own_rightset directlyis_on_income_supportMerges into this head
Each is its own commit.
is_on_income_support) with Place the UC and Pension Credit QYP terminal date from the birth date #2300's terminal-date condition and documentation; the formula kept this branch's gate as well.test_child_and_adult_definitions_properties.py: the merged text keeps Add Child Benefit qualifying young person routes for school leavers #2299's and Add CB and CTC qualifying young person routes for school leavers #2301's leaver inputs and Place the UC and Pension Credit QYP terminal date from the birth date #2300's terminal-date and Income Support sentences, and names Child Benefit reg. 8 and CTC reg. 5(4)(c) beside SPC reg. 4A(5).receives_income_support_in_own_rightfrom the Pension Credit and CTC tests, and 6db2b6d reformats the property file.receives_income_support_in_own_rightfrom Add Child Benefit qualifying young person routes for school leavers #2299's commits. Three conflicts:receives_income_support_in_own_right.py, which both sides added: one copy, with the same formula and comment, and documentation that names Child Benefit, Pension Credit and CTC as readers, the active parameter among the ways a reform ends the exclusion, and the claimant-or-partner reading ofis_on_income_support.is_qualifying_young_person_for_child_benefit.py: the same gate on both sides; the documentation keeps the incoming sentence that a positive report for the year ends the status for the whole year.child_tax_credit_school_leaver_routes.yamlCases 18 and 19: the incoming cases, which set the cost-of-living payment to zero.main95dfc62; 919cc37 and 0d934a8 merge them again after each tookmain47a2817. None of the four had a conflict.Differential against 98a4739
A generated population of 400 households a year (pensioners with a young person in their benefit unit or in the young person's own, CTC claimants with a young person and sometimes a child, and young people alone; reported Income Support, income-related ESA and income-based JSA drawn for the young person), run on 98a4739 and 6db2b6d. Households whose Pension Credit, CTC or Child Benefit differ:
Mutation checks
At 4e1e017 (6db2b6d changes only the property file's formatting), each applied alone in a copy of the branch (
qualifying_young_person_income_support.yaml,child_tax_credit_school_leaver_routes.yaml,qualifying_young_person_terminal_date.yaml,qualifying_young_person_reported_own_awards.yamland three property files):test_income_support_ends_three_statuses_and_not_universal_credit,test_reforms_that_remove_income_support_end_the_exclusions; in the CTC filetest_income_support_ends_every_route,test_income_support_does_not_end_the_status_once_neutralised,test_family_members_in_any_benefit_unitreceives_income_support_in_own_rightto its own-benefit block, so a claimant's report counts)test_a_reform_paying_no_income_support_restores_the_severe_disability_addition,test_reforms_that_remove_income_support_end_the_exclusionsis_on_income_supportreads the report for everyone)test_a_reform_paying_no_income_support_restores_the_severe_disability_addition,test_reforms_that_remove_income_support_end_the_exclusionstest_qualifying_young_person_terminal_date_properties.py(8 tests) passes under all three.At 0d934a8,
is_on_income_supportkeeping another member's report under a reform that neutralisesincome_support((not removed)dropped fromown_award) failstest_income_support_ends_three_statuses_and_not_universal_credit(120 of 512 statuses differ from the unreported grid under neutralisation): killed. 05095a1 added that check.Earlier mutations, at the commits named:
test_no_receipt_once_a_reform_removes_income_support(removed at 4e1e017)Run locally
policyengine-core teston 57 YAML files (every test YAML file the branch changes againstmain47a2817, and every baseline file that namesqualifying_young_person,income_support_reportedorreceives_income_support_in_own_right), 1,004 passed,qualifying_young_person_income_support.yaml8 of them;pytest -n 4, one file at a time:test_benefit_cap_specified_benefits_properties.py46 passed,test_child_and_adult_definitions_properties.py21,test_child_benefit_school_leaver_routes_properties.py5,test_child_tax_credit_school_leaver_routes_properties.py6,test_income_support_eligibility_properties.py4,test_legacy_award_readers_properties.py20,test_means_test_income_properties.py2,test_pension_credit_young_person_income_support.py10,test_qualifying_young_person_income_support_properties.py5,test_qualifying_young_person_terminal_date_properties.py8,policyengine_uk/tests/code_health3,177. No skip, xfail or failure.uvx ruff@0.17.2 format --check .,ruff check .andruff check --select F811,F821 policyengine_uk: clean;git diff --checkagainstmain47a2817: clean;git merge-tree --write-treewithmain47a2817: no conflict.policyengine-core teston 31 YAML files, 499 passed, and the same property files, all passing, withcode_health3,107. At 62e9317 (Count only the claimant's and partner's income in the legacy means tests #2387, Count 16-year-olds outside education as UC and Pension Credit qualifying young persons until the 1 September after their 16th birthday #2279 and the Child Benefit, CTC, terminal-date and Income Support follow-ups):policyengine-core teston the 248 YAML files that mention these programmes, 2,685 passed;pyteston the 135 Python test files that mention them, 1,930 passed, 1 xfailed and 6 failed (four the benefit cap property oracle, fixed at 8a5980c, and two a test generator on Count 16-year-olds outside education as UC and Pension Credit qualifying young persons until the 1 September after their 16th birthday #2279, fixed there at 560005c).The full suites run in CI.
Microsimulation impact
Aggregate impact report (CI)
The report runs
main040e9a5 against this PR merged into it (14701f0, head 0d934a8) on the certified Enhanced FRS 2024-25 (policyengine-uk-data 1.58.1), one full run per side for each year 2025-26 to 2031-32. Result: pass, 0 checks broken, 1 failing on both sides, 0 moves flagged. Child Benefit rises by £5.2m to £6.2m a year (about 1,000 more awards) and income tax by £1.8m to £2.2m. The report matches #2301's at 78d4d50 line for line, so the Child Benefit routes that #2301 lands make these moves, and the income tax comes from the High Income Child Benefit Charge on that Child Benefit, as #2301's local runs show; this PR's own change and #2300's move nothing. The standard reform costing "Raise child benefit by 25GBP/week per additional child" moves by −£1.5m to −£0.9m a year, and the other standard costings by £8 or less.Local runs
These cover c6c46e6 only. Real runs on Enhanced FRS 2024-25 (uk-data 1.58.0, sha256
5ba399ea5ab9a6c7), one run each for 2024-25 to 2030-31, exact comparison of every record. Base: local merge 565b29c04 (onmaine01f2f5 with #2279 and #2387). Branch: c6c46e6.No record changes in any year. In 2024-25 and 2025-26, 60 records (about 36,000 weighted people) receive Income Support in their own right, and none of them is 16 to 19; no one aged 16 to 19 reports any Income Support (on the earlier base). From 2026-27 Income Support no longer runs. The change shows in household calculations (the tables above).
🤖 Generated with Claude Code