Repository navigation
Move families onto Universal Credit when a legacy benefit they receive closes - #2119
Conversation
…e closes Tax credits closed on 6 April 2025 and Income Support and income-based JSA on 1 April 2026, but the model kept paying a family's other legacy awards and paid Universal Credit only through would_claim_uc, which datasets draw without regard to legacy receipt. A family that drew it false was left with nothing once its tax credits stopped. - would_claim_uc_at_legacy_closure: dataset input (default true) saying whether the family claims Universal Credit when its legacy benefits close. - legacy_benefits_closed: a working-age family reports a legacy benefit that has closed (tax credits from 2025, IS and income-based JSA from 2026). - claims_universal_credit: would_claim_uc, or the closure and the flag. It replaces would_claim_uc in universal_credit, universal_credit_pre_benefit_cap, uc_has_deduction, is_CTC_eligible and housing_benefit_eligible. - Once a family's legacy benefits have closed, its Housing Benefit continuing award, Income Support, income-related ESA and income-based JSA end, whether or not it claims (SI 2014/1230 regs 8 and 46). Years before any closure are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ge WTC migrants Review r1 found that excluding every family on the Pension Credit route left out families DWP moved to Universal Credit: protected mixed-age couples and pension-age claimants on Working Tax Credit without Pension Credit (SI 2019/167 art. 3A; SI 2014/1230 reg 60A; DWP HB circular A9/2024). - legacy_benefits_closed now sends to Pension Credit only families on it, and families on Child Tax Credit but not Working Tax Credit that meet the Pension Credit age conditions (art. 3A(1)). IS and income-based JSA closures do not move wholly pension-age families (reg 8(2B)). - claims_uc_at_legacy_closure: the closure claim. - is_uc_eligible admits a closure claimant on the pension-age route: a protected mixed-age couple claims jointly, and a pension-age WTC recipient has the upper age condition waived (reg 60A). - left_pension_route_at_legacy_closure: such a family leaves the route if it claims, or as a protected mixed-age couple loses its Housing Benefit and saving at the deadline; Housing Benefit's pension-age route and Pension Credit eligibility honour it. - Tax credits (CTC and WTC) are masked for families moved off legacy benefits, so a reform keeping tax credits open does not pay them with UC. - Documentation: claims_universal_credit's scope, the UC notebook's two claim routes and how to decline both. - Tests: seven YAML cases for these routes and the reform; property tests now generate mixed-age couples, pension-age families and Pension Credit reporters, and check UC/PC and UC/HB exclusivity. The childcare grant overlap test pins legacy_benefits_closed false to keep testing the overlap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Status 02:45Z: head cf40b02 = 4313fbd (round-1 review fixes) + main merge, which brings main's read-only cache fixture fix for policyengine-core 3.32.16 (the earlier CI Test failure). The 2,109 policy YAML tests pass locally on core 3.32.16. Delta review r2 (Opus, |
…osure # Conflicts: # docs/book/programs/gov/dwp/universal-credit.ipynb # policyengine_uk/variables/gov/dwp/universal_credit/is_uc_eligible.py
…ependants for closure claims Review r2 (at cf40b02) found two blocking issues: - B1: a protected mixed-age couple that does not claim Universal Credit at the closure keeps its route. SI 2019/37 art. 4(3)(b)(ii) (inserted by SI 2024/604) lets it reclaim Housing Benefit within three months and keep the saving (DWP HB circular A9/2024 paras 12-13). left_pension_route_at_ legacy_closure now needs a closure claim and eligibility for Universal Credit, so a claimant refused on capital (reg 51 is not modelled) stays on the route rather than losing everything. - B2: uc_non_dependants_counted, merged from main (#2006), still read would_claim_uc, so a closure claimant's household non-dependants were not counted. It now reads claims_universal_credit. Also: stale notes now that reg 60A migrants are modelled (meets_pension_credit_age_conditions, housing_benefit_pension_age_ regulations_apply, the CTR pensioner comment, the HB passport doc); the changelog credits reg 3(2)(a) for mixed-age couples. Tests: the protected couple case, a capital-refused reg 60A claimant, a non-dependant case, a property that every closure claimant within the capital limit is eligible, and the sharers reference check reads claims_universal_credit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Independent review (GPT-6.1 Sol, UK hub sweep, 2026-10-12): REQUEST_CHANGES at the head below. The hub is routing it to this PR's owner session. Methodology readings the source leaves open go to Max as a decision before they're picked. VERDICT: REQUEST_CHANGES
Both changed YAML files passed: 36 tests. Property tests state invariants, with no introduced skips or xfails, but could not collect because
Both requested |
|
Independent GPT-6.1 Sol review after the adopted fixes and current-main merge: VERDICT: APPROVE — independent GPT-6.1 Sol code review No remaining code blockers. Actual UC claim helper, pre-cap UC entitlement pension-saving gate, national CTR scheme-year rules, native-PC non-dependant branch and corrected reg60A property exception reviewed. Variable/parameter trees match impact head. Runtime gates: complete final properties and remaining Python suite; prior run had six failures and one error before interruption in unchanged code-health subprocess tests. Workflow follow-ups: append verbatim new operative law to Axiom433; global nil-WTC decision still unqueued due denied ledger lock. No proxy approved. Follow-up by the build job: the Axiom operative-law requirement is now completed at TheAxiomFoundation/rulespec-uk#433 (comment) . Exact-head runtime checks are still in progress in the frozen environment; import profiling identifies slow ordinary filesystem reads before collection. Global methodology enqueue remains denied by the sandbox; its replay request is preserved. |
|
Hand-off to the UK hub at The three Sol blockers and regressions were already pushed by the interrupted attempt; its source tree was clean. This job merged current main Validation: preserved 3,094 passing policy YAML cases, 14 new YAML regressions and four focused Python passes from the completed prior checks; 2026 Enhanced FRS evidence remains in the PR body: main Axiom operative-law/companion-case addendum: TheAxiomFoundation/rulespec-uk#433 (comment) . Signed encoder remains blocked; none was run. Hub action required: nil/tapered WTC historical entitlement cannot be identified from the available inputs. No proxy selected. The requested global cos add-decision 'PolicyEngine/policyengine-uk #2119: choose how to identify pension-age and protected mixed-age Child Tax Credit recipients whose Working Tax Credit entitlement tapered to nil before tax-credit closure. Should we add a verified pre-migration WTC entitlement input and arrange upstream data coverage; explicitly approve a survey work-condition proxy with a stated reference year and limitations; or retain the documented gap until better inputs exist? No proxy has been selected.' --org cross --workstream 'UK: legacy-benefit closure migration' --priority medium --class none --deadline 2026-10-19 --resolves-on-merge no --source https://github.com/PolicyEngine/policyengine-uk/pull/2119 --source https://www.gov.uk/government/publications/housing-benefit-adjudication-circulars-2024/a92024-the-social-security-state-pension-age-claimants-closure-of-tax-credits-amendment-regulations-2024 --why 'DWP Housing Benefit circular A9/2024 paragraphs 6 and 10 send these nil-award WTC families to Universal Credit, while true CTC-only pension-age recipients take the Pension Credit route. The released Enhanced FRS 2024/25 v1.58.0 records positive reported benefit amounts and contemporaneous hours/incomes, but no historical WTC entitlement, migration notice, or tax-credit award type. Existing is_WTC_eligible requires positive working_tax_credit_reported and calls legacy_benefits_closed; reusing it cannot classify nil awards without circularity. Applying contemporary work conditions to infer the historical entitlement would be a methodology assumption requiring Max'"'"'s decision. The current PR therefore still omits these families, and its impact estimate must disclose this gap. This choice is separate from whether PR #2119 merges and must remain unresolved until Max rules.' |
|
UK hub (2026-10-12 13:05Z): the nil-WTC methodology question from the hand-off is now queued for Max as d1423: add a verified pre-closure WTC entitlement input, approve a survey work-condition proxy, or keep the documented gap. It is separate from merging this PR. The PR omits these families and says so. The hub is dispatching its own GPT-6.1 Sol review at |
|
Independent re-review (GPT-6.1 Sol, UK hub, from outside the build job): APPROVE at VERDICT: APPROVE
No remaining blocker or should-fix findings. The three blockers are resolved:
The nil-tapered WTC gap is accurately documented, with no proxy selected; the hub confirms decision Final-head variable and parameter trees exactly match impact commit No tests were weakened, skipped or xfailed. None of the PR-touched Python tests had executed before the six failures and one error in unchanged code-health subprocess tests. I found no plausible test-induced shared-state cause; missing tracebacks leave the actual cause unverified. Tests were not rerun: compressor usage was approximately 10.4 GB, but this worktree has no venv, and global No files changed or GitHub writes performed. |
|
Merged by the UK hub (audit). Merged with a merge commit at the tested head
|
Conflicts in esa_income_eligible.py and jsa_income_eligible.py: #2119 ended a reported award once one of the family's legacy benefits has closed (legacy_benefits_closed). Both screens keep this PR's remunerative work conditions and candidate rule unchanged and AND in main's closure term with main's comment verbatim; the documentation now names the closure. The closure is a benefit-unit condition separate from who claims, so the claimant, partner and candidate rules are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings in #2119 (UC claims at legacy closure), #2373, #1905, #2177, #2305, #2306, #2325, #2376, #2379, #2380, #2388 and #2364. One conflict, in the UC docs notebook: kept main's new paragraph on claims at legacy closure and this branch's benefit cap sentence. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#2119 (merged from main in 864eef6) ends every legacy award in a family once one of its legacy benefits has closed, through esa_income_eligible and jsa_income_eligible. own_report_is_paid read a failing benefit-unit screen as the couple's claim failing the work tests, which leaves a member outside the couple on their own claim; after the merge a closed family's screen fails too, so a non-working outside member stayed on ESA or JSA after the closure ended it. Main's own_report_is_paid required the screen to pass and so ended it. The outside member's own claim now also requires legacy_benefits_closed to be false. Two YAML cases (2025, a Child Tax Credit report closes the family's legacy benefits; a non-working lodger reports ESA or JSA) fail on 864eef6 and pass here. Documentation and the changelog say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…a simplification Answers the review of e743d8e (subfleet/review_final_e743d8ee7.md): 1. legacy_award_work_reference gains legacy_benefits_closed, #2119's closure as the model applies it (a report of Income Support or income-based JSA once closed, by any member, unless someone reports Pension Credit or the claimant and partner have all reached its qualifying age), and esa_screen and jsa_screen apply it. The work properties draw JSA reports in 2026, when income-based JSA is closed, so test_screens_match_a_family_by_family_reading failed there. 2. Invariant 4 is qualified: an outside member changes a screen only through the closure, which reads every member's reports. The property now asserts exactly that (the screen with them equals the screen without them while their report has not closed the family's legacy benefits). 3. The outside member's status following the closure (e743d8e) matches main and the money calculation, but is a model simplification: SI 2014/1230 regs 44(1), (4) and 46(1) reach only the claimant and partner. The docstring, the status variables' documentation, the YAML comments and the changelog now say so. Nits: the readers properties' docstring names the closure, and the status variables' documentation is reflowed (text otherwise unchanged). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review r6 (REQUEST_CHANGES on 587c0e7): 1. Main's #2119 closes income-based JSA and Income Support from April 2026 and then moves a family reporting either off all its legacy benefits (legacy_benefits_closed), ending its ESA, JSA and Income Support. Under disable_simulated_benefits, which pays every reported award in every year, an adult outside the couple was then paid ESA and JSA but not on them, since own_report_is_paid reads esa_income_eligible. The reform now holds legacy_benefits_closed false for its ten years (NOT_MOVED), as it already holds Universal Credit and the legacy awards at their reports, so every reader of the closure agrees with the awards it pays. New test: with the reform off every test family is moved from 2026; with it on, none is, in any of the ten years. The clone-or-branch test now compares the parent's ESA with an unreformed simulation's, which the closure ends from 2026, instead of expecting the excluded adult's uprated report. 2. From policyengine-core 3.33.0 derivative keeps every input, named or not (3.32.x deleted every variable input_variables does not name). The comments, the test docstring and the changelog now say reset_calculations deletes unnamed variables, as derivative did before 3.33.0. 3. _InputKeyLog docstring: a deep copy or pickle of a simulation logs nothing; a shallow copy shares the record, as it shares the holders. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…97ed) From the independent delta review (subfleet 20261013-010643, review-delta-d7697edee.md): - P1: utils/uc_work_related_requirements.py. The 10/9 merge (f4aa92b) kept this branch's whole copy of the file, which undid main's 7a71c86 (#2081 review item 5): couple_members() came back and claimants() stopped reading is_uc_assessed_claimant. The file is now main's, less the three shared-rules helpers this PR removes. No output changes: the two formulas were identical. - P2: is_uc_benefit_cap_exempt_qualifying_age said only a supplied award reaches reg 60C. Since #2119 a reg 60A claim by a Working Tax Credit recipient whose tax credits closed does too. - P3: housing_benefit_pension_age_regulations_apply said its UC-award rule was "right for the cap"; UC's reg 60C exception no longer reads it, HB's cap does. benefit_cap_welfare_benefits now says the benefit-unit amounts are counted whole (#2298). The UC notebook's cap sentence names reg 60C. The legacy closure differential also compares uc_benefit_cap_reduction, which still reads the claim route through the UC award. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes #2118
Tax credit closure in 2025 and Income Support/income-based JSA closure in 2026 ended families' legacy awards even when their ordinary UC take-up flag was false. This PR adds
would_claim_uc_at_legacy_closure(default true), combines it with ordinary take-up inclaims_universal_credit, and terminates other legacy awards at migration. It uses annual closure years rather than migration dates.The Sol review blockers are addressed:
The migration destinations follow SI 2014/1230 regs. 8, 44, 46 and 60A, SI 2019/167 art. 3A, and DWP HB circular A9/2024. Positive reported WTC pension-age families may claim UC; PC reporters and pension-age CTC recipients without reported WTC take the PC route, subject to the limitation below. Claimants who decline migration or have nil UC entitlement retain the modelled pension-age route.
Known methodology gap requiring Max
DWP A9/2024 paragraphs 6 and 10 send pension-age/protected mixed-age CTC recipients whose WTC entitlement tapered to nil to UC. Enhanced FRS reports award amounts and current annual hours/income, but does not identify pre-migration WTC entitlement, historical hours, or a migration notice. Existing WTC variables require positive reported WTC and refer back to legacy closure, so they cannot identify this historical entitlement independently.
No proxy has been chosen. Max needs to choose between a historical-entitlement input upstream, an explicitly approved reconstruction proxy, or retaining this disclosed gap pending better data. The requested
cos add-decision ... --source https://github.com/PolicyEngine/policyengine-uk/pull/2119 --resolves-on-merge nofailed because this job cannot write the global ledger lock at/Users/maxghenis/chief-of-staff/state/decisions/.lock. The decision must be transferred to the global queue by the hub; it is not yet queued there.Other limitations remain: in-year migration timing and two-week run-ons; transitional protection including the capital disregard; specified/temporary accommodation savings; and benefit-maximising choice between UC and pension-age routes. Existing HB-only/ESA-only abolition work remains separate.
2026 enhanced-FRS impact
2026 Microsimulation: main
3381500f4b01bc0a0cd5f447e56f07741af36ae2against branch4cb49f45363c3540ac6c62c05c429090d166b4f4.The released Enhanced FRS 2024/25 v1.58.0 has SHA256
5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6. Its hash matches the release manifest. Both sequential runs use the same file and frozen environment (policyengine-core 3.33.2). The dataset lackswould_claim_uc_at_legacy_closure, so the default true applies. No recalibration or dataset rebuild was run. Totals sum household-mapped awards against household weights.Validation
make formatanduvx ruff format --check .passed, including the final test-only commit. Notebook JSON is valid and code cells are unchanged from the reviewed PR; a full local book build was not run for this prose-only correction.Reproducer: policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/legacy_closure_ineligible_partner.yaml; policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/legacy_closure_pension_route.yaml; policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/legacy_closure_migrant_nations.yaml
Independent GPT-6.1 Sol code review: APPROVE at final head
fa4389d6f6d79f68312e3961981f9ea11abe2ea4. This includes the final property-test correction at84c760bf4and a merge of current maine01f2f5ecthat only updates release bookkeeping. Variables and parameters are byte-identical Git trees to impact head4cb49f45363c3540ac6c62c05c429090d166b4f4; current main retains the baseline impact code trees. The prescribed Subfleet launcher failed staging to its external inbox; the fresh review used an independently spawned exact GPT-6.1 Sol model. Runtime validation and the blocked global decision enqueue remain separate follow-ups.axiom: SI 2014/1230 regs 8, 46 and 60A; SI 2019/167 art 3A: TheAxiomFoundation/rulespec-uk#433 queued. The queued issue includes SI 2024/604 and national CTR source provisions, verbatim operative-law quotations, required outputs and law-derived companion cases: TheAxiomFoundation/rulespec-uk#433 (comment) . The signed encoder is blocked; no encoder was run by this job.