Skip to content

Use each rule's own Universal Credit earned income in the benefit cap, targeted childcare and local CTR - #1999

Draft
MaxGhenis wants to merge 19 commits into
mainfrom
uc-earned-income-consumers-1986
Draft

MaxGhenis wants to merge 19 commits into
mainfrom
uc-earned-income-consumers-1986

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #1986

Depends on #1820

This draft is stacked on Vahid Ahmadi's #1820 at ea2b87cece52736992dc6ce1860f16b2a02b0325. It must not merge before #1820. Vahid's work lands through his PR; after it merges, merge main here so this diff reduces to the #1986 changes. Main 0bc08f2fd45a4dc5215da7f4a055978226635f36 was merged without conflicts as 00d4bdb0328e7f915fd6aaea62ff091d67f57141 on 12 October 2026.

Vahid's #1820 contributes the parameterised earnings threshold, earnings-attributable tax measure, Armed Forces Independence Payment exception, surrounding exception structure, removal of dead code and corrected labels, its 12 YAML cases and 1818.fixed.md, and removal of the strict dividend-property xfail. This branch preserves that work. The earnings measure is the part replaced for #1986.

This PR adds:

  • benefit_cap_earned_income: sum each assessed claimant's uc_individual_earned_income_before_mif, using main's individual definition. Each person deducts their own tax and NI on earnings and relievable pension contributions. Voluntary Class 3, tax on unearned income and contributions paid at 75 do not reduce it; minimum income floor income is excluded.
  • UC award scope: a Housing Benefit award without a UC award does not get the UC earnings exception.
  • Earlier values in Fix benefit cap exemption defects (#1818) #1820's gov.dwp.benefit_cap_earnings_exemption parameter: £430 monthly from 29 April 2013, then £520, £542 and £569 from April 2017, 2018 and 2019. The old derived threshold variable and its separate parameters are removed. The differential test compares every dated value from April 2017 with the minimum wage parameter and statutory rounding.
  • uc_earned_income_before_work_allowance: preserve main's assessed-claimant member rule and individual minimum income floor treatment; uc_earned_income subtracts the work allowance and floors at zero.
  • Targeted childcare's UC criterion and the Kingston upon Thames, Merton, Newham and Westminster CTR helper use earnings before the work allowance. The childcare and UC pages document the measures; the single-person claim test comment gives the rounded threshold.

The pension-tax approximation and pension-age sentence in #1820's earnings-file comments are replaced because the new measure makes them inaccurate. Its AFIP and health/disability changes, dead-code removal, tests and fragment remain. Main's other individual earnings changes, including #2327's miscellaneous-loss treatment, remain intact.

Code at this head: cap income, threshold and pre-cap award scope, pre-allowance claimant sum, childcare, and CTR.

Law and scope

Primary texts were retrieved again on 12 October 2026. Their substantive XML matches the saved point-in-time evidence; all four freshly retrieved official borough PDFs are byte-identical to the saved scheme copies.

UC Regs 2013 reg 82 applies to “an award of universal credit”. Paragraph (1)(a) uses 16 hours at the reg 4 national living wage rate, converted by 52/12; paragraph (4) excludes “income a person is treated as having by virtue of regulation 62”. Reg 6(1A)(za) requires the fractional pound to be disregarded. SI 2017/138 introduced the formula and rounding from 1 April 2017; reg 82 as made gave £430.

NMW Regs 2015 reg 4 April 2017–2026 rates are £7.50, £7.83, £8.21, £8.72, £8.91, £9.50, £10.42, £11.44, £12.21 and £12.71. The corresponding monthly thresholds are £520, £542, £569, £604, £617, £658, £722, £793, £846 and £881. The 2023 rate was already corrected by merged #2053; this PR tests the £722 threshold and carries no #2053 caveat.

HB Regs 2006 reg 75E(2) instead excepts work through entitlement to Working Tax Credit. The model applies that through the existing health/disability exception. Because its reduction currently caps both awards, the UC earnings test must not lift the HB cap. This branch reads both awards before the cap: is_uc_entitled for UC and housing_benefit_pre_benefit_cap for HB. Reading pre-cap awards avoids a circular dependency. With HB and no UC the earnings exception is false. With neither award it returns the earnings test; that fallback preserves #1820's cases and changes no award amount.

SI 2014/2147 reg 1 defines the targeted-childcare UC income measure by Part 6 Chapter 2 of the UC Regulations. The work allowance belongs to reg 22, in Part 3. The existing annual model limit remains £15,400; the legal one-, two- and three-assessment-period limits are £1,283.34, £2,566.67 and £3,850. This PR changes the earnings measure, while retaining the model's annual approximation and existing minimum income floor treatment.

Default Scheme Schedule para 37 uses the Secretary of State's UC income calculation and adds the award. Kingston and Merton's 2026–27 para 37 reproduce that provision; Newham's 2026 para 37 refers to the UC entitlement income calculation; Westminster's 2026–27 summary adds the actual award and other income and earnings. None deducts the work allowance. The official scheme URLs are in parameter metadata under gov/local_authorities/{borough}/council_tax_reduction.

Miscellaneous income and review findings

P2: the award and cap share uc_individual_earned_income_before_mif. Following current main, it counts taxable_miscellaneous_income, so a miscellaneous loss does not reduce employment earnings. Positive miscellaneous income is still classified as earned by the award. The FRS field mixes paid work (reg 52) with royalties, trust income and overseas pensions that reg 66 treats as unearned. #1961 remains open for the split. This limitation is documented in the cap variable and pinned by the synthetic £11,000 YAML case: both measures and the exception agree. A correct classification split needs data work and is outside this PR. No national-impact bound is claimed pending the refreshed runs.

P3: this body is audited against current code and sources. The stale #2053 caveat, dead-code claims and earlier-main impact claims are removed. Main has merged #1949 and #1973; their assessed-claimant and individual-income definitions are preserved.

P1: previous population tables and their output-file citations are removed. They used an earlier main and had not passed a joint disclosure audit. The replacement publication script counts distinct survey households, suppresses all change values involving households behind primary-small cells or small subgroup residuals across comparisons and years, and uses common base deciles and only base absolute levels/rates. Its synthetic checks pass. The certified runs and real-output audit remain pending, so this body publishes no national-impact figures. A small cell is never published as a weighted count or amount.

Tests and invariants

Hand-derived YAML includes 29 cap cases, 9 targeted-childcare criterion cases and four borough counterexamples, plus #1820's 12 unchanged cases. It covers the partner's £923 Class 3 counterexample; claimant-only aggregation; exclusion of floor income; relievable contributions at 74 versus 75; tax on property income; the £722 monthly 2023 threshold; and 2026 income £10,571 versus £10,572 at the £881 monthly threshold. Childcare cases include £16,500 pay giving £15,399.60 earned income and £16,501 giving £15,400.32, either side of the annual model limit.

Eight Hypothesis/differential tests in test_uc_earned_income_consumers_properties.py check: unearned tax and voluntary NI invariance; equality with pre-allowance UC income when no floor applies and exclusion of floor income; the exception/HB scope identity; childcare and CTR bounds; childcare monotonicity; the CTR hand reference; and the dated threshold/rounding differential. Dividend and rent property pins exercise the removed xfail and tax-on-unearned-income defect.

Current continuation results:

  • Ruff format/check pass for all ten Python files in the PR diff; git diff --check is clean.
  • Latest-main focused YAML: 106 passed in 99.35 seconds, including all 12 unchanged Fix benefit cap exemption defects (#1818) #1820 cases.
  • Required Python files (test_uc_earned_income_consumers_properties.py, test_uc_income_from_capital_properties.py, test_uc_state_pension_properties.py): 20 passed, 1 expected xfailed in 1,278.47 seconds with uv run ... python -m pytest -n 3 -v. All eight consumer properties and both dividend/rent pins pass. The existing strict xfail is test_state_pension_does_not_change_partners_marriage_allowance, tracked separately in Marriage Allowance is booked on the recipient as the transferor's unused allowance, not the fixed s.55B transfer #1947.
  • Further related files (test_uc_claimant_income_properties.py, test_uc_earnings_deductions_properties.py, test_uc_minimum_income_floor_properties.py, test_benefit_cap_and_ctr_pension_age_properties.py): 19 passed in 636.95 seconds, also with at most three workers. Local Python total: 39 passed, 1 expected xfailed.
  • CI at 00d4bdb03: 3,112 YAML cases passed (1 warning, 142.51 seconds) via policyengine-core test policyengine_uk/tests/policy -c policyengine_uk, covering every requested related folder. Lint, documentation build checks and Python 3.11–3.14 smoke imports pass. Python shards 1/3 and 3/3 pass; 2/3 remains in progress at the final check. CI run.
  • The saved checkpoint focused run had 351 passed at 36f747121. The saved broad run had 1,886 passed before that main merge. These are historical results, not passes claimed for the newest main.
  • Full related YAML folders through the required machine-wide helper: blocked by the sandbox before execution, as explained below.

Fail-on-main refresh: ten semantic cases assert variables present in base, mid and head, avoiding missing-variable failures. At the new SHAs listed below, base and mid each have 7 failed, 3 passed; head has 10 passed. Main fails cap Class 3, childcare, Merton CTR, the fixed-threshold rounding edge, the historical threshold and tax-on-property/Class-3 cases. Mid fails Class 3, childcare, CTR, historical threshold, HB scope and contributions at 75. The de-xfailed dividend/rent property examples both fail on current main (2 failed, 5 deselected), pass on mid (2 passed, 5 deselected) and pass on head in the complete required Python run. The prior failures are thus reproduced at the refreshed base rather than inferred from old main.

Saved mutation logs kill M1–M11: main's tax/NI measure; #1820's deductions; counting floor income; removing HB scope; omitting threshold rounding; omitting pre-2020 values; counting all members; childcare or CTR after the allowance; reversing childcare's inequality; and requiring a UC award outright. These runs preceded the newest-main merge and are retained as historical evidence. No new mutation pass is claimed here.

Certified-pair impact: refresh blocked

Required dataset: uk-data 1.58.0 enhanced_frs_2024_25.h5, certified SHA-256 5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6 (the manifest's certified pair uses UK 2.125.1). The refreshed comparison is prepared for:

The checkpoint's refreshed impact never executed because its zsh loop collapsed the three labels into one. That runner is corrected. The new foreground attempts at ~/reviews/us-hub/scripts/heavy_run.sh exit 75 before taking the lock: the sandbox denies /bin/ps and the fallback os.nice(0). No dataset run starts, and no earlier result is scaled or reused as current impact.

Thus 2025–2030 base→mid (#1820), mid→head (#1986) and base→head totals, earnings-exception changes, UC losses/gains, targeted-childcare eligibility, CTR, household income, government balance, poverty and deciles remain unverified. Updated numbers and real-output disclosure verification are required before approval. No current numeric impact table is available.

Overlaps

All listed PRs remain open; none is edited or commented on here. The later lander must preserve:

Axiom

Checked against rulespec-uk main b918260427b91eafabdade7fb5630f5d1b4123e6, with all four issues open. #399's stale mapping/ownership text, #400's stale impact/monthly-limit claims, #401's stale population statement/fixture provenance and #57's obsolete encoding claim and missing pe-parity label are corrected. Prior national-impact assertions in the earlier #400 and #57 comments are withdrawn. Signed encoding needs separate approval; no encoder ran.

  • axiom: uk:regulations/uksi/2013/376/82 TheAxiomFoundation/rulespec-uk#399 queued — dated thresholds and whole-pound rounding remain outstanding.
  • axiom: uk:regulations/uksi/2015/621/4 TheAxiomFoundation/rulespec-uk#399 queued — historical rates remain outstanding; the current module contains the 2026 rate.
  • axiom: uk:regulations/uksi/2014/2147/1 TheAxiomFoundation/rulespec-uk#400 queued — targeted-childcare income provision remains unencoded.
  • axiom: uk-{kingston-upon-thames,merton,newham,westminster}:policies/*/council-tax-reduction TheAxiomFoundation/rulespec-uk#401 queued — UC income remains an opaque input.
  • axiom: uk:regulations/uksi/2006/213/75E TheAxiomFoundation/rulespec-uk#57 queued — the HB current/recent-work exception remains unencoded.

Not verified

Refreshed certified-pair impact, its final disclosure audit and the required heavy-lock broad local YAML rerun are blocked by the sandbox; CI's complete YAML suite passes. The annual model does not implement reg 82's nine-month grace period or childcare's assessment-period look-back. NLW rates after 2026–27 remain absent, so the current threshold stays £881 monthly thereafter. A docs build and full-repository suite were not run locally; CI results are recorded separately above. All local test processes have completed, and scratch exports/dataset-copy directories are removed. The current body and updated parity comments contain no national-impact values; historical edit revisions and external archives have not been certified by this continuation.

🤖 Generated with Claude Code

Reproducer: policyengine_uk/tests/policy/baseline/finance/benefit/family/universal_credit/claims_as_single_person.yaml, policyengine_uk/tests/policy/baseline/gov/dfe/targeted_childcare_entitlement/meets_universal_credit_criteria_for_targeted_childcare_entitlement.yaml, policyengine_uk/tests/policy/baseline/gov/dwp/benefit_cap/benefit_cap_earnings_exception.yaml, policyengine_uk/tests/policy/baseline/gov/dwp/benefit_cap/is_benefit_cap_exempt.yaml, policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction.yaml, policyengine_uk/tests/test_uc_earned_income_consumers_properties.py::test_benefit_cap_exception_ignores_tax_not_on_earnings

MaxGhenis and others added 4 commits October 1, 2026 09:52
…ldcare and local CTR

Fixes #1986.

- Benefit cap earnings exception (UC Regs 2013 reg 82): earned income is
  each person's earnings less their own tax, NI and pension contributions,
  summed over the unit, without the minimum income floor (reg 82(4)). The
  threshold is 16 hours a week at the national living wage, x 52 / 12, in
  whole pounds (reg 6(1A)(za)), x 12; GBP 430 a month before 1 April 2017.
- Targeted childcare (SI 2014/2147 reg 1(3)(a)) and the Kingston, Merton,
  Newham and Westminster CTR schemes (Default Scheme para 37) read earned
  income before the work allowance, the new
  uc_earned_income_before_work_allowance, which uc_earned_income now uses.
- uc_individual_earned_income_before_mif is copied unchanged from #1973 so
  the two PRs add identical files.
- Adds the missing 2023-24 minimum wage rates (SI 2023/354).

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

- The Class 3 and unearned income property now bumps one adult in every
  family by a realistic amount and mixes in earners just above the
  threshold, so it fails against the pre-#1986 formula (it did not before).
- Adds a reg 82(4) property: switching every minimum income floor off never
  changes benefit cap earned income.
- Moves the benefit cap earnings exception docs into a separate notebook
  cell, leaving the means-test cell that #1973 also edits untouched.

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

Follows #1949's f333e17: contributions paid after 75 are not relievable
(Finance Act 2004 s. 188(3)(a)), so reg 55(5)(a) does not deduct them.
uc_individual_earned_income_before_mif now matches uc_individual_earned_income
apart from the minimum income floor. #1973 carries the same file without
this change; whichever merges second takes this version.

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

Copy link
Copy Markdown
Collaborator Author

Heads-up on an overlap: #2053 (fixes #2044) adds the same 1 April 2023 minimum wage rates as a standalone fix, cites the S.I. and regulation for every dated rate, and adds a pytest transcribed from the S.I.s.

Once #2053 merges, this PR should drop its two gov/hmrc/minimum_wage parameter hunks and the uc-earned-income-consumers-1986-nmw-2023.fixed.md fragment when it rebases; both parameter files will conflict otherwise. The five 2023 cases in tests/policy/baseline/finance/income/minimum_wage.yaml are copied verbatim into #2053 (minus a trailing blank line), so that hunk should merge with at most a trivial end-of-file conflict. The benefit cap threshold here depends on the 2023 rate, which #2053 provides.

🤖 Generated with Claude Code

Independent review of b696f8d (legal/code and tests/impact lanes):

- The benefit cap is shared with Housing Benefit, so the UC earnings
  exception also excepted HB claimants; with the NLW-based threshold that
  newly excepted some in years when the threshold was under 10,152. Reg
  82(1) applies "to an award of universal credit"; HB has its own
  exceptions (HB Regs 2006 regs 75E and 75F, WTC entitlement already in
  is_benefit_cap_exempt_health_disability). The income test is now
  uc_benefit_cap_earnings_threshold_met, and the exception needs a UC award
  before the cap as well. Adds the reviewer's HB regression.
- Documents that the cap counts miscellaneous_income as the UC award does
  (FRS misc is mainly odd-job pay, reg 52(a)(iii)); the reg 66(1)(m)
  royalties split will move both together.
- Tests: exact pins at 10,572 and 15,400, ages 74/75 for relievable
  contributions, a London BRMA in the counterexample, a floor-dependent
  childcare case, and a fixed 16,500 -> 16,501 childcare crossing in the
  monotonicity property (it kills a reversed-inequality mutant the random
  draws missed). Property 1 compares the income test, and the exception
  where there is a UC award both ways.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#2053 adds the same S.I. 2023/354 rates with regulation-level citations
and tests, so #1999 no longer carries them and the two do not conflict.
The benefit cap's 2023-24 threshold follows once #2053 merges (722 a
month; 658 until then). The 2023 benefit cap cases move to 2024-25
(793 a month = 9,516 a year): the 9,520/9,500 pair and the Housing Benefit
regression (9,600 earnings, cap 25,323). The property tests sample 2024
instead of 2023.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 2, 2026 10:19
…c-earned-income-consumers-1986

# Conflicts:
#	policyengine_uk/variables/gov/dwp/universal_credit/income/uc_earned_income.py
After #1896, is_claimant_or_partner is inferred when not given, and an
adult under 20 who is 16+ years younger than the other can be presumed a
child. The generated families have at most two adults, both claimants, as
#1949's fixtures now declare.

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

Copy link
Copy Markdown
Collaborator Author

Coordination with #2089 (each scheme its own benefit cap), stacked on #2084.

#2089 moves the reg 82 earnings exception to is_uc_benefit_cap_exempt_earnings (UC only) and deletes is_benefit_cap_exempt_earnings.py. HB has its own exceptions (75E working tax credit, 75F), so this PR's "and UC before the cap" gate is no longer needed: is_uc_benefit_cap_exempt_earnings only reaches UC through uc_benefit_cap.

Whichever lands second: put this PR's benefit_cap_earned_income and benefit_cap_earnings_threshold test into policyengine_uk/variables/gov/dwp/universal_credit/benefit_cap/is_uc_benefit_cap_exempt_earnings.py, without the UC-award condition.

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Note from #1949 (head 8c88c7c, not merged yet): it adds a strict xfail pinned to #1986 that this PR will flip to XPASS.

  • test_tax_on_dividends_does_not_remove_the_benefit_cap_earnings_exception in policyengine_uk/tests/test_uc_income_from_capital_properties.py. Case: single London claimant aged 30, council rent £20,000, earnings £11,000, dividends £10,000. With the dividends the cap's earnings exception flips off and final UC drops £2,081.80, because is_benefit_cap_exempt_earnings nets all income tax off earnings.
  • Remove the marker when this branch next merges Deduct only each person's own tax and NI on earnings from UC earned income #1949 or main.
  • In the same file, test_interest_dividends_and_rent_leave_the_award_unchanged compares universal_credit only where is_benefit_cap_exempt is unchanged. Once the exception is fixed here, the same_cap filter and the docstring paragraph about Benefit cap, targeted childcare and local CTR use the wrong UC earned income figure #1986 can go.

MaxGhenis added a commit that referenced this pull request Oct 4, 2026
Brings the branch up to main at be877c8, which includes #1949
(fc1ecc4) and #1943.

Conflicts:
- docs/book/programs/gov/dwp/universal-credit.ipynb: main's notebook
  with this PR's minimum income floor paragraph re-inserted after the
  earnings-deductions sentence.
- uc_individual_earned_income.py: this PR's reg 62(2)/(3) floor. Main's
  Finance Act 2004 s.188(3)(a) age filter on pension contributions is
  ported to uc_individual_earned_income_before_mif, where this PR takes
  the deductions; the file is copied as is from #1999 (blob 73a9370)
  so the two PRs merge in either order.
- test_uc_earnings_deductions_properties.py: main's file with this PR's
  start-up-period note, the pre-#1942 gross earnings and invariant 4's
  start-up setting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vahid-ahmadi and others added 2 commits October 8, 2026 15:26
Four defects in the benefit cap exception logic:

1. The earnings exception subtracted total income tax liability from
   earnings, so tax on property, savings, dividend and pension income
   reduced measured net earnings. Regulation 55(5) of the Universal
   Credit Regulations 2013 deducts only the tax paid in respect of the
   employment, primary Class 1 NI and relievable pension contributions.
   Now uses earned_income_tax, national_insurance and
   pension_contributions.

2. The earnings threshold was hardcoded as 10_152 in three files. Moved
   to the dated parameter gov.dwp.benefit_cap_earnings_exemption,
   expressed monthly as reg. 82 and DWP do, with values for 2020-21 to
   2026-27 derived from 16 hours a week at the National Living Wage.

3. Armed Forces Independence Payment is a statutory exception but was
   never checked. Added to the health/disability qualifying benefits.

4. Removed dead copy-pasted code from all three is_benefit_cap_exempt_*
   variables, keeping each one's return semantics unchanged apart from
   defect 3.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…s fix makes it pass

The earnings exception to the benefit cap now nets only earned_income_tax off
earnings, so tax on dividends no longer removes it (#1986).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 5 commits October 11, 2026 12:41
Conflicts:
- uc_earned_income.py: main's documentation and references, reading the
  branch's uc_earned_income_before_work_allowance; the work allowance still
  comes off it (max(0, before - work allowance)).
- is_benefit_cap_exempt_earnings.py: the branch's version for now; it is
  reworked on top of #1820 in the next merge.

Semantic follow-ups to main's claimant rule (is_uc_assessed_claimant, from
#1978): uc_earned_income_before_work_allowance and benefit_cap_earned_income
now sum over the assessed claimants with add_for_members, as main's
uc_earned_income did. uc_individual_earned_income_before_mif is main's (the
branch's copy was identical). benefit_cap_earned_income documents that
miscellaneous_income is counted as the award counts it (#1961). The CTR
helper comment names the Default Scheme regulations correctly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch is stacked on #1820 and must not
merge before it. #1820's changes (AFIP exception, dated earnings threshold
parameter, earnings-attributable tax in the reg. 82 test, dead-code removal,
its YAML tests, changelog fragment and the dividend xfail removal) are
Vahid's and land through #1820.

Conflicts:
- is_benefit_cap_exempt_health_disability.py: main's claimant scoping
  (not_a_claimant, add_for_members) kept; #1820's removal of the dead
  earnings block and its AFIP entry applied on top.
- is_benefit_cap_exempt_earnings.py: #1820's version. The next commit
  replaces only its earned income measure for #1986.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#1820 measures the benefit cap's earned income as earnings less
earned_income_tax, national_insurance and pension_contributions. That still
deducts tax on pension and property income, all Class 3 (the #1986
counterexample: a partner's 923 of voluntary Class 3 removed a couple's
exception) and contributions paid after 75. Replace only that measure with
benefit_cap_earned_income: each claimant's uc_individual_earned_income_before_mif
(earnings less their own tax and NI on those earnings and relievable pension
contributions), summed over the claimants, without minimum income floor
income (reg. 82(4)). #1820's structure, threshold parameter and comments stay;
the comments its measure made untrue are edited.

Reg. 82(1) excepts "an award of universal credit", so the exception no longer
lifts the cap on a Housing Benefit award without Universal Credit (HB's own
work exception is WTC entitlement, HB Regs 2006 reg. 75E). Families with
neither award keep the income test, so #1820's YAML cases are unchanged.

Threshold: drop #1999's own NLW derivation (benefit_cap_earnings_threshold,
uc_benefit_cap_earnings_threshold_met and the earnings_exception parameters)
in favour of #1820's gov.dwp.benefit_cap_earnings_exemption, extended back
with cited values: 430 a month from 29 April 2013 (reg. 82(1)(a) as made),
then 520, 542 and 569 for 2017-18 to 2019-20 (S.I. 2017/138; NMW Regs 2015
reg. 4; reg. 6(1A)(za)). A differential test checks every dated value from
April 2017 against floor(16 x NLW x 52 / 12) from gov.hmrc.minimum_wage.

Tests: the cap YAML moves onto the parameter with boundary pairs for 2016,
2017, 2018, 2019 and 2023 (722 a month); the property file computes the
income test from the parameter and loads the model once per module; a rent
pin joins #1820's de-xfailed dividend case; the floor childcare case names
the responsible carer, since main now defaults the nomination to the elder.

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

The cap's earned income shares uc_individual_earned_income_before_mif with
the UC award, which counts miscellaneous_income as earned. The FRS input
mixes paid work with royalties, trust income and overseas pensions, which
reg. 66(1) treats as unearned; #1961 tracks the split. A YAML case pins the
shared treatment so the #1961 fix moves the award and the cap together.

Also corrects a test comment that still described a fixed 10,152 threshold.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each case now checks is_benefit_cap_exempt_earnings as well as the earned
income, so a measure that deducts contributions paid after 75 (not
relievable, Finance Act 2004 s. 188(3)(a)) fails the exception test too.

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

Copy link
Copy Markdown
Collaborator Author

CI run cancelled to free runners (UK hub, 2026-10-11 23:30Z). The PolicyEngine org is at GitHub's limit of 60 concurrent jobs, with about 360 queued. Fleet ops asked the hub to let the Budget-critical #2305 take runners first. This PR's queued run had not started, so I cancelled it. Nothing is wrong with the PR.

Please don't re-run it or push just to retrigger CI. The hub re-runs this run itself once #2305 has runners. The record is ~/reviews/uk-hub/ci-yield-2026-10-11.json; see notice 17 in ~/reviews/uk-hub/notices.md.

Brings in #2349 (round-trip recorded inputs) and #1925 (DWP 2025-26
announced rates). No conflicts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Includes the reform-contract and tax-band fixes; preserves the stack on #1820 without conflicts.

Co-Authored-By: OpenAI Codex <noreply@openai.com>

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.

Benefit cap, targeted childcare and local CTR use the wrong UC earned income figure

2 participants