Repository navigation
Conversation
…ducation condition UC Regs 2013 reg. 5(1)(a) and SPC Regs 2002 reg. 4A(1)(a) make a person who has reached 16 a qualifying young person up to the 1 September following their 16th birthday, whatever their education. The model encoded only the education route, so a 16-year-old outside education was not a UC or PC qualifying young person. is_before_first_september_following_16th_birthday places that date from the date of birth and counts the route for a year that starts (6 April) before it: every annual age of 16, and a 17-year-old born from 1 September to 6 October. Both QYP variables OR it with the education route, under the same age band and own-right benefits exclusion. Tests: YAML cases hand-computed from the regulations (flags, date edges, UC child element and work allowance, PC child addition), the property-test oracle, a calendar differential over every birth date in 2008-2011 and across years, and a grid test of sufficiency, monotonicity, exclusion and UC/PC agreement. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 10, 2026
Stop counting a benefit unit's claimant or partner as its own child or qualifying young person
#2285
Merged
Two property tests build a member who is outside every programme's family as a 16 to 19 year old not in education. At 16 that member is now a UC qualifying young person under reg 5(1)(a), so the family's UC gains a child element and the tests' premise no longer holds. Their generators now set is_before_first_september_following_16th_birthday false for that member. The test functions are unchanged, so Hypothesis draws the same examples. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
added a commit
that referenced
this pull request
Oct 11, 2026
…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>
This was referenced Oct 11, 2026
Draft
…date-of-birth tests - The route variable's docs now warn that setting it for some people gives everyone else false, and point to date_of_birth for placing one person. They also state that the rule departs from the 6 October reading that is_SP_age uses. - YAML: a 2025-26 case where the 16-year-old ranks first under the two-child limit and the youngest child loses the element (GBP 7,581.72), and a case mixing a person with date_of_birth and one without (both in the route). The second kills a mutant that reads the raw date_of_birth input instead of birth_day. - means_test_income_members.yaml: the 17-year-old case's name says why they are outside the route. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3 tasks done
Collaborator
Author
|
PE-UK main fix landed (UK hub, 2026-10-11 21:42Z): #2349 merged as |
MaxGhenis
added a commit
that referenced
this pull request
Oct 12, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
UC Regs 2013 reg 5(1) makes a person who has reached 16 but not 20 a qualifying young person:
SPC Regs 2002 reg 4A(1) is the same. Route (a) has no education condition. The model encoded only route (b), so a 16-year-old outside education was not a UC or Pension Credit qualifying young person (QYP), and nothing that reads QYP status counted them: the UC child element, the two-child limit order, the work allowance, UC responsibility, and the Pension Credit child addition. The benefit cap and LHA family rules already counted every 16-year-old non-claimant through a separate stand-in on main, so there the change reaches only 17-year-olds born from 1 September to 6 October.
is_before_first_september_following_16th_birthday(Person, year) is true when the fiscal year starts (6 April) before the 1 September following the person's 16th birthday. It places the date fromdate_of_birth, or fromageandmonths_since_last_birthday, as the model's other date-of-birth rules do, and a user can set it directly. It mirrors the Day-level inputcurrent_day_is_before_first_september_following_16th_birthdayin rulespec-uk'suk/regulations/uksi/2013/376/5.yaml.is_responsible_for_child_or_young_person_for_uc_or_housing_benefitsaid "the UC child element does not yet model reg 5(1)(a)". It now says the UC test includes it. Its separate count of any 16-year-old non-claimant stays for Housing Benefit, whose young person follows Child Benefit's unmodelled school-leaver rules (Child Benefit (General) Regulations 2006 regs 4, 5 and 7).The annual approximation
The route ends on a fixed 1 September; the model's year runs from 6 April, and its age is the age on 6 October. A year counts in the route if any of it falls in the route, which is the same as the year starting before that 1 September. This follows the rule that main already applies to this route for the benefit cap and LHA family rates (
is_responsible_for_child_or_young_person_for_uc_or_housing_benefit, andhas_sixteen_year_old_dependantin #2089), so UC's child element, work allowance, cap and LHA tests all agree on who is a QYP. It is also the approximation the task suggested ("treat age 16 as within the route for the part-year").Who it covers:
Bias, computed by calendar arithmetic over every birthday (
datearithmetic, ages on 6 October, fiscal year 2026-27, birthdays equally likely). It compares the share of the year a person outside education is a child or in the route with what each rule counts:No annual boolean is unbiased. A status-on-6-October rule is less biased in aggregate, but it would count about one 16-year-old outside education in ten. It would also disagree with the cap and LHA family rules, which count all of them. Switching to it is one character in the new variable:
year_of_first_september >= period.start.yearbecomes>, since 6 October falls before the 1 September of a later year only. With no date of birth, a household calculation places the birthday on 6 April, so a 16-year-old outside education is a QYP for the year and a 17-year-old is not.Tests
YAML, hand-computed from the regulations: new
qualifying_young_person_no_education_route.yaml, 14 cases (2026-27 unless stated):date_of_birth15 September 2009 beside another household's 16-year-old with noneis_uc_work_allowance_eligible.yamlCase 6 expected no work allowance for "a nonqualifying 16-year-old" outside education, which reg 5(1)(a) contradicts. It now sets the route false, and a new Case 6a asserts the default.Fail on base (for the first 12 cases). With main's two QYP formulas restored, the new variable removed and its output lines stripped, the 10 cases that do not set the new input run: 7 fail and 3 pass. Cases 1, 2, 5, 6 and 9 fail on
is_qualifying_young_person_for_universal_credit([0, 0]for[0, 1]), case 11 onuc_individual_child_element(£0 for £4,222.56) and case 12 onchild_minimum_guarantee_addition(£0 for £4,215.64). Cases 7, 8 and 10, where the route does not apply, pass on both.Properties (
test_child_and_adult_definitions_properties.py, new invariant 5):date(2026, 4, 6) < first 1 September after the 16th birthday, computed with Pythondatearithmetic, which shares no code with the model's month grid.qualifying_young_person) gains the route for UC and PC, and the module docstring drops the route from its list of omissions.Mutation checks. Each mutation below was applied alone, and in each case a new test failed:
date_of_birthinput instead ofbirth_day(killed by case 14);>= 901to> 901(1 September birthdays);>=to>on the year;Two property tests elsewhere built "a member outside every programme's family" as a 16 to 19 year old not in education (
test_means_test_income_properties.py,test_legacy_award_readers_properties.py). At 16 that member is now a UC QYP, so the family gains a child element (£4,068 in 2025-26) and the premise fails. CI on6af701944failed on exactly these two tests, with 3,618 passed and the YAML suite at 2,972 passed. Their generators now set the route false for that member (2ef1d8dbf). The test functions are unchanged, so Hypothesis draws the same examples as on main.Run locally at
6af701944, plus the two modules above at2ef1d8dbf(test_legacy_award_readers_properties.py11 passed;test_means_test_income_properties.pypassed):pytest policyengine_uk/tests/test_child_and_adult_definitions_properties.py: 15 passed (12 existing, 3 new).policyengine-core teston the new YAML, the work allowance, QYP and benefit cap files: 44 passed.ruff formatandruff check: clean.The full suites run in CI, because the host was over its memory threshold for a full local run.
Review
Independent review r1c (Opus 5.5, Subfleet job
20261010-204535-qyp16-review-r1c; the Codex lanes had no capacity) APPROVED2ef1d8dbfand rulespec-uk#446 at15f391e, with seven P2 findings, all addressed inb171ef789:date_of_birth.axiom:line's companion case is on main.is_SP_ageuses.The review is in
~/reviews/pe-uk-qyp-sixteen-route-2026-10-10/review_r1c.md. A delta review (GPT-6.1 Sol,20261011-085419-qyp16-review-delta,review_delta.md) APPROVEDb171ef789with no new defects. rulespec-uk#446 merged first, as P2-2 asked (c65fd7dfb).addd1270dmerges main (43 commits), including the claimant-or-partner filter for PC and the move of Scottish CTR to the UC definition. Run on the merged tree: 66 YAML cases (this PR's file, the work allowance, benefit cap and means-test files, and main's new claimant and CTR young-person files) and 34 property tests (the child and adult definitions, CTR young person, legacy award readers and means-test income modules) all pass.Microsimulation impact
These are real
Microsimulationruns on the Enhanced FRS 2024-25 (uk-data release 1.57.4, SHA-25603fe15e4…8d4), run one at a time, each in its own venv, for 2025-26 to 2030-31:6d89338ab(main on 2026-10-11, which includes Narrow the legacy award readers property: an adult non-dependant ends the severe disability premium #2294 and the claimant-or-partner filter from9d3a9be5a);addd1270d(this PR merged with that main).Each run saved 38 arrays a year (
microsim_dump.py):uc_individual_child_element,is_uc_claimant, and BHC/AHC poverty;household_net_income,council_tax_reductionandcouncil_tax_less_benefit.Ids and weights were checked identical, and the arrays were compared exactly, with no tolerance.
What people receive: no change in any year. These differ in 0 records in every year from 2025 to 2030:
universal_creditanduniversal_credit_pre_benefit_cap;benefit_cap_reduction,housing_benefitandpension_credit;council_tax_reduction,council_tax_benefitandcouncil_tax_less_benefit;two_child_limit_payment,household_net_income,in_poverty_bhcandin_poverty_ahc.So do the cap's single rate, the LHA shared-rate test, and the CTR lone-parent test and applicable amount.
What changes:
Why the money doesn't move (2026-27):
9d3a9be5a, the PC child-or-QYP flag and Scottish CTR also exclude the benefit unit's claimant and partner, so only 7,372 of the new QYPs (the dependants) change the PC flag.would_claim_uc, verified false for all four) has them not claiming.pension_credit.An earlier run against
3173baa89(main before9d3a9be5a) gave the same paid outputs (all £0). Its PC child-addition intermediate rose by £1.0bn, because own-unit heads then counted as their own QYPs;9d3a9be5aremoved that.The route would reach the parents' claims only if the data put these 16- and 17-year-olds in their parents' benefit units. The uk-data investigation the UK hub started measured that on this branch against
3173baa89, with uk-data 1.58.0:traincolumn that no FRS release has policyengine-uk-data#560): UC £0;Whether to re-form those units is the open question in PolicyEngine/policyengine-uk-data#562.
Follow-ups (not in this PR; queued with the UK hub)
receives_benefits_in_own_rightcovers UC, ESA and JSA.has_sixteen_year_old_dependantin the UC cap's single rate is redundant with UC responsibility, except for 16-year-olds receiving benefits in their own right or looked after.9d3a9be5a).axiom: uk:regulations/uksi/2013/376/5#qualifying_young_person encoded-correct, companion case
aged_16_before_first_september_following_16th_birthday_without_education_or_training_qualifiesinuk/regulations/uksi/2013/376/5.test.yaml(TheAxiomFoundation/rulespec-uk#446, mergedc65fd7dfb); uk/regulation/uksi/2002/1792/4A TheAxiomFoundation/rulespec-uk#360 queued (corpus scope in TheAxiomFoundation/axiom-corpus#765 not yet released)🤖 Generated with Claude Code
Reproducer:
policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/work_allowance/is_uc_work_allowance_eligible.yaml::Case 6, a 16-year-old outside education past the reg. 5(1)(a) route does not create a work allowance.,policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/work_allowance/is_uc_work_allowance_eligible.yaml::Case 6a, a 16-year-old outside education in the reg. 5(1)(a) route creates a work allowance.,policyengine_uk/tests/policy/baseline/finance/benefit/qualifying_young_person_no_education_route.yaml,policyengine_uk/tests/policy/baseline/gov/dwp/means_test_income_members.yaml::A 17-year-old outside education and past the 1 September after their 16th birthday is not a UC young person, so their pay does not count,policyengine_uk/tests/test_child_and_adult_definitions_properties.py::test_route_year_starts_before_first_september_for_every_birthday,policyengine_uk/tests/test_child_and_adult_definitions_properties.py::test_route_matches_calendar_arithmetic_in_any_year