Skip to content

Add the child disability premiums to pensioner Council Tax Reduction - #2861

Draft
MaxGhenis wants to merge 67 commits into
mainfrom
claude/pensioner-ctr-disability-premiums-9b4amp
Draft

MaxGhenis wants to merge 67 commits into
mainfrom
claude/pensioner-ctr-disability-premiums-9b4amp

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #2824
Reproducer: policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner_child_disability_premiums.yaml::Case A2 England, a child on the highest DLA care rate adds both premiums.; policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner_child_disability_premiums.yaml::AFIP England 2023, a child under 16 on AFIP alone meets the enhanced condition only.
axiom: TheAxiomFoundation/rulespec-uk#533 queued

This PR lands after #2826 and #2808. Its first commit, 5acffdbd8, merges #2808's head (6563f73e5) into #2826's head (06e51a8ab) with no conflict (tree ef486deac). Review the commits after it:

  1. e2699b77 moves the conditions that Housing Benefit and CTR share into one helper;
  2. 67004f48 adds each nation's amounts and AFIP routes as parameters;
  3. e4767ab5 adds council_tax_reduction_pensioner_child_disability_premiums and adds it to a pensioner's council_tax_reduction_premiums;
  4. 7d8b70dd adds the YAML cases;
  5. 9ef585de adds the property tests and the changelog fragment;
  6. a2434433 merges main at 9b456bda6 (tree 8f3bdeef6);
  7. f00ad5be gives the family-total oracle the lower DLA mobility age and adds explicit examples for that boundary and for each AFIP route;
  8. 2df03f2b adds the Northern Ireland nil case and cites each nation's own provisions in the YAML comments;
  9. 16a74f81 names the actor in the comments, docstrings and parameter notes;
  10. 6e96ffef cites the Welsh and Scottish provisions in the A2c comments and drops a pronoun from a case name;
  11. 5a6c8d9e merges Add pensioner CTR child amounts and uncap Scotland's tariff income #2826's head at 87cbc397e (tree 4c486e260), with no conflict;
  12. 254fac3c merges main at 5c7744144 (tree 50316afa1), with no conflict.

What the model does now

Councils add the disabled child premium and the enhanced disability premium to a pensioner's applicable amount for each qualifying child or young person in the family: England under SI 2012/2885 Sch 1 para 6(1)(d) and Sch 2 paras 7, 8 and Part 4; Wales under WSI 2013/3029 Sch 1 para 1(1)(d) and Sch 2 paras 7, 8 and 12; Scotland under SSI 2012/319 reg 20(d) and Sch 1 paras 8, 9 and 13. Before this PR the model added neither for pensioners.

  • council_tax_reduction_pensioner_child_disability_premiums (BenUnit, YEAR, GBP) sums over the family's children and young persons (is_child_or_young_person_for_council_tax_reduction). Each who meets the disabled child condition adds 52 times the nation's disabled child premium, and each who meets the enhanced condition adds 52 times its enhanced disability premium. It returns nil for a working-age family, for a household head who applies alone, and outside England, Wales and Scotland, as council_tax_reduction_pensioner_child_amounts does.
  • A new helper, child_disability_premium_benefit_conditions (policyengine_uk/variables/gov/dwp/housing_benefit/_child_disability_premiums.py), returns the conditions the two schemes share. The disabled child condition rests on a positive DLA or PIP amount (either component) or is_blind, and the enhanced condition on has_highest_dla_sc_award or has_enhanced_pip_dl_award. housing_benefit_child_disability_premiums and the new variable each add their own armed forces independence payment (AFIP) route.
  • For a pensioner, council_tax_reduction_premiums now adds the new variable to pension_age_benefits_premiums, and so holds every premium that Sch 1 para 6(1)(d) includes.
  • For "young person" in the AFIP routes the formula reads is_qualifying_young_person_for_child_benefit, the Child Benefit qualifying young person. The Secretary of State, the Welsh Ministers and the Scottish Ministers define a young person by SSCBA s.142 (SI 2012/2885 reg 2; WSI 2013/3029 reg 2; SSI 2012/319 reg 4), and is_child_or_young_person_for_council_tax_reduction applies that definition to every pensioner's family. Anyone counted who does not meet it is a child under 16.

Amounts and their sources

The Secretary of State, the Welsh Ministers and the Scottish Ministers set both amounts in the table of premium amounts in each schedule (England Sch 2 Part 4 entries (2) and (3); Wales Sch 2 para 12 entries (2) and (3); Scotland Sch 1 para 13 entries (2) and (3)). Each parameter cites the version in force on 30 April of the year, at https://www.legislation.gov.uk/<instrument>/schedule/<n>/<year>-04-30. They set the same amounts in all three nations, in pounds a week:

From Enhanced disability premium Disabled child premium
2013-04-01 (England, Scotland) 23.45 57.89
2014-04-01 (all three; Wales starts here) 24.08 59.50
2015-04-01 (unchanged in 2016-17) 24.43 60.06
2017-04-01 24.78 60.90
2018-04-01 25.48 62.86
2019-04-01 26.04 64.19
2020-04-01 26.60 65.52
2021-04-01 26.67 65.94
2022-04-01 27.44 68.04
2023-04-01 30.17 74.69
2024-04-01 32.20 80.01
2025-04-01 32.75 81.37
2026-04-01 33.99 84.46

From 2015-16, gov.dwp.housing_benefit.premiums.disabled_child and .enhanced_disabled_child hold the same amounts, but the CTR formula reads its own parameters, so a Housing Benefit reform leaves CTR alone. The files sit under gov.local_authorities.<nation>.council_tax_reduction.pensioners.applicable_amount, as disabled_child_premium.yaml and enhanced_disability_premium.yaml, and uprate with gov.benefit_uprating_cpi after 2026-27, as child_or_young_person.yaml does.

AFIP routes

Boolean parameters under applicable_amount.armed_forces_independence_payment.<premium>.{child,young_person} hold these routes, so the formula holds no dates:

Nation Enhanced disability premium Disabled child premium
England any child or young person, for schemes from 1 April 2023 (para 7(1)(c); SI 2023/16 regs 1(3) and 7(7)(c)); none before a young person, for schemes from 1 April 2023 (para 8(e); SI 2023/16 regs 1(3) and 7(8)); none before
Wales any child or young person, in every model year (para 7(1)(c)) any child or young person, for schemes from 1 April 2024 (para 8(d); WSI 2024/56 regs 1(3) and 5(d)); none before
Scotland a young person, in every model year (Sch 1 para 8(1)(aa), from 11 June 2013) a young person, in every model year (Sch 1 para 9(ba), from 11 June 2013)

housing_benefit_child_disability_premiums keeps its own route: AFIP for any child or young person in both premiums.

Who reads council_tax_reduction_premiums

  • council_tax_reduction_applicable_amount: rises for a pensioner family with a qualifying child or young person; otherwise unchanged. Through it, the excess of council_tax_reduction_applicable_income over the applicable amount can fall, and council_tax_reduction and council_tax_benefit can rise, for such a family.
  • enhanced_disability_premium.yaml, applicant_or_partner.yaml (CTR directory) and housing_benefit_pre_cutoff_period.yaml: unchanged; none has a pensioner family with a qualifying child.
  • test_housing_benefit_pension_age_cohorts.py sets the variable as an input; unchanged.
  • test_council_tax_reduction_applicant_properties.py reads it among its outputs; unchanged; its test passes.

The comments at benefits_premiums.py and council_tax_reduction_applicable_amount.py, and the documentation of council_tax_reduction_premiums and council_tax_reduction_applicable_amount, now say that a pensioner's CTR premiums include the two child premiums. No page under docs/ describes the pension-age CTR premiums, so no page changes.

Out of scope

Invariants

  1. The new variable returns nil for every working-age family and wherever the household head applies alone.
  2. A pensioner family's total equals the sum, over its children and young persons, of 52 times each premium whose condition the child meets.
  3. On the model's inputs, a child or young person who meets the shared enhanced condition always meets the shared disabled child condition. Through AFIP alone, a child under 16 in England from 2023-24, and any child or young person in Wales before 2024-25, meets only the enhanced condition, as paras 7 and 8 provide.
  4. The applicable amount and the premiums never fall when a child or young person gains a qualifying benefit.
  5. For pension-age families with no AFIP, in every year from 2015 to 2026, the new variable equals housing_benefit_child_disability_premiums.
  6. Housing Benefit's results do not change.

Tests

We ran the tests below at 6e96ffef8, before commits 11 and 12.

  • council_tax_reduction_pensioner_child_disability_premiums.yaml (new, 31 cases): the issue's cases A0 to A4 in each nation in 2026, on council_tax_reduction_applicable_amount and the new variable; A2c in each nation on council_tax_reduction; AFIP alone in England (a young person in 2022 and 2023, a child in 2023), Wales (a child in 2023 and 2024) and Scotland (a child and a young person in 2026); a working-age family and a head who applies alone, each with a qualifying child; a pensioner in Northern Ireland with a child on the highest DLA care rate; and 2015 in each nation. Each comment shows the sum from the amounts table.
  • test_council_tax_reduction_pensioner_child_disability_premium_properties.py (new, 6 Hypothesis properties, invariants 1 to 5) builds many families in one simulation per example. Explicit examples check, on every run, children aged 3, 4 and 5 on the lower DLA mobility rate alone, since dla_m pays that rate only from age 5. They also check each AFIP route for a child and a young person in England (2022, 2023), Wales (2023, 2024) and Scotland (2026).
  • Without this PR's commits, all 31 YAML cases fail, because the variable doesn't exist, and the property module fails to import, because the helper doesn't exist. With only the helper copied in, 5 of the 6 properties fail; the one that reads only the helper passes. On the head with the formula returning nil, 20 cases fail; with the AFIP routes removed, 5 fail; with the child and young person routes swapped, 4 fail. With Northern Ireland given England's amounts and routes, the Northern Ireland case fails.
  • Before this PR, the base merge gives the issue's model column in every case: for example 17,881.76 for England A2 and £1,233.55, £1,443.84 and £1,454.11 for A2c. After it, the model gives the issue's statutory column (24,041.16, 25,092.60 and 25,183.60 for A2) and the full £2,000 for A2c in each nation.
  • Housing Benefit: housing_benefit_child_disability_premiums.yaml passes (62 cases). On 300 drawn benefit units in each year from 2015 to 2030 (4,800 values, 2,224 of them positive, across all four nations, with AFIP, DLA, PIP and blindness), housing_benefit_child_disability_premiums gives identical results before and after.
  • The CTR YAML directory (416 cases) and housing_benefit_pre_cutoff_period.yaml (4 cases) pass.
  • test_council_tax_reduction_pensioner_children_tariff_properties.py, test_council_tax_reduction_child_benefit_properties.py, test_enhanced_disability_premium_properties.py, test_council_tax_reduction_applicant_properties.py and test_housing_benefit_pension_age_cohorts.py pass (96 tests), and policyengine_uk/tests/code_health passes (3,140 tests).

Merge notes

Survey data

The Aggregate impact job compares main with this PR merged into it, so it includes #2826 and #2808. This PR's report, from the run at 6e96ffef8, compares main at 9b456bda65 with this PR merged into it (9b7d5da44e). #2826's report compares main at 46a60678ff with #2826 at 06e51a8a merged into it (2d90bcc1c8). Apart from the run details, the two reports print the same figures, including the Council Tax Reduction rows (spending from −£0.1m in 2025-26 to −£0.2m in 2031-32, caseload from +254 to −104). They compare different pairs of commits, so the match doesn't isolate what this PR's own commits change on the certified data.


🤖 Generated with Claude Code

MaxGhenis and others added 30 commits October 31, 2026 20:24
…limit

The legacy enhanced disability premium read is_enhanced_disabled_for_benefits,
whose formula tested only the highest-rate DLA care component. The
Regulations (HB Regs 2006 Sch 3 para 15, IS Regs 1987 Sch 2 para 13A, ESA
Regs 2008 Sch 4 para 7, JSA Regs 1996 Sch 1 para 15A and the Northern
Ireland equivalents) also name the enhanced PIP daily living component and
armed forces independence payment, and they limit the premium to people who
have not attained the qualifying age for State Pension Credit.

- receives_enhanced_disability_premium_qualifying_benefit reads a GB and a
  Northern Ireland list of qualifying benefits, with each country's dates.
- The claimant-or-partner count applies the age limit.
- Council Tax Reduction applies its scheme's own condition: Scotland's
  working-age scheme adds attendance allowance from April 2023 and has had
  no age limit since 20 June 2022.
- is_enhanced_disabled_for_benefits becomes a deprecated alias.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
YAML cases worked by hand from HB Regs 2006 Sch 3 para 15 and Part 4, IS
Regs 1987 Sch 2 para 13A, the Northern Ireland lists and the Welsh and
Scottish Council Tax Reduction schemes. Read the Scottish age-limit switch
as a scalar with `not`, since `~` on a Python bool is bitwise inversion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pension-age Council Tax Reduction applicable amount now adds an amount
for each child or young person in the family (England SI 2012/2885 Sch 1
para 6(1)(b) and Sch 2 para 2, with the 2018-19 to 2024-25 two-child limit
and its Child Tax Credit exception; Wales WSI 2013/3029 Sch 2 para 2;
Scotland SSI 2012/319 reg 20(b) and Sch 1 para 3) and the family premium
where the scheme still has one (Wales; England and Scotland to April 2016).
General-rule income now counts tariff income from capital over 10,000 (SI
2012/2885 Sch 1 para 37; WSI 2013/3029 Sch 1 para 31; SSI 2012/319 reg
27(2)), reusing the pension-age Housing Benefit tariff parameters.

Four existing YAML expectations move with the law: the 16,000 capital case
gains 624 a year of tariff income, and three pensioner cases with a child
or young person gain the child amount.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An oracle computed from the award inputs checks the legacy and Council Tax
Reduction premiums for single people, couples and lone parents in every
nation across 2016-2026, with monotonicity, rate bounds, the CTR-versus-
legacy differential and the Housing Benefit child premiums' own copy of the
paragraph 15 list. The CTR applicant differential now also draws enhanced
PIP daily living for the household head, since the deprecated flag it drew
no longer reaches the premium. Add the changelog fragment and cite the
Income Support and ESA claimant age conditions.

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

The new property tests check that tariff income is the statutory tariff and
never falls as capital rises, that adding a dependent child never lowers the
applicable amount, and that pensioners with no child and capital up to
10,000 and every working-age family get none of the new amounts. A frozen
differential checks those households against values computed on origin/main
at 2da212a.

Two existing property tests move with the law: the Child Benefit test's
State Pension range rises so its award stays interior above an applicable
amount that now includes the children, and the Pension Credit test's
recomputed general-rules income adds the statutory tariff income.

Wales's 2013-14 child amount is 65.62, set by WSI 2013/112 reg 5(b).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
legislation.gov.uk serves SI 2012/2885 Schedule 2 paragraphs 2 and 3 under
Parts 1 and 2.

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

A lone-applying household head aged 60 in Edinburgh with attendance
allowance now meets Scotland's working-age enhanced disability premium
condition, which SSI 2023/38 extended to attendance allowance from 1 April
2023 (SSI 2021/249 Sch 1 para 14(1)(g)). Each case's premiums and
applicable amount rise by the single rate, 22.00 * 52 = 1,144.00.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The applicant in these three Scottish cases receives the enhanced PIP daily
living component, which meets the enhanced disability premium condition
for Housing Benefit (HB Regs 2006 Sch 3 para 15(1)(c)), Income Support (IS
Regs 1987 Sch 2 para 13A(1ZA)(c)) and Scotland's working-age Council Tax
Reduction (SSI 2021/249 Sch 1 para 14(1)(f)). Each premium total and
applicable amount rises by 22.00 * 52 = 1,144.00, and each reduction by
20% of that, 228.80.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…heme's own list

An award of the highest DLA care rate or the enhanced PIP daily living rate
now needs a positive amount, and takes its rate from the award category or,
for an amount entered without its category, from an amount within £1 a week
of the top rate. A zero or neutralised amount is no award. The Housing
Benefit child premium reads the same awards.

Merton and Kingston upon Thames count PIP daily living at either rate and no
armed forces independence payment; Newham counts both (Sch 3 para 12 of each
council's 2026-27 scheme). Westminster keeps the Housing Benefit condition.

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

Adds YAML for amounts entered without a category, the £1 tolerance,
explicit zero amounts and part amounts, the child premium, a Merton
applicant whose AFIP adds no premium and each London council's list, and
replaces the property test's outside-Scotland equality with scheme-specific
expectations.

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

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

SI 2012/2885 Sch 1 para 6(1B)(a) asks whether the applicant has an award of
Child Tax Credit "whether or not any amount is payable". The child amounts
read an award only from would_claim_CTC and is_CTC_eligible, so an entered
final child_tax_credit with three individual elements gave two child
amounts. A positive final child_tax_credit now counts as an award too, and
the claim-and-eligibility route stays for a nil-rate award.

New YAML cases: the entered award (three amounts), a claim without
eligibility (two), and a nil-rate award (three). Case 16's name uses
"their".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SI 2012/2885 Sch 1 para 37 and WSI 2013/3029 Sch 1 para 31 count capital in
excess of £10,000 "but not exceeding £16,000". SSI 2012/319 reg 27(2) has
no such ceiling; reg 40 separately ends entitlement above £16,000. The
tariff now caps capital only in England and Wales, so a Scottish pensioner
with £20,000 has 20 * 52 = £1,040 of tariff income, not £624, and still no
reduction.

New YAML cases for Scotland and Wales at £20,000. The Pension Credit and
children/tariff property tests' reference calculations cap only England and
Wales.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The general-rules income floors cash income after tax, pension
contributions and the earnings disregards, then adds tariff income as a
separate source. A pensioner with no cash income, £3,000 of pension
contributions and £10,001 of capital has applicable income of £52. Moving
the tariff inside the floor would give nil.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Capital changes a savings-credit-only pensioner's applicable income through
the Secretary of State's assessment, and a child who brings Universal
Credit into payment for a mixed-age couple moves them to the working-age
scheme. The property docstring now states each invariant for the route
its generated families stay on, and names those route changes as model
behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The applicable amount comment now says we include the severe disability
and carer premiums for pensioners, rather than that the pension-age
schedules have only those (England's Sch 2 paras 7 and 8 have more). The
applicable income comment uses "them", and the new documentation names the
Ministers, councils or "we" that act.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A situation that supplies an amount for one person supplies zero for
everyone else, so the oracle's per-person category rate did not hold once
any person in the example entered an amount.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tariff documentation and comments now say who acts (councils, the
Scottish Ministers) rather than giving the verb to a regulation, and the
"Nil for working-age families" fragments become sentences. No code
changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Give the qualifying verbs to claimants, councils and the Scottish
Ministers in the parameter descriptions, docstrings, changelog and test
comments, state the stored flag's exact DLA boundary, and qualify
Kingston upon Thames's printed amounts with its adopted uprating
mechanism. No executable code or parameter value changes: ASTs without
docstrings and parameter YAML without descriptions and references match
7c42ca7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
State that the council delegated annual uprating in December 2013, kept
its 2015-17 scheme apart from Annex 3's uprating in July 2014, and that
its 2026-27 introductions name the Prescribed Requirement Scheme.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The child-limit exception in council_tax_reduction_pensioner_child_amounts
now reads the claim and eligibility only while gov.dwp.tax_credits.active
holds, as has_tax_credit_award does. A supplied positive final award still
counts. Case 21 covers eligibility without a claim, and Case 22 an
inactive-scheme reform with a reported award.

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

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Aggregate impact on certified data: pass

Base 5c7744144a against head 12d0340bc1, both on enhanced_frs_2024_25.h5 (policyengine-uk-data 1.58.1, sha256 056e80fd8e91), fiscal years 2025-26 to 2031-32. Each year is a full microsimulation run on each side.

Checks: 0 broken by this change, 1 failing on both sides, 0 fixed. Moves flagged for review: 0 (thresholds in report_spec.yaml; a flag does not fail the job).

Workflow run and full report

Notes

  • In the years a figure from fewer than 10 records is suppressed (spending.disabled_students_allowance), every total containing it, and the decile incomes, are rebuilt from their other components, so no published total includes it. Those totals are marked †. A change is withheld where the two sides leave out different figures and can't be lined up.

Moves flagged for review

None.

Spending by benefit and service

Measure 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Council Tax Reduction +£0.2m +£0.3m +£0.3m +£0.2m +£0.3m +£0.3m +£0.3m
Disabled Students' Allowance suppressed suppressed suppressed suppressed suppressed suppressed suppressed

Caseloads

Measure 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Council Tax Reduction +254 +255 +255 0 0 0 0
Disabled Students' Allowance suppressed suppressed suppressed suppressed suppressed suppressed suppressed

Government balance, each component counted once

Measure 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Government spending +£0.2m † +£0.3m † +£0.3m † +£0.2m † +£0.3m † +£0.3m † +£0.3m †
Government balance, each receipt once -£0.2m † -£0.3m † -£0.3m † -£0.2m † -£0.3m † -£0.3m † -£0.3m †

Model totals

Measure 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
gov_spending +£0.2m † +£0.3m † +£0.3m † +£0.2m † +£0.3m † +£0.3m † +£0.3m †
household_benefits +£0.2m † +£0.3m † +£0.3m † +£0.2m † +£0.3m † +£0.3m † +£0.3m †
gov_balance -£0.2m † -£0.3m † -£0.3m † -£0.2m † -£0.3m † -£0.3m † -£0.3m †

Household income totals

Measure 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Household net income +£0.2m † +£0.3m † +£0.3m † +£0.2m † +£0.3m † +£0.3m † +£0.3m †
Household net income (HBAI definition) +£0.2m +£0.3m +£0.3m +£0.2m +£0.3m +£0.3m +£0.3m

Inequality

Measure 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Gini coefficient, equivalised HBAI income before housing costs -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000 -0.0000

Mean household net income in each side's own deciles

Measure 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Decile 1: mean household_net_income per household -£0.30 † -£0.32 † -£0.36 † 0 † 0 † 0 † 0 †
Decile 2: mean household_net_income per household -£0.43 † -£0.45 † -£0.38 † +£0.08 † +£0.08 † +£0.08 † +£0.08 †

Standard reform costings (change in gov_balance)

Measure 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Raise basic rate by 1pp -£991 -£976 +£997 0 +£0 +£0 -£1
Raise higher rate by 1pp +£0 +£0 0 0 0 0 +£0
Raise personal allowance by ~800GBP/year -£1,144 -£1,146 -£1,148 +£0 0 +£0 -£1
Raise child benefit by 25GBP/week per additional child +£0 +£0 -£1 0 +£0 +£0 -£0
Reduce Universal Credit taper rate to 20% +£0 +£0 -£0 0 0 0 -£0
Raise Class 1 main employee NICs rate to 10% +£0 0 +£0 0 -£0 0 -£0
Raise VAT standard rate by 2pp +£0 +£0 +£0 0 +£0 +£0 0
Raise additional rate by 3pp 0 +£0 -£0 0 0 +£0 0
Raise the Universal Credit standard allowance by 10% +£0 0 -£0 0 0 +£0 -£0
Raise the State Pension by 10% -£16,194 -£17,004 -£17,690 +£46,477 +£40,639 +£33,250 +£24,393

Household net income by decile

Mean change in household net income per household, and as a share of the decile's base income; households stay in the base run's deciles.

Base decile 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Decile 1 fewer than 10 households change fewer than 10 households change fewer than 10 households change 0 0 0 0
Decile 2 0 0 0 fewer than 10 households change fewer than 10 households change fewer than 10 households change fewer than 10 households change
Decile 3 0 0 0 0 0 0 0
Decile 4 0 0 0 0 0 0 0
Decile 5 0 0 0 0 0 0 0
Decile 6 0 0 0 0 0 0 0
Decile 7 0 0 0 0 0 0 0
Decile 8 0 0 0 0 0 0 0
Decile 9 0 0 0 0 0 0 0
Decile 10 0 0 0 0 0 0 0
all fewer than 10 households change fewer than 10 households change fewer than 10 households change fewer than 10 households change fewer than 10 households change fewer than 10 households change fewer than 10 households change
Year People gaining over £1 People losing over £1
2025-26 fewer than 10 households change fewer than 10 households change
2026-27 fewer than 10 households change fewer than 10 households change
2027-28 fewer than 10 households change fewer than 10 households change
2028-29 fewer than 10 households change fewer than 10 households change
2029-30 fewer than 10 households change fewer than 10 households change
2030-31 fewer than 10 households change fewer than 10 households change
2031-32 fewer than 10 households change fewer than 10 households change

No change in any year: receipts by tax head; population; poverty rates; people in poverty; standard reforms: change in each reform's target.

Checks failing on both base and head (1)
  • VAT excluding private school fees is never negative (sign:vat): 2025-26: 76 units below zero, a weighted £-53,888,684 in total; 2026-27: 76 units below zero, a weighted £-55,777,260 in total; 2027-28: 76 units below zero, a weighted £-57,727,917 in total
Counted-once check

Each of 92 components was raised by £1 per unit in 2026-27, and every head of its totals was read household by household: its own head must rise by exactly £1, no other tax head may move, no other benefit may rise, and the model's own total must move by what its heads moved. A head that breaks a rule is measured again twice: with every other head held at its baseline value, and with every other head held at its value after the first £1 while the component rises again. It fails where either still shows the response. 0 failed; 0 were skipped.

  • widowed_parents_allowance: pension_credit responds only through other heads in fewer than 10 households (other heads that moved there: carers_allowance; gov_spending; not a failure)
  • widowed_parents_allowance: pension_credit responds only through other heads in fewer than 10 households (other heads that moved there: carers_allowance; household_benefits; not a failure)
Provenance
Side Commit Runtime Environment hash Partition hash Time
base main 5c7744144a uk 2.174.7 (files f97351c7e59f), core 3.34.1, py 3.13.18 aarch64 5cc6f6ff0466 3bcfb3473960 2501.61s
head #2861 merged into main 12d0340bc1 uk 2.174.7 (files 962f9ad81433), core 3.34.1, py 3.13.18 aarch64 5cc6f6ff0466 3bcfb3473960 2392.36s

Dataset: hf://policyengine/policyengine-uk-data-private/enhanced_frs_2024_25.h5@2526edbbb687a3b54dbb11272e5389e4b62d2ac2, sha256 056e80fd8e9151d78f432a25cde863340baee81304c6216a37fb575ce8563784 (verified on both sides), policyengine-uk-data 1.58.1.

Receipts by tax head: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Final charge on cash interest in non-cash ISAs £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Lifetime ISA withdrawal charge £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Income tax £294.46bn £315.23bn £335.82bn £351.28bn £366.96bn £385.36bn £399.99bn
National Insurance (employee and self-employed) £51.70bn £54.14bn £56.13bn £57.73bn £59.76bn £61.64bn £63.51bn
National Insurance (employer) £148.71bn £155.37bn £160.88bn £165.09bn £172.06bn £177.36bn £182.57bn
Employer NI change borne by capital £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Employer NI change borne by consumers £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Capital gains tax £12.60bn £13.15bn £13.60bn £14.11bn £14.67bn £15.24bn £15.80bn
Student loan repayments £7.82bn £8.13bn £8.39bn £8.58bn £8.79bn £9.04bn £9.29bn
VAT excluding private school fees £249.37bn £256.87bn £266.33bn £272.70bn £278.97bn £285.24bn £291.59bn
Change in VAT from its baseline £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
VAT on private school fees £1.95bn £2.01bn £2.09bn £2.14bn £2.20bn £2.26bn £2.31bn
Change in private school VAT from its baseline £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Fuel duties £24.71bn £24.13bn £26.00bn £26.83bn £26.51bn £25.78bn £24.63bn
Alcohol duties £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Tobacco duties £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Vehicle excise duties £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Betting and gaming duties £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
TV licence fee £4.26bn £4.40bn £4.41bn £4.42bn £4.43bn £4.44bn £4.45bn
Council tax £49.21bn £52.16bn £54.89bn £57.95bn £61.16bn £64.47bn £67.91bn
High value council tax surcharge £0.00bn £0.00bn £0.00bn £0.48bn £0.49bn £0.50bn £0.51bn
Northern Ireland domestic rates £0.55bn £0.58bn £0.60bn £0.63bn £0.66bn £0.69bn £0.72bn
Business rates £34.68bn £36.20bn £38.00bn £39.46bn £42.27bn £43.25bn £44.29bn
Stamp duty land tax on the household's own purchases £6.88bn £7.32bn £7.66bn £8.06bn £8.47bn £8.91bn £9.35bn
Stamp duty land tax paid by companies £4.72bn £4.57bn £5.29bn £6.03bn £6.37bn £6.92bn £7.45bn
Land transaction tax (Wales) £0.07bn £0.08bn £0.08bn £0.09bn £0.10bn £0.10bn £0.11bn
Land and buildings transaction tax (Scotland) £0.31bn £0.32bn £0.33bn £0.35bn £0.36bn £0.38bn £0.40bn
Unspecified tax change borne by capital £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Unspecified tax change borne by consumers £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Wealth tax £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Wealth tax excluding the main residence £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Land value tax £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Carbon tax £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Spending by benefit and service: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Lifetime ISA bonus £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
State Pension £121.68bn £125.92bn £126.72bn £129.48bn £132.98bn £136.65bn £140.41bn
Pension Credit £6.21bn £6.46bn £6.68bn £6.82bn £6.89bn £7.07bn £7.22bn
Winter Fuel Payment £1.86bn £1.85bn £1.79bn £1.77bn £1.78bn £1.78bn £1.78bn
Pension Age Winter Heating Payment (Scotland) £0.19bn £0.20bn £0.20bn £0.21bn £0.21bn £0.22bn £0.22bn
Universal Credit £75.48bn £80.52bn £82.95bn £84.96bn £86.11bn £87.61bn £88.21bn
Housing Benefit £8.56bn £8.89bn £9.23bn £9.46bn £9.69bn £9.99bn £10.27bn
Council Tax Reduction £2.07bn £2.20bn £2.32bn £2.45bn £2.59bn £2.73bn £2.87bn
Employment and Support Allowance (income-related) £0.79bn £0.82bn £0.84bn £0.86bn £0.88bn £0.90bn £0.92bn
Employment and Support Allowance (contribution-based) £5.20bn £5.37bn £5.56bn £5.69bn £5.82bn £5.95bn £6.09bn
Jobseeker's Allowance (income-based) £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Jobseeker's Allowance (contribution-based) £0.29bn £0.30bn £0.31bn £0.31bn £0.32bn £0.33bn £0.34bn
Income Support £0.11bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Working Tax Credit £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Child Tax Credit £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Incapacity Benefit £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Personal Independence Payment £26.95bn £28.03bn £29.05bn £30.09bn £30.75bn £31.51bn £32.21bn
Disability Living Allowance £7.49bn £7.79bn £8.07bn £8.36bn £8.55bn £8.76bn £8.95bn
Attendance Allowance £8.68bn £9.03bn £9.36bn £9.69bn £9.90bn £10.15bn £10.38bn
Carer's Allowance £4.48bn £4.66bn £4.83bn £5.00bn £5.11bn £5.27bn £5.42bn
Carer Support Payment (Scotland) £0.31bn £0.32bn £0.33bn £0.34bn £0.35bn £0.36bn £0.37bn
Carer's Allowance Supplement (Scotland) £0.00bn £0.04bn £0.04bn £0.05bn £0.05bn £0.05bn £0.05bn
Severe Disablement Allowance £0.03bn £0.03bn £0.03bn £0.03bn £0.03bn £0.03bn £0.03bn
Industrial Injuries Disablement Benefit £0.50bn £0.52bn £0.54bn £0.55bn £0.56bn £0.58bn £0.59bn
Armed Forces Compensation Scheme £0.61bn £0.63bn £0.65bn £0.66bn £0.68bn £0.69bn £0.71bn
War Widow's or Widower's Pension £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Child Benefit £16.19bn £16.82bn £17.39bn £18.00bn £18.39bn £18.84bn £19.25bn
Scottish Child Payment £0.49bn £0.52bn £0.53bn £0.55bn £0.56bn £0.57bn £0.56bn
Two Child Limit Payment (Scotland, counterfactual) £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Healthy Start vouchers £0.05bn £0.05bn £0.05bn £0.05bn £0.05bn £0.05bn £0.05bn
Maternity Allowance £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Statutory Maternity Pay £3.30bn £3.41bn £3.54bn £3.62bn £3.70bn £3.78bn £3.87bn
Statutory Paternity Pay £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Statutory Sick Pay £1.12bn £1.16bn £1.20bn £1.23bn £1.26bn £1.29bn £1.32bn
Sure Start Maternity Grant £0.01bn £0.01bn £0.01bn £0.01bn £0.01bn £0.01bn £0.01bn
Bereavement Support Payment £0.67bn £0.69bn £0.71bn £0.73bn £0.75bn £0.76bn £0.78bn
Widowed Parent's Allowance £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Tax-Free Childcare £0.56bn £0.57bn £0.57bn £0.58bn £0.60bn £0.61bn £0.59bn
Extended childcare entitlement £2.99bn £3.50bn £3.59bn £3.71bn £3.78bn £3.86bn £3.93bn
Universal childcare entitlement £2.06bn £2.22bn £2.29bn £2.37bn £2.43bn £2.48bn £2.53bn
Targeted childcare entitlement £0.50bn £0.51bn £0.52bn £0.54bn £0.55bn £0.57bn £0.56bn
Childcare Offer for Wales £0.26bn £0.28bn £0.28bn £0.29bn £0.30bn £0.31bn £0.32bn
Care to Learn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Childcare Grant £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Parents' Learning Allowance £0.20bn £0.20bn £0.20bn £0.20bn £0.20bn £0.20bn £0.20bn
Adult Dependants' Grant £0.06bn £0.06bn £0.04bn £0.04bn £0.04bn £0.04bn £0.04bn
Travel Grant £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Disabled Students' Allowance suppressed suppressed suppressed suppressed suppressed suppressed suppressed
16 to 19 Bursary Fund £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
NHS spending £203.89bn £204.30bn £204.56bn £204.91bn £205.34bn £205.85bn £206.35bn
State education spending £0.02bn £0.02bn £0.02bn £0.02bn £0.02bn £0.02bn £0.02bn
Transport subsidy spending £25.05bn £25.10bn £25.14bn £25.18bn £25.23bn £25.30bn £25.36bn
Cost-of-living support payment £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Energy Bills Rebate £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Household Energy Payment £0.00bn £2.11bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Energy Price Guarantee subsidy £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Basic income £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Disability basic income £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Other public spending budget change £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Caseloads: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Lifetime ISA bonus 0k 0k 0k 0k 0k 0k 0k
State Pension 11,264k 11,145k 10,819k 10,700k 10,723k 10,750k 10,776k
Pension Credit 1,489k 1,484k 1,476k 1,454k 1,452k 1,457k 1,466k
Winter Fuel Payment 7,844k 7,783k 7,473k 7,375k 7,391k 7,409k 7,427k
Pension Age Winter Heating Payment (Scotland) 803k 802k 800k 797k 799k 801k 802k
Universal Credit 6,342k 6,347k 6,336k 6,297k 6,292k 6,271k 6,223k
Housing Benefit 1,249k 1,245k 1,244k 1,227k 1,227k 1,229k 1,232k
Council Tax Reduction 3,180k 3,200k 3,206k 3,219k 3,234k 3,245k 3,252k
Employment and Support Allowance (income-related) 71k 71k 71k 71k 71k 71k 71k
Employment and Support Allowance (contribution-based) 719k 720k 721k 722k 724k 726k 728k
Jobseeker's Allowance (income-based) 0k 0k 0k 0k 0k 0k 0k
Jobseeker's Allowance (contribution-based) 67k 67k 67k 67k 67k 68k 68k
Income Support 25k 0k 0k 0k 0k 0k 0k
Working Tax Credit 0k 0k 0k 0k 0k 0k 0k
Child Tax Credit 0k 0k 0k 0k 0k 0k 0k
Incapacity Benefit 0k 0k 0k 0k 0k 0k 0k
Personal Independence Payment 3,567k 3,575k 3,579k 3,585k 3,593k 3,602k 3,611k
Disability Living Allowance 1,291k 1,294k 1,296k 1,298k 1,300k 1,304k 1,307k
Attendance Allowance 1,695k 1,698k 1,700k 1,703k 1,707k 1,711k 1,715k
Carer's Allowance 1,034k 1,037k 1,038k 1,040k 1,042k 1,060k 1,062k
Carer Support Payment (Scotland) 71k 71k 71k 72k 72k 72k 72k
Carer's Allowance Supplement (Scotland) 0k 71k 71k 72k 72k 72k 72k
Severe Disablement Allowance 4k 4k 4k 4k 4k 4k 4k
Industrial Injuries Disablement Benefit 137k 137k 137k 138k 138k 138k 139k
Armed Forces Compensation Scheme 93k 93k 94k 94k 94k 94k 94k
War Widow's or Widower's Pension 0k 0k 0k 0k 0k 0k 0k
Child Benefit 8,123k 8,120k 8,120k 8,130k 8,145k 8,161k 8,178k
Scottish Child Payment 351k 352k 352k 353k 350k 348k 337k
Two Child Limit Payment (Scotland, counterfactual) 0k 0k 0k 0k 0k 0k 0k
Healthy Start vouchers 200k 200k 200k 201k 201k 201k 202k
Maternity Allowance 0k 0k 0k 0k 0k 0k 0k
Statutory Maternity Pay 333k 333k 334k 334k 335k 336k 337k
Statutory Paternity Pay 0k 0k 0k 0k 0k 0k 0k
Statutory Sick Pay 181k 182k 182k 182k 182k 183k 183k
Sure Start Maternity Grant 26k 26k 26k 26k 26k 26k 26k
Bereavement Support Payment 98k 98k 98k 98k 98k 99k 99k
Widowed Parent's Allowance 0k 0k 0k 0k 0k 0k 0k
Tax-Free Childcare 1,043k 1,027k 1,014k 1,009k 1,011k 1,009k 993k
Extended childcare entitlement 795k 800k 796k 797k 798k 798k 792k
Universal childcare entitlement 1,071k 1,072k 1,072k 1,073k 1,076k 1,079k 1,074k
Targeted childcare entitlement 165k 156k 154k 154k 155k 155k 150k
Childcare Offer for Wales 39k 39k 39k 39k 39k 39k 39k
Care to Learn 0k 0k 0k 0k 0k 0k 0k
Childcare Grant 0k 0k 0k 0k 0k 0k 0k
Parents' Learning Allowance 98k 98k 98k 99k 99k 99k 99k
Adult Dependants' Grant 18k 18k 12k 12k 12k 12k 12k
Travel Grant 0k 0k 0k 0k 0k 0k 0k
Disabled Students' Allowance suppressed suppressed suppressed suppressed suppressed suppressed suppressed
16 to 19 Bursary Fund 0k 0k 0k 0k 0k 0k 0k
Cost-of-living support payment 0k 0k 0k 0k 0k 0k 0k
Energy Bills Rebate 0k 0k 0k 0k 0k 0k 0k
Household Energy Payment 0k 21,065k 0k 0k 0k 0k 0k
Energy Price Guarantee subsidy 0k 0k 0k 0k 0k 0k 0k
Basic income 0k 0k 0k 0k 0k 0k 0k
Disability basic income 0k 0k 0k 0k 0k 0k 0k
Government balance, each component counted once: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Government receipts, each component once £892.00bn £934.66bn £980.50bn £1,015.93bn £1,054.24bn £1,091.56bn £1,124.89bn
Government spending £528.93bn † £545.10bn † £550.16bn † £558.85bn † £566.49bn † £575.19bn † £582.78bn †
Government balance, each receipt once £363.07bn † £389.57bn † £430.34bn † £457.08bn † £487.75bn † £516.37bn † £542.11bn †
Benefits in household_benefits but not in gov_spending £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn £0.00bn
Model totals: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
gov_tax £892.00bn £934.66bn £980.50bn £1,015.93bn £1,054.24bn £1,091.56bn £1,124.89bn
household_tax £491.97bn £520.41bn £551.21bn £576.00bn £601.00bn £626.69bn £648.42bn
pre_budget_change_household_tax £484.15bn £512.28bn £542.82bn £566.95bn £591.72bn £617.16bn £638.61bn
gov_spending £528.93bn † £545.10bn † £550.16bn † £558.85bn † £566.49bn † £575.19bn † £582.78bn †
household_benefits £528.93bn † £545.10bn † £550.16bn † £558.85bn † £566.49bn † £575.19bn † £582.78bn †
gov_balance £363.07bn † £389.57bn † £430.34bn † £457.08bn † £487.75bn † £516.37bn † £542.11bn †
Household income totals: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Household market income £1,637.96bn £1,702.77bn £1,757.35bn £1,806.41bn £1,855.97bn £1,912.43bn £1,970.44bn
Household net income £1,636.24bn † £1,687.25bn † £1,714.85bn † £1,746.83bn † £1,777.98bn † £1,816.26bn † £1,858.87bn †
Household net income (HBAI definition) £1,449.13bn £1,499.27bn £1,530.25bn £1,564.51bn £1,597.18bn £1,634.83bn £1,675.80bn
Population: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
People 69,245k 69,383k 69,473k 69,592k 69,738k 69,912k 70,080k
Benefit units 35,110k 35,181k 35,226k 35,286k 35,360k 35,449k 35,534k
Households 31,046k 31,108k 31,149k 31,201k 31,267k 31,345k 31,420k
Poverty rates: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Absolute poverty, before housing costs: everyone 16.3% 15.5% 16.4% 16.3% 16.5% 16.5% 16.6%
Absolute poverty, before housing costs: children 24.7% 22.1% 23.3% 22.9% 23.1% 23.2% 23.5%
Absolute poverty, before housing costs: working-age adults 14.1% 13.8% 14.7% 14.7% 14.8% 14.8% 15.0%
Absolute poverty, before housing costs: pensioners 13.7% 13.4% 14.0% 13.8% 13.9% 14.0% 13.9%
Absolute poverty, after housing costs: everyone 21.6% 21.0% 22.0% 22.6% 22.9% 23.1% 23.4%
Absolute poverty, after housing costs: children 33.3% 31.3% 32.3% 32.5% 32.9% 33.4% 34.2%
Absolute poverty, after housing costs: working-age adults 19.9% 19.8% 20.8% 21.6% 21.9% 22.0% 22.3%
Absolute poverty, after housing costs: pensioners 12.7% 12.4% 13.1% 13.2% 13.3% 13.4% 13.6%
Relative poverty, before housing costs: everyone 17.0% 16.0% 16.4% 16.3% 16.4% 16.3% 16.6%
Relative poverty, before housing costs: children 25.9% 22.9% 23.3% 22.9% 23.0% 22.9% 23.5%
Relative poverty, before housing costs: working-age adults 14.5% 14.1% 14.6% 14.7% 14.7% 14.7% 15.0%
Relative poverty, before housing costs: pensioners 14.5% 14.0% 13.9% 13.8% 13.8% 13.9% 13.9%
Relative poverty, after housing costs: everyone 21.5% 21.0% 21.3% 21.3% 21.3% 21.5% 21.7%
Relative poverty, after housing costs: children 33.1% 31.1% 31.2% 31.0% 31.1% 31.2% 31.8%
Relative poverty, after housing costs: working-age adults 19.9% 19.8% 20.2% 20.4% 20.5% 20.6% 20.8%
Relative poverty, after housing costs: pensioners 12.5% 12.4% 12.2% 11.7% 11.7% 11.8% 12.0%
People in poverty: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Absolute poverty, before housing costs: everyone 11,277k 10,778k 11,402k 11,365k 11,475k 11,514k 11,650k
Absolute poverty, before housing costs: children 3,688k 3,314k 3,496k 3,445k 3,480k 3,502k 3,549k
Absolute poverty, before housing costs: working-age adults 5,965k 5,893k 6,308k 6,362k 6,420k 6,430k 6,521k
Absolute poverty, before housing costs: pensioners 1,624k 1,571k 1,597k 1,558k 1,575k 1,581k 1,580k
Absolute poverty, after housing costs: everyone 14,944k 14,599k 15,310k 15,721k 15,937k 16,140k 16,426k
Absolute poverty, after housing costs: children 4,975k 4,682k 4,837k 4,888k 4,945k 5,040k 5,179k
Absolute poverty, after housing costs: working-age adults 8,463k 8,461k 8,971k 9,344k 9,491k 9,584k 9,706k
Absolute poverty, after housing costs: pensioners 1,506k 1,456k 1,501k 1,489k 1,501k 1,517k 1,541k
Relative poverty, before housing costs: everyone 11,750k 11,084k 11,387k 11,364k 11,416k 11,416k 11,654k
Relative poverty, before housing costs: children 3,872k 3,423k 3,496k 3,445k 3,466k 3,454k 3,551k
Relative poverty, before housing costs: working-age adults 6,159k 6,013k 6,301k 6,362k 6,389k 6,389k 6,523k
Relative poverty, before housing costs: pensioners 1,719k 1,648k 1,590k 1,558k 1,561k 1,573k 1,580k
Relative poverty, after housing costs: everyone 14,864k 14,552k 14,777k 14,809k 14,872k 15,012k 15,232k
Relative poverty, after housing costs: children 4,944k 4,660k 4,673k 4,663k 4,679k 4,707k 4,806k
Relative poverty, after housing costs: working-age adults 8,431k 8,440k 8,711k 8,823k 8,873k 8,967k 9,062k
Relative poverty, after housing costs: pensioners 1,489k 1,452k 1,393k 1,323k 1,321k 1,338k 1,364k
Inequality: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Gini coefficient, equivalised HBAI income before housing costs 0.3078 0.3050 0.3056 0.3055 0.3060 0.3066 0.3082
Mean household net income in each side's own deciles: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Decile 1: mean household_net_income per household £17,681 † £17,997 † £17,915 † £18,152 † £18,308 † £18,533 † £18,718 †
Decile 2: mean household_net_income per household £27,942 † £29,025 † £28,715 † £29,017 † £29,280 † £29,698 † £30,156 †
Decile 3: mean household_net_income per household £34,316 † £35,481 † £36,069 † £36,606 † £37,195 † £37,732 † £38,182 †
Decile 4: mean household_net_income per household £38,934 † £40,684 † £41,726 † £42,728 † £43,331 † £44,130 † £44,432 †
Decile 5: mean household_net_income per household £43,235 † £45,581 † £46,012 † £46,961 † £47,713 † £48,725 † £50,296 †
Decile 6: mean household_net_income per household £47,931 † £49,202 † £50,891 † £51,936 † £52,936 † £53,820 † £54,663 †
Decile 7: mean household_net_income per household £55,659 † £56,569 † £57,437 † £57,642 † £58,733 † £59,661 † £61,087 †
Decile 8: mean household_net_income per household £68,784 † £70,802 † £71,864 † £73,512 † £73,886 † £75,319 † £77,177 †
Decile 9: mean household_net_income per household £78,889 † £81,012 † £80,859 † £82,645 † £85,463 † £86,945 † £89,508 †
Decile 10: mean household_net_income per household £116,861 † £120,161 † £124,545 † £126,420 † £125,753 † £128,368 † £130,693 †
Standard reform costings (change in gov_balance): head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Raise basic rate by 1pp £6.41bn £6.66bn £6.63bn £6.85bn £7.03bn £7.25bn £7.49bn
Raise higher rate by 1pp £3.61bn £3.87bn £4.00bn £4.22bn £4.44bn £4.71bn £4.83bn
Raise personal allowance by ~800GBP/year £-3.81bn £-3.93bn £-3.99bn £-4.05bn £-4.11bn £-4.24bn £-1.95bn
Raise child benefit by 25GBP/week per additional child £-1.99bn £-1.75bn £-1.55bn £-1.38bn £-1.30bn £-1.18bn £-1.07bn
Reduce Universal Credit taper rate to 20% £-20.77bn £-21.32bn £-21.75bn £-22.00bn £-22.35bn £-22.75bn £-22.94bn
Raise Class 1 main employee NICs rate to 10% £10.89bn £11.30bn £11.71bn £12.01bn £12.31bn £12.62bn £13.00bn
Raise VAT standard rate by 2pp £24.89bn £25.71bn £26.63bn £27.24bn £27.87bn £28.50bn £29.14bn
Raise additional rate by 3pp £2.90bn £3.15bn £3.22bn £3.41bn £3.61bn £3.85bn £4.14bn
Raise the Universal Credit standard allowance by 10% £-3.06bn £-3.18bn £-3.26bn £-3.35bn £-3.44bn £-3.49bn £-3.50bn
Raise the State Pension by 10% £-7.76bn £-8.00bn £-8.22bn £-8.45bn £-8.80bn £-8.53bn £-8.87bn
Standard reforms: change in each reform's target: head levels
Measure (head) 2025-26 2026-27 2027-28 2028-29 2029-30 2030-31 2031-32
Raise basic rate by 1pp: change in income_tax £6.55bn £6.86bn £6.79bn £7.00bn £7.20bn £7.44bn £7.66bn
Raise higher rate by 1pp: change in income_tax £3.61bn £3.92bn £4.01bn £4.23bn £4.45bn £4.72bn £4.84bn
Raise personal allowance by ~800GBP/year: change in income_tax £-3.93bn £-4.07bn £-4.13bn £-4.18bn £-4.22bn £-4.40bn £-1.75bn
Raise child benefit by 25GBP/week per additional child: change in child_benefit £2.33bn £2.14bn £1.94bn £1.76bn £1.65bn £1.52bn £1.40bn
Reduce Universal Credit taper rate to 20%: change in universal_credit £20.74bn £21.31bn £21.79bn £22.05bn £22.37bn £22.78bn £22.99bn
Raise Class 1 main employee NICs rate to 10%: change in national_insurance £11.15bn £11.63bn £12.00bn £12.29bn £12.61bn £12.94bn £13.31bn
Raise VAT standard rate by 2pp: change in vat £24.69bn £25.51bn £26.42bn £27.03bn £27.65bn £28.28bn £28.91bn
Raise additional rate by 3pp: change in income_tax £2.90bn £3.15bn £3.22bn £3.42bn £3.62bn £3.86bn £4.12bn
Raise the Universal Credit standard allowance by 10%: change in universal_credit £3.06bn £3.19bn £3.28bn £3.37bn £3.43bn £3.49bn £3.51bn
Raise the State Pension by 10%: change in state_pension £10.68bn £11.17bn £11.28bn £11.60bn £12.03bn £12.46bn £12.96bn

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Ready for hub review

Verdict: APPROVE WITH NITS at 9ef585defd64daa7fb592b26af631c058c1be497

I reviewed 5acffdbd8..9ef585def, the five commits after the base merge. The model change is right. Each nation's conditions, AFIP routes, start dates and amounts match the law files and rulespec-uk#533's table, Housing Benefit gives the same results, and every test passes, at the head and on the merges. Three things need fixing before merge, all small. One property's oracle is wrong for part of its input space. Another property never draws the AFIP case it exists to check. One line in the body is stale. The rest is text.

Findings

P1

None.

P2

P2-1. The family-total property's oracle is wrong for a child under 5 whose only award is the lower DLA mobility rate.
policyengine_uk/tests/test_council_tax_reduction_pensioner_child_disability_premium_properties.py:95, :109 and :204. AWARDS says dla_mobility_lower meets the disabled child condition on its own at any age, and child_strategy draws a child's age from 0 to 15. But dla_m pays the lower mobility rate only from age 5 (gov.dwp.dla.mobility.lower_min_age, which cites SSCBA s.73(1A)(b)), so the model correctly gives such a child nothing. The six examples, fixed by derandomize=True, never draw that child, so CI passes today. Recording them as in P2-2 finds 47 children. The one under 5 on that award, a Welsh 4-year-old in 2017, also has DLA care at the lowest rate, which qualifies on its own. A change to the strategies or the example count, or a new Hypothesis version in uv.lock, can turn the test red against a model that is right. This is the same kind of generator gap as the dla_sc_category collision the hand-off fixed with unique_by.

I ran the module's own test body on explicit inputs (fn.hypothesis.inner_test(families, 2026), England, one child, awards ["dla_mobility_lower"]):

FAIL  family total, child aged 3 on dla_mobility_lower only, 2026: ... [0]: 0.0 (ACTUAL), 4391.92 (DESIRED)
FAIL  family total, child aged 4 on dla_mobility_lower only, 2026: ... [0]: 0.0 (ACTUAL), 4391.92 (DESIRED)
PASS  family total, child aged 5 on dla_mobility_lower only, 2026
{'dla_m': [0.0, 0.0], 'council_tax_reduction_pensioner_child_disability_premiums': [0.0], 'housing_benefit_child_disability_premiums': [0.0]}

Replace line 204, disabled = any(AWARDS[award][1] for award in child["awards"]), with:

    disabled = any(
        AWARDS[award][1]
        # dla_m pays the lower mobility rate only from age 5.
        and not (
            award == "dla_mobility_lower"
            and child["kind"] == "child"
            and child["age"] < 5
        )
        for award in child["awards"]
    )

On a patched copy, ruff leaves this unchanged, and the test body passes for a child aged 3, 4, 5 and 10 with ["dla_mobility_lower"] and with ["dla_mobility_lower", "blind"].

P2-2. The AFIP-exception property draws no AFIP, so it can't check the AFIP half of invariant 3.
test_enhanced_without_disabled_child_premium_only_through_afip (property file lines 298-335). I wrapped the module's calculate, leaving the test's source unchanged so the derandomize=True seed holds, and recorded its six examples. None has an AFIP award:

  • England 2015: a child on DLA care at the lowest rate
  • Scotland 2016: a child on DLA care at the highest rate
  • England 2026: a young person on enhanced PIP daily living and DLA care at the lowest rate
  • Wales 2020: a young person on standard PIP daily living
  • England 2015: a young person on DLA care at the lowest rate and enhanced PIP daily living
  • Wales 2024: a child on standard PIP daily living

So exception is always false, and the test can't catch a wrong AFIP route: it passes under the nil, no-AFIP, route-swap and Wales-2023 mutations. The YAML cases do cover the routes: those mutations fail 20, 5, 4 and 1 cases. test_family_total_is_the_sum_of_each_childs_premiums happens to draw two AFIP children, a Welsh young person in 2017 on DLA care at the middle rate and an English young person in 2023 on AFIP alone. That is enough to catch the no-AFIP and swap mutations, but no property catches a wrong Welsh route date. Add explicit examples so every route is checked on every run:

from hypothesis import HealthCheck, assume, example, given, settings

and, between the @given(...) call and def test_enhanced_without_disabled_child_premium_only_through_afip(:

# Each AFIP route for a child and a young person, which the six drawn
# examples may not reach.
@example("ENGLAND", 2022, "child", ["afip"])
@example("ENGLAND", 2022, "young_person", ["afip"])
@example("ENGLAND", 2023, "child", ["afip"])
@example("ENGLAND", 2023, "young_person", ["afip"])
@example("WALES", 2023, "child", ["afip"])
@example("WALES", 2023, "young_person", ["afip"])
@example("WALES", 2024, "child", ["afip"])
@example("WALES", 2024, "young_person", ["afip"])
@example("SCOTLAND", 2026, "child", ["afip"])
@example("SCOTLAND", 2026, "young_person", ["afip"])

On a patched copy, ruff leaves this unchanged and the test passes at the head. Under the no-AFIP, route-swap and Wales-2023 mutations it fails (assert enhanced_only == exception), where today's version passes all three.

P2-3. The body's "No survey-data run measured this change." is stale.
The Aggregate impact job (run 41654077564, comment 6608138001) ran on certified enhanced_frs_2024_25.h5, comparing main 1d4d020aa1 with this PR merged into it (1461ec9bdb). That merge includes #2826 and #2808, so the report doesn't isolate these five commits. Its Council Tax Reduction rows show spending of −£0.1m, +£67,865, +£44,867, −£28,718, −£87,455, −£85,901 and −£0.2m for 2025-26 to 2031-32, and caseload changes of +254, +255, +255, 0, 0, 0 and −104. A reader would ask why a PR that only adds premiums lowers CTR spending. The answer is in #2826's own report (base 46a60678ff, head 2d90bcc1c8, updated at 17:23Z on 2 November, after #2826's head 06e51a8ab was committed at 16:00Z). I extracted every change-table row from both comments and diffed them: all 59 rows match, so the whole movement is #2826's. #2808 and this PR's commits move no figure the report prints. #2808's report has no CTR change row.

Replace the line with:

The Aggregate impact job compares main with this PR merged into it, so it includes #2826 and #2808. Its Council Tax Reduction rows (spending from −£0.1m in 2025-26 to −£0.2m in 2031-32, caseload from +254 to −104) and every other changed row match #2826's own report, so on the certified data this PR's five commits move no figure the report prints.

P3

P3-1. The Welsh and Scottish A2c comments cite England's provisions.
council_tax_reduction_pensioner_child_disability_premiums.yaml:388-390 (Wales) and :568-570 (Scotland) both say "(England Sch 1 paras 2(e), 7(1) and 10(2))". sed -n 386,392p and sed -n 566,572p show the English citation in both. Nobody quoted the Welsh or Scottish provisions. The model's own parameters gov.local_authorities.wales.council_tax_reduction.maximum_support_rate (value 1, citing WSI 2013/3029 Sch 1 para 2(1)) and ...scotland...maximum_support_rate (value 1, citing SSI 2012/319 reg 47(1)) cover the point. Replace:

    # Applicable income 21,714.00 falls short of 25,092.60, so the council
    # gives the maximum reduction, the whole council tax
    # (gov.local_authorities.wales.council_tax_reduction.maximum_support_rate),
    # here 2,000.
    # Applicable income 21,753.67 falls short of 25,183.60, so the council
    # gives the maximum reduction, the whole council tax
    # (gov.local_authorities.scotland.council_tax_reduction.maximum_support_rate),
    # here 2,000.

P3-2. No test covers the Northern Ireland nil that the body and the documentation claim.
The YAML has no Northern Ireland case, and the property generator draws only England, Wales and Scotland (AUTHORITIES, line 56). My mutation ni_gets_england, which gives Northern Ireland England's amounts and routes, survives: all 30 YAML cases and all 6 properties pass. The code itself is right: in my differential below, no Northern Ireland unit got a premium, across 321 pension-age units whose Housing Benefit child premiums were positive. Add this case. It passes at the head, and under that mutation it fails with council_tax_reduction_pensioner_child_disability_premiums@2026: [6159.4] differs from 0.0:

- name: Nil, a pensioner in Northern Ireland with a child on the highest DLA care rate gets no child disability premium.
  period: 2026
  absolute_error_margin: 0.01
  input:
    people:
      pensioner:
        age: 72
        state_pension: 12_570
      child:
        age: 10
        dla_sc_category: HIGHER
    benunits:
      benunit:
        members: [pensioner, child]
        would_claim_pc: false
        would_claim_uc: false
    households:
      household:
        members: [pensioner, child]
        country: NORTHERN_IRELAND
  output:
    council_tax_reduction_pensioner: true
    # The child meets both conditions, as Housing Benefit's reading shows.
    housing_benefit_child_disability_premiums: 6_159.40
    council_tax_reduction_pensioner_child_disability_premiums: 0

P3-3. Four cases give a 10-year-old an AFIP.
These are "AFIP England 2023, a child under 16", "AFIP Wales 2023", "AFIP Wales 2024" and "AFIP Scotland 2026, a child under 16" (YAML lines 636-751). The property generator also gives AFIP to children aged 0 to 15. The model allows this. In law, England para 7(1)(c) and Wales paras 7(1)(c) and 8(d) do reach "a child or young person", so the cases test the drafting. Two of them, England 2023 and Scotland 2026, are among the four cases that kill the route-swap mutation. But the model documents AFIP as payable "to people with a guaranteed income payment at a relevant percentage of 50% or more" (policyengine_uk/variables/gov/dwp/afip.py:7-10). I think only an injured serving or former member of the forces holds such a payment, and no child under 16 can be one. Nobody quoted article 24A of SI 2011/517, though, so I can't confirm that from the law. Add a comment above line 636:

# The Secretary of State and the Welsh Ministers name AFIP for a child or
# young person (England para 7(1)(c); Wales paras 7(1)(c) and 8(d)); the
# cases with a 10-year-old on AFIP test that wording.

P3-4. The property module's docstring names a constant that doesn't exist and understates invariant 3.
grep -n "AFIP_ROUTES\|afip_routes" on the property file prints 13:(AFIP_ROUTES)., 77:def afip_routes(...) and 207:...afip_routes(. Lines 11-13 should read:

daily living rate. The armed forces independence payment (AFIP) meets a
condition where the nation's ministers name it for that person in that year
(afip_routes).

Lines 23-26 limit Wales's exception to a child under 16, but the test (exception = ... or (country == "WALES" and year < 2024), lines 331-334) and the body cover any child or young person. Replace with:

3. On the model's inputs, every child or young person who meets the enhanced
   condition also meets the disabled child condition, except through AFIP:
   AFIP alone meets only the enhanced condition for a child under 16 in
   England from 2023, and for any child or young person in Wales before 2024.

Line 154 calls the household head "her" although the generator never sets a sex. Replace "as the claimant couple in her benefit unit." with "as the claimant couple in the head's benefit unit."

P3-5. The helper's docstring says both conditions read only DLA and PIP fields.
policyengine_uk/variables/gov/dwp/housing_benefit/_child_disability_premiums.py:20-21, but the disabled child condition also reads is_blind (grep -n is_blind prints 25: disabled_child = dla | pip | person("is_blind", period)). Replace with:

    Neither condition reads a field for child disability payment or adult
    disability payment, which the model lacks, so callers enter those awards
    in the DLA and PIP fields.

P3-6. Fix history in a durable comment.
YAML line 30 says "(#2826's parameters)". Replace with "(the child_or_young_person and family_premium parameters under gov.local_authorities..council_tax_reduction.pensioners.applicable_amount)".

P3-7. Writing rules: a provision, scheme or benefit acts, or "we" does.

Where Now Replace with
YAML 6-8 SI 2023/16 adds an AFIP limb for any child or young person to para 7 and for a young person to para 8, for schemes from 1 April 2023. For schemes from 1 April 2023 the Secretary of State added an AFIP limb to para 7 for any child or young person, and to para 8 for a young person (SI 2023/16 regs 1(3) and 7(7)-(8)).
YAML 9-11 Para 7(1)(c) names AFIP for any child or young person; WSI 2024/56 adds it to para 8 for schemes from 1 April 2024. The Welsh Ministers name AFIP for any child or young person in para 7(1)(c), and added it to para 8 for schemes from 1 April 2024 (WSI 2024/56 regs 1(3) and 5(d)).
YAML 12-13 Paras 8(1)(aa) and 9(ba) name AFIP for a young person only. The Scottish Ministers name AFIP for a young person only (paras 8(1)(aa) and 9(ba)).
YAML 32 We multiply weekly amounts by 52. The formula multiplies weekly amounts by 52.
YAML 662 # Para 8(e) reaches only a young person: 30.17 * 52 = 1,568.84. # The Secretary of State gives AFIP the disabled child premium for a young person only (para 8(e)): 30.17 * 52 = 1,568.84.
YAML 749 # Paras 8(1)(aa) and 9(ba) reach only a young person. # The Scottish Ministers give AFIP both premiums for a young person only (paras 8(1)(aa) and 9(ba)).
council_tax_reduction_pensioner_child_disability_premiums.py:23-24 where the nation's scheme names it for that person in that year where the nation's ministers name it for that person in that year
same file, 71-72 # Each scheme names the armed forces independence payment for a child, # a young person, both or neither, by premium and year. # The Secretary of State and the Welsh and Scottish Ministers name the # armed forces independence payment for a child, a young person, both or # neither, by premium and year.
housing_benefit_child_disability_premiums.py:43-44 # Housing Benefit counts AFIP for any child or young person in both # premiums. # The formula counts AFIP for any child or young person in both premiums.
PR body, "What the model does now", last bullet SI 2012/2885 reg 2, WSI 2013/3029 reg 2 and SSI 2012/319 reg 4 define a young person by SSCBA s.142, and The Secretary of State, the Welsh Ministers and the Scottish Ministers define a young person by SSCBA s.142 (SI 2012/2885 reg 2; WSI 2013/3029 reg 2; SSI 2012/319 reg 4), and
six amount files, lines 3-4 (optional: child_or_young_person.yaml has the same wording) # We take each value from the table of premium amounts in the version # of the schedule in force on 30 April of that year. # Each value is the weekly amount in the table of premium amounts in the # version of the schedule in force on 30 April of that year.

P3-8. The body's revert claim describes a run with the helper copied in.
"Without this PR's commits, all 30 YAML cases fail, and 5 of the 6 properties fail; the property on the shared helper alone passes." On the base merge with only the new test files copied in, the YAML gives 30 failed, because the variable doesn't exist. The property module gives 1 error: ModuleNotFoundError: No module named 'policyengine_uk.variables.gov.dwp.housing_benefit._child_disability_premiums'. With the helper copied in too, the properties give 5 failed, 1 passed, and the one that passes is test_shared_enhanced_condition_implies_disabled_child_condition. Replace with: "Without this PR's commits, all 30 YAML cases fail, because the variable doesn't exist, and the property module fails to import, because the helper doesn't exist. With only the helper copied in, 5 of the 6 properties fail; the one that reads only the helper passes."

P3-9. Two more body lines.

  • "Who reads": "Through it, council_tax_reduction_applicable_income comparisons, council_tax_reduction and council_tax_benefit can rise for such a family." The applicable income doesn't change. Replace with: "Through it, the excess of council_tax_reduction_applicable_income over the applicable amount can fall, and council_tax_reduction and council_tax_benefit can rise, for such a family."
  • "This head merges into main (1d4d020aa) without conflict." main has moved. Replace with: "This head merges into main (9b456bda6) without conflict." I ran git merge-tree --write-tree --name-only 9ef585def 9b456bda6: exit 0, tree 8f3bdeef6.

P3-10. council_tax_reduction_premiums's rewritten sentence leaves out the working-age swap.
council_tax_reduction_premiums.py:14-18 says "otherwise working_age_benefits_premiums". But lines 67-75 swap in Council Tax Reduction's own severe disability and enhanced disability premiums. The base already omitted the swap, but this PR rewrote the sentence. Replace "; otherwise working_age_benefits_premiums." with "; otherwise working_age_benefits_premiums, with Council Tax Reduction's own severe disability and enhanced disability premiums in place of the shared ones."

P3-11. Reference titles in England's two amount files list paragraphs out of order.
Line 76 of each file reads "Sch. 2 paras. 8 and 4" and "paras. 7 and 4". Use "Sch. 2 paras. 4 and 8, Part 4 entry (3)" and "Sch. 2 paras. 4 and 7, Part 4 entry (2)".

P3-12. The hand-off's resolution of the #2827 conflict drops a fact from #2827's side.
I confirmed the conflict. git merge-tree --write-tree --name-only 9ef585def f9fdc636a and the same at 5acffdbd8 both conflict only in council_tax_reduction_premiums.py, in the same two hunks, word for word. The hand-off's resolution drops #2827's "both differ from the shared premiums only in Scotland". This one keeps both sides; I committed it on a scratch merge, ruff left it as it was, and on that merge the new YAML passes (30) and so does the CTR YAML directory (427, which is the head's 415 plus #2827's 12 carer premium cases).

        # The working-age severe disability premium takes Council Tax
        # Reduction's own family test (council_tax_reduction_severe_disability_
        # premium) and the working-age carer premium its own caring test
        # (council_tax_reduction_carer_premium); both differ from the shared
        # premiums only in Scotland. The enhanced disability premium takes the
        # scheme's own condition
        # (council_tax_reduction_enhanced_disability_premium).
            + (
                benunit("council_tax_reduction_enhanced_disability_premium", period)
                - benunit("enhanced_disability_premium", period)
            )
            + (
                benunit("council_tax_reduction_carer_premium", period)
                - benunit("carer_premium", period)
            ),

P3-13. rulespec-uk#533.

  • England's amount quote drops the repeated entry numbers in the amount column. The 2026 law file reads "(2) Enhanced disability premium. | (2) £33.99 in respect of each child or young person in respect of whom the conditions specified in paragraph 7 are satisfied." and "(3) Disabled Child Premium. | (3) £84.46 in respect of each child or young person in respect of whom the condition specified in paragraph 8 is satisfied". The issue gives "| £33.99" and "| £84.46". Wales's quote keeps them, and Scotland's text has none.
  • It cites WSI 2024/56 reg 5(e) twice, under "Module path" and in review_finding, but quotes only 5(d). Quote 5(e) or drop it.
  • .github/CONTRIBUTING.md:61 says "Use queued only when the signed encoder is blocked; record the blocker in the issue." The issue body I was given records no blocker, and I couldn't see its labels.
  • "legislation.gov.uk notes that SSI 2013/142 regs 1 and 12(7)(c) and (d) inserted paras 8(1)(aa) and 9(ba)" makes a regulation act. Replace with "legislation.gov.uk notes that the Scottish Ministers inserted paras 8(1)(aa) and 9(ba) from 11 June 2013 (SSI 2013/142 regs 1 and 12(7)(c) and (d))."

Checked and sound

Law. I checked every condition against the law files, nation by nation and year by year. For the disabled child condition, England para 8(a)-(b) (2015, 2022, 2023, 2026), Wales para 8(a)-(b) (2015, 2023, 2024, 2026) and Scotland para 9(a)-(b) (2015, 2026) each rest on receipt of DLA or PIP, either component, or blindness. The helper tests dla_sc > 0 | dla_m > 0 | pip_dl > 0 | pip_m > 0 | is_blind. For the enhanced condition, England para 7(1)(a)-(b), Wales para 7(1)(a)-(b) and Scotland para 8(1)(a), (b) each rest on the DLA care component at the highest rate or the PIP daily living component at the enhanced rate. The helper tests has_highest_dla_sc_award | has_enhanced_pip_dl_award, each of which requires a positive amount. The limbs the PR leaves out (hospital, s.145A, child disability payment, adult disability payment, Scottish Adult DLA) are documented. The model has no CDP, ADP or SADLA field: grep -rhn "^class " policyengine_uk/variables finds none.

AFIP routes, cell by cell. Each cell matches the law files:

  • England EDP: none in 2015 or 2022. Para 7(1)(c) in 2023 and 2026 reaches "a child or young person".
  • England DCP: none in 2015 or 2022. Para 8(e) in 2023 and 2026 reaches "a young person" only.
  • Wales EDP: para 7(1)(c) reaches a child or young person in every file, 2015 to 2026.
  • Wales DCP: none in 2015 or 2023. Para 8(d) in 2024 and 2026 reaches any child or young person, through para 8's opening words.
  • Scotland: paras 8(1)(aa) and 9(ba) reach a young person only, in 2015 and 2026.

The start dates follow SI 2023/16 reg 1(3) and WSI 2024/56 reg 1(3) as quoted. I printed all twelve booleans for each year from 2015 to 2030 through CountryTaxBenefitSystem().parameters. England's EDP routes are 00 to 2022 and 11 from 2023, and its DCP routes 00 then 01. Wales's EDP routes are 11 throughout, and its DCP routes 00 to 2023 and 11 from 2024. Scotland's are 01 for both premiums throughout. Every year matches the body's table and rulespec-uk#533's.

Who counts. For any pensioner family, is_child_or_young_person_for_council_tax_reduction returns is_child_or_young_person_for_legacy_benefits: the Scottish working-age branch needs ~council_tax_reduction_pensioner. That flag counts a benefit-unit member who is a Child Benefit child (under 16) or qualifying young person (16 to 19, in non-advanced education or approved training begun before 19, and not on Universal Credit, ESA or JSA in their own right), other than the claimant, the partner or a child looked after by a local authority. So any counted person who isn't a qualifying young person is under 16, and the AFIP young-person test can't misclassify one. My mutation young_person_any_16_plus, which swaps the qualifying-young-person test for age >= 16, is equivalent: it survives every YAML case and property, as it should. Benefit-unit membership stands in for para 8's "responsible for … and a member of the applicant's household", and para 7 reaches the same people through "member of the applicant's family". The flag leaves out looked-after children. Until #2016 merges it still counts a child placed for adoption, whom, by #2016's docstring, the schemes leave out (SI 2012/2885 reg 8(2) and its equivalents). The new variable then follows #2016.

Amounts. I compared all six files with rulespec-uk#533's table: 82 cells, with Wales starting in 2014 and 2016 read through the 2015 entry, and no differences. They also match the law files for England 2015, 2022, 2023 and 2026 and Scotland 2015 and 2026. The files start on 2013-04-01 (England and Scotland) and 2014-04-01 (Wales). Every dated reference opens /schedule/<n>/<year>-04-30 for its own year, and the 2015 entry says "unchanged to 2016-17". All six uprate with gov.benefit_uprating_cpi. Through the model they equal gov.dwp.housing_benefit.premiums.enhanced_disabled_child and .disabled_child in every year from 2015 to 2035, for example 35.18 and 87.42 in 2027 and 41.87 and 104.03 in 2035. So the descriptions' equality claim holds, and uprating after 2026-27 tracks Housing Benefit.

Pre-2015 years. The England and Wales AFIP files start in 2015. A 2013 or 2014 run of council_tax_reduction_premiums fails at the head, but on gov.dwp.pension_credit.mixed_age_couples[saving_latest_birth_date], exactly as it does on the base, so the PR adds no failure. A 2015 run gives 4,393.48 in each nation.

Code. pensioner * applicant_family * ... gives nil to working-age families and to a head who applies alone. select(..., default) gives Northern Ireland nil amounts and False routes. Adding the variable to the pensioner branch of council_tax_reduction_premiums leaves the head-alone branch (head_premiums) and the working-age branch unchanged. Of the variables, only council_tax_reduction_applicable_amount reads council_tax_reduction_premiums. The body's list of tests that read it is complete: housing_benefit_pre_cutoff_period.yaml, applicant_or_partner.yaml, enhanced_disability_premium.yaml, test_council_tax_reduction_applicant_properties.py and test_housing_benefit_pension_age_cohorts.py, which sets it as an input.

Housing Benefit unchanged. Housing Benefit keeps its own AFIP route, any child or young person in both premiums: disabled = disabled | afip and enhanced = enhanced | afip at housing_benefit_child_disability_premiums.py:45-47, over the same legacy child flag as before. The helper reproduces the old DLA, PIP and blindness expressions term for term. I ran my own generator on the base merge and the head: 250 benefit units a year for 2015 to 2030, so 4,000 units, of which 1,848 have positive child premiums. They cover all four nations, adults of working and pension age, and children aged 0 to 19 with DLA care by category and by direct amount (to reach has_highest_dla_sc_award through the amount route), DLA mobility, PIP, blindness, AFIP and looked-after status. housing_benefit_child_disability_premiums differs in 0 units, and so does housing_benefit_applicable_amount. On the same head run, the new variable is nil in every working-age and Northern Ireland unit. It equals Housing Benefit's child premiums in all 1,587 pension-age units in Great Britain with no AFIP, 2015 to 2030, and the two child flags agree in every one.

The issue's cases. On the base merge 5acffdbd8, A2 gives 17,881.76, 18,933.20 and 19,024.20, and A2c gives £1,233.55, £1,443.84 and £1,454.11 (England, Wales, Scotland), the issue's model column. At the head, A2 gives 24,041.16, 25,092.60 and 25,183.60, A3 and A4 give 22,273.68, 23,325.12 and 23,416.12, and A2c gives £2,000.00 in each nation, the issue's statutory column.

The 30 YAML cases by hand.

  • A1: (256.00 + 87.88) × 52 = 17,881.76; Wales (256.00 + 87.88 + 20.22) × 52 = 18,933.20; Scotland (256.00 + 109.85) × 52 = 19,024.20.
  • A2 adds 118.45 × 52 = 6,159.40, and A3 and A4 add 84.46 × 52 = 4,391.92.
  • A2c: income 24,000 less tax of 20% × (24,000 − 12,570) = 2,286 gives 21,714.00, below each applicable amount, so 2,000. The base gives 2,000 − 0.2 × (21,714.00 − 17,881.76) = 1,233.55.
  • AFIP: England 2022 young person 0; England 2023 young person 104.86 × 52 = 5,452.72; England 2023 child 30.17 × 52 = 1,568.84; Wales 2023 child 1,568.84; Wales 2024 child 112.21 × 52 = 5,834.92; Scotland 2026 child 0; Scotland 2026 young person 6,159.40.
  • 2015: 84.49 × 52 = 4,393.48 in each nation.
  • The working-age and head-alone cases give nil.

All 30 match. The inputs describe families the model allows; the head-alone household follows the example in council_tax_reduction_head_applies_alone's documentation. The Scottish 2026 cases enter DLA for a Scottish child. Scotland's 2026 text treats child disability payment the same way (paras 8(1)(c) and 9(a)), and the documentation tells callers to enter it in the DLA fields, so the cases stand for that too. The one realism doubt is P3-3.

Invariants against the properties.

  1. test_nil_for_working_age_families_and_a_head_who_applies_alone (no Northern Ireland: P3-2).
  2. test_family_total_is_the_sum_of_each_childs_premiums (oracle gap: P2-1).
  3. test_shared_enhanced_condition_implies_disabled_child_condition and test_enhanced_without_disabled_child_premium_only_through_afip (no AFIP drawn: P2-2).
  4. test_applicable_amount_never_falls_when_a_child_gains_a_benefit.
  5. test_matches_housing_benefit_child_premiums_without_afip, 12 years per example.

Invariant 6 has no test, but my differential covers it.

Mutations. I applied each to a scratch copy of the head, ran the new YAML and the property file (-n 4), and restored the copy. Shrinking was off, so a failing property reports at once: a pytest plugin outside the repository loads a Hypothesis profile with only the explicit, reuse and generate phases, and the control run passes with it.

Mutation Change New YAML (30) Properties (6) Result
none (control) 30 pass 6 pass
nil (body) the formula returns 0 20 fail 2 fail: family total, differential killed, as the body says
no_afip (body) both AFIP routes removed 5 fail 1 fails: family total killed, as the body says
swap_routes (body) child and young-person routes swapped 4 fail 1 fails: family total killed, as the body says
ni_gets_england Northern Ireland takes England's amounts and routes 0 fail 0 fail survived (P3-2)
no_head_alone_gate applicant_family dropped 1 fails: the head-alone case 1 fails: nil property killed
enhanced_any_care_rate helper's enhanced condition on any DLA care rate (dla_sc > 0) 3 fail: A3 in each nation; HB YAML 4 of 62 fail 1 fails: family total killed
wales_dcp_afip_from_2023 Wales's disabled child AFIP route for a child starts 2023-04-01 1 fails: Wales 2023 0 fail killed by the YAML only (P2-2)
not_in_premiums the variable left out of council_tax_reduction_premiums 15 fail 0 fail killed by the YAML only
young_person_any_16_plus the young-person test becomes age >= 16 0 fail 0 fail survived, an equivalent mutant (see "Who counts")
helper_drops_dla the disabled child condition ignores DLA 12 fail 3 fail: helper implication, AFIP exception, family total killed; so the helper-only property can fail

rulespec-uk#533. Every quote of a provision that the law files contain matches them word for word, except the England amount formatting in P3-13. That covers England paras 7 and 8 (2015, 2023), Wales paras 7 and 8 (2015, 2024), Scotland paras 8 and 9 (2015) and the Scottish amounts (2026). The AFIP table matches the law files. I worked C1 to C12 by hand and ran them through the model at the head: C1 118.45, C2 84.46, C3 84.46, C4 0, C5 104.86, C6 30.17, C7 30.17, C8 112.21, C9 0, C10 118.45, C11 84.49, C12 33.99 + 2 × 84.46 = 202.91 a week. All twelve match.

Changelog, title and descriptions. changelog.d/2824.fixed.md is one active sentence that matches the code, and the Changelog fragments check passed. The title is in sentence case. The AFIP descriptions ("Councils in England count a child (under 16) … if this is true.") match the values. The labels are sentence-case noun phrases.

Fix evidence. I ran .github/check_fix_pr.py from main at 9b456bda6 the way pr_fix_evidence.yaml runs it: live title and body, no labels, --changes-file from git diff --name-status --no-renames -z between merge-base 0080274d7 and the head, --head-sha 9ef585def. Output: Fix evidence: PASS ('Add the child disability premiums to pensioner Council Tax Reduction'), "Fix PR has valid reproducer evidence. Changed executable tests: 16.", exit 0. Both reproducer names match YAML cases exactly, trailing full stops included.

Tests at the head (uv sync --frozen --extra dev, dataset variables unset):

Run Result
new YAML file 30 passed
CTR YAML directory 415 passed
housing_benefit_pre_cutoff_period.yaml 4 passed (415 + 4 = the body's 419)
housing_benefit_child_disability_premiums.yaml 62 passed
new property file, -n 4 6 passed in 182.86 s; the differential took 145.51 s
the five property files the body names, -n 4 96 passed
policyengine_uk/tests/code_health, -n 4 3,135 passed
ruff format --check, ruff check on the 7 changed Python files, git diff --check clean

CI at the head. All 21 check runs completed with success: Aggregate impact; Changelog fragments; Changes; Documentation build; Fix evidence (twice, on open and on the body edit at 14:56Z); Install + smoke-import on py3.11 to 3.14; Lint; Release build records the commit; Test / Python 1/7 to 7/7; Test / Result; Test / YAML. None failed. The only annotations are cache-reservation and Node.js 20 deprecation warnings. The combined-status endpoint reads pending only because no legacy statuses exist.

Merges (git merge-tree --write-tree --name-only):

With Result
main 9b456bda6 (current) clean, tree 8f3bdeef6
main 1d4d020aa (PR base) clean
#2845 f379377f9 clean (tree 485c573ea). On the scratch merge: new YAML 30 passed, properties 6 passed. #2845 changes only the Scottish working-age branch of the CTR child flag.
#2016 983488065 clean (tree 563ab2ac5). On the scratch merge: new YAML 30 passed, properties 6 passed. #2016 changes the legacy flag, which both the new variable and Housing Benefit read for pensioners.
#2827 f9fdc636a conflict in council_tax_reduction_premiums.py, the same two hunks as at 5acffdbd8; resolution in P3-12
#1966 a013f520a conflict only in severe_disability_premium_young_person.yaml, which this PR doesn't touch. #2808's head alone conflicts there with #1966, and main and #2826 merge cleanly with it. #1966 also changes council_tax_reduction_pensioner.py, which the new variable reads. On a scratch merge taking #1966's side of that YAML, the new YAML passes (30).

Hand-off claims. No earlier review round exists, so there are no earlier findings to close. I reproduced the base tree ef486deac, the merge parents, the issue's columns, the test counts and the three mutation counts. "No difference from the issue" holds. The unique_by fix works, but P2-1 and P2-2 are further generator gaps. The judgement calls on young person, AFIP start dates, parameter layout and docs are sound. No page under docs/ describes CTR premiums, and programs.yaml has no stale note.

What I couldn't check

  • Missing law files. No Welsh amount: the Welsh law files stop at para 12(1). I checked the Welsh amounts only against rulespec-uk#533's table and the Housing Benefit parameters. Nor any value for a year with no law file: England 2013, 2014, 2016 to 2021, 2024 and 2025; Scotland 2013, 2014 and 2016 to 2025. The 2025 values in all three nations agree with the amending instruments that issue Pension-age Council Tax Reduction omits the disabled child and enhanced disability premiums #2824 quotes (SI 2026/27 reg 6(9), WSI 2026/13 reg 8(d), SSI 2026/56 reg 6(c)).
  • Same-text claims. rulespec-uk#533's "(the same text to 2021)" and "(the same text to 2025)" for England. The 2026 file differs from 2023, with para 7(1)(aza) and para 8(ab) for Scottish Adult DLA, so whether 2024 and 2025 match 2023 needs those files.
  • Young person definitions. WSI 2013/3029 reg 2 and SSI 2012/319 reg 4, which nobody quoted. England's reg 2 appears only in issue Pension-age Council Tax Reduction omits the disabled child and enhanced disability premiums #2824 and rulespec-uk#533, not in a law file. Nor whether the model's receives_benefits_in_own_right exclusion matches the prescribed conditions under SSCBA s.142.
  • Responsibility and household rules. The schemes' own rules (SI 2012/2885 regs 7 and 8 and their Welsh and Scottish equivalents), against which benefit-unit membership is only a stand-in.
  • Amending instruments. The texts and titles of SI 2023/16, WSI 2024/56 (including reg 5(e)) and SSI 2013/142, and the 11 June 2013 date. The law files carry no amendment notes.
  • Other provisions nobody quoted. HB Regs 2006 Sch 3 paras 15 and 16, behind Housing Benefit's AFIP route for any child or young person. Article 24A of SI 2011/517 (P3-3). Whether England's two-child limit for the 2018-19 to 2024-25 schemes (Sch 1 para 6(1A) to (1C)) reaches the child premiums. The PR doesn't limit them, and no YAML or companion case has more than two qualifying children in those years. England Sch 1 paras 2(e), 7(1) and 10(2) and their Welsh and Scottish equivalents.
  • rulespec-uk#533 itself. Its labels (pe-parity), whether its uk/regulations/... paths follow Implement basic income controls #522, and Implement basic income controls #522 itself: the proxy refuses other repositories.
  • The author's own numbers. The 300-unit differential (4,800 values, 2,224 positive) rests on logs on the hub's machine; I ran my own instead.
  • Survey data. I had no dataset access, so I can't measure this delta alone on survey data. P2-3 rests on the two CI reports.

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Picking this up for the UK hub. Reply here if you're mid-change and I'll stop.


Generated by Claude Code

… tests

The family-total oracle now gives a child under 5 nothing for the lower
DLA mobility rate alone, as dla_m does, and explicit examples check that
boundary and each AFIP route on every run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6FttQdG5fxwz6TgtjM
…n the YAML cases

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6FttQdG5fxwz6TgtjM
@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

PR_BODY.md

Fixes #2824
Reproducer: `policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner_child_disability_premiums.yaml::Case A2 England, a child on the highest DLA care rate adds both premiums.`; `policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner_child_disability_premiums.yaml::AFIP England 2023, a child under 16 on AFIP alone meets the enhanced condition only.`
axiom: TheAxiomFoundation/rulespec-uk#533 queued

This PR lands after #2826 and #2808. Its first commit, `5acffdbd8`, merges #2808's head (`6563f73e5`) into #2826's head (`06e51a8ab`) with no conflict (tree `ef486deac`). Review the commits after it:

1. `e2699b77` moves the conditions that Housing Benefit and CTR share into one helper;
2. `67004f48` adds each nation's amounts and AFIP routes as parameters;
3. `e4767ab5` adds `council_tax_reduction_pensioner_child_disability_premiums` and adds it to a pensioner's `council_tax_reduction_premiums`;
4. `7d8b70dd` adds the YAML cases;
5. `9ef585de` adds the property tests and the changelog fragment;
6. `a2434433` merges `main` at `9b456bda6` (tree `8f3bdeef6`);
7. `f00ad5be` gives the family-total oracle the lower DLA mobility age and adds explicit examples for that boundary and for each AFIP route;
8. `2df03f2b` adds the Northern Ireland nil case and cites each nation's own provisions in the YAML comments;
9. `16a74f81` names the actor in the comments, docstrings and parameter notes.

## What the model does now

Councils add the disabled child premium and the enhanced disability premium to a pensioner's applicable amount for each qualifying child or young person in the family: England under [SI 2012/2885](https://www.legislation.gov.uk/uksi/2012/2885/schedule/2) Sch 1 para 6(1)(d) and Sch 2 paras 7, 8 and Part 4; Wales under [WSI 2013/3029](https://www.legislation.gov.uk/wsi/2013/3029/schedule/2) Sch 1 para 1(1)(d) and Sch 2 paras 7, 8 and 12; Scotland under [SSI 2012/319](https://www.legislation.gov.uk/ssi/2012/319/schedule/1) reg 20(d) and Sch 1 paras 8, 9 and 13. Before this PR the model added neither for pensioners.

- `council_tax_reduction_pensioner_child_disability_premiums` (BenUnit, YEAR, GBP) sums over the family's children and young persons (`is_child_or_young_person_for_council_tax_reduction`). Each who meets the disabled child condition adds 52 times the nation's disabled child premium, and each who meets the enhanced condition adds 52 times its enhanced disability premium. It returns nil for a working-age family, for a household head who applies alone, and outside England, Wales and Scotland, as `council_tax_reduction_pensioner_child_amounts` does.
- A new helper, `child_disability_premium_benefit_conditions` (`policyengine_uk/variables/gov/dwp/housing_benefit/_child_disability_premiums.py`), returns the conditions the two schemes share. The disabled child condition rests on a positive DLA or PIP amount (either component) or `is_blind`, and the enhanced condition on `has_highest_dla_sc_award` or `has_enhanced_pip_dl_award`. `housing_benefit_child_disability_premiums` and the new variable each add their own armed forces independence payment (AFIP) route.
- For a pensioner, `council_tax_reduction_premiums` now adds the new variable to `pension_age_benefits_premiums`, and so holds every premium that Sch 1 para 6(1)(d) includes.
- For "young person" in the AFIP routes the formula reads `is_qualifying_young_person_for_child_benefit`, the Child Benefit qualifying young person. The Secretary of State, the Welsh Ministers and the Scottish Ministers define a young person by SSCBA s.142 (SI 2012/2885 reg 2; WSI 2013/3029 reg 2; SSI 2012/319 reg 4), and `is_child_or_young_person_for_council_tax_reduction` applies that definition to every pensioner's family. Anyone counted who does not meet it is a child under 16.

### Amounts and their sources

The Secretary of State, the Welsh Ministers and the Scottish Ministers set both amounts in the table of premium amounts in each schedule (England Sch 2 Part 4 entries (2) and (3); Wales Sch 2 para 12 entries (2) and (3); Scotland Sch 1 para 13 entries (2) and (3)). Each parameter cites the version in force on 30 April of the year, at `https://www.legislation.gov.uk/<instrument>/schedule/<n>/<year>-04-30`. They set the same amounts in all three nations, in pounds a week:

| From | Enhanced disability premium | Disabled child premium |
| --- | ---: | ---: |
| 2013-04-01 (England, Scotland) | 23.45 | 57.89 |
| 2014-04-01 (all three; Wales starts here) | 24.08 | 59.50 |
| 2015-04-01 (unchanged in 2016-17) | 24.43 | 60.06 |
| 2017-04-01 | 24.78 | 60.90 |
| 2018-04-01 | 25.48 | 62.86 |
| 2019-04-01 | 26.04 | 64.19 |
| 2020-04-01 | 26.60 | 65.52 |
| 2021-04-01 | 26.67 | 65.94 |
| 2022-04-01 | 27.44 | 68.04 |
| 2023-04-01 | 30.17 | 74.69 |
| 2024-04-01 | 32.20 | 80.01 |
| 2025-04-01 | 32.75 | 81.37 |
| 2026-04-01 | 33.99 | 84.46 |

From 2015-16, `gov.dwp.housing_benefit.premiums.disabled_child` and `.enhanced_disabled_child` hold the same amounts, but the CTR formula reads its own parameters, so a Housing Benefit reform leaves CTR alone. The files sit under `gov.local_authorities.<nation>.council_tax_reduction.pensioners.applicable_amount`, as `disabled_child_premium.yaml` and `enhanced_disability_premium.yaml`, and uprate with `gov.benefit_uprating_cpi` after 2026-27, as `child_or_young_person.yaml` does.

### AFIP routes

Boolean parameters under `applicable_amount.armed_forces_independence_payment.<premium>.{child,young_person}` hold these routes, so the formula holds no dates:

| Nation | Enhanced disability premium | Disabled child premium |
| --- | --- | --- |
| England | any child or young person, for schemes from 1 April 2023 (para 7(1)(c); [SI 2023/16](https://www.legislation.gov.uk/uksi/2023/16/made) regs 1(3) and 7(7)(c)); none before | a young person, for schemes from 1 April 2023 (para 8(e); SI 2023/16 regs 1(3) and 7(8)); none before |
| Wales | any child or young person, in every model year (para 7(1)(c)) | any child or young person, for schemes from 1 April 2024 (para 8(d); [WSI 2024/56](https://www.legislation.gov.uk/wsi/2024/56/made) regs 1(3) and 5(d)); none before |
| Scotland | a young person, in every model year (Sch 1 para 8(1)(aa), from 11 June 2013) | a young person, in every model year (Sch 1 para 9(ba), from 11 June 2013) |

`housing_benefit_child_disability_premiums` keeps its own route: AFIP for any child or young person in both premiums.

### Who reads `council_tax_reduction_premiums`

- `council_tax_reduction_applicable_amount`: rises for a pensioner family with a qualifying child or young person; otherwise unchanged. Through it, the excess of `council_tax_reduction_applicable_income` over the applicable amount can fall, and `council_tax_reduction` and `council_tax_benefit` can rise, for such a family.
- `enhanced_disability_premium.yaml`, `applicant_or_partner.yaml` (CTR directory) and `housing_benefit_pre_cutoff_period.yaml`: unchanged; none has a pensioner family with a qualifying child.
- `test_housing_benefit_pension_age_cohorts.py` sets the variable as an input; unchanged.
- `test_council_tax_reduction_applicant_properties.py` reads it among its outputs; unchanged; its test passes.

The comments at `benefits_premiums.py` and `council_tax_reduction_applicable_amount.py`, and the documentation of `council_tax_reduction_premiums` and `council_tax_reduction_applicable_amount`, now say that a pensioner's CTR premiums include the two child premiums. No page under `docs/` describes the pension-age CTR premiums, so no page changes.

## Out of scope

- The section 145A run-on after a child's death, and the hospital limbs (suspension, abatement, a patient no longer in receipt).
- Child disability payment, adult disability payment and Scottish Adult Disability Living Allowance, which have no field in the model; callers enter such awards in the DLA and PIP fields.
- The gap between the schemes' registration test for blindness and the certification wording of `is_blind`.
- Working-age CTR child premiums (#1962, #1966).

## Invariants

1. The new variable returns nil for every working-age family and wherever the household head applies alone.
2. A pensioner family's total equals the sum, over its children and young persons, of 52 times each premium whose condition the child meets.
3. On the model's inputs, a child or young person who meets the shared enhanced condition always meets the shared disabled child condition. Through AFIP alone, a child under 16 in England from 2023-24, and any child or young person in Wales before 2024-25, meets only the enhanced condition, as paras 7 and 8 provide.
4. The applicable amount and the premiums never fall when a child or young person gains a qualifying benefit.
5. For pension-age families with no AFIP, in every year from 2015 to 2026, the new variable equals `housing_benefit_child_disability_premiums`.
6. Housing Benefit's results do not change.

## Tests

- `council_tax_reduction_pensioner_child_disability_premiums.yaml` (new, 31 cases): the issue's cases A0 to A4 in each nation in 2026, on `council_tax_reduction_applicable_amount` and the new variable; A2c in each nation on `council_tax_reduction`; AFIP alone in England (a young person in 2022 and 2023, a child in 2023), Wales (a child in 2023 and 2024) and Scotland (a child and a young person in 2026); a working-age family and a head who applies alone, each with a qualifying child; a pensioner in Northern Ireland with a child on the highest DLA care rate; and 2015 in each nation. Each comment shows the sum from the amounts table.
- `test_council_tax_reduction_pensioner_child_disability_premium_properties.py` (new, 6 Hypothesis properties, invariants 1 to 5) builds many families in one simulation per example. Explicit examples check, on every run, children aged 3, 4 and 5 on the lower DLA mobility rate alone (`dla_m` pays that rate only from age 5), and each AFIP route for a child and a young person in England (2022, 2023), Wales (2023, 2024) and Scotland (2026).
- Without this PR's commits, all 31 YAML cases fail, because the variable doesn't exist, and the property module fails to import, because the helper doesn't exist. With only the helper copied in, 5 of the 6 properties fail; the one that reads only the helper passes. On the head with the formula returning nil, 20 cases fail; with the AFIP routes removed, 5 fail; with the child and young person routes swapped, 4 fail. With Northern Ireland given England's amounts and routes, the Northern Ireland case fails.
- Before this PR, the base merge gives the issue's model column in every case: for example 17,881.76 for England A2 and £1,233.55, £1,443.84 and £1,454.11 for A2c. After it, the model gives the issue's statutory column (24,041.16, 25,092.60 and 25,183.60 for A2) and the full £2,000 for A2c in each nation.
- Housing Benefit: `housing_benefit_child_disability_premiums.yaml` passes (62 cases). On 300 drawn benefit units in each year from 2015 to 2030 (4,800 values, 2,224 of them positive, across all four nations, with AFIP, DLA, PIP and blindness), `housing_benefit_child_disability_premiums` gives identical results before and after.
- The CTR YAML directory (416 cases) and `housing_benefit_pre_cutoff_period.yaml` (4 cases) pass.
- `test_council_tax_reduction_pensioner_children_tariff_properties.py`, `test_council_tax_reduction_child_benefit_properties.py`, `test_enhanced_disability_premium_properties.py`, `test_council_tax_reduction_applicant_properties.py` and `test_housing_benefit_pension_age_cohorts.py` pass (96 tests), and `policyengine_uk/tests/code_health` passes (3,140 tests).

## Merge notes

- This head merges into `main` (`9b456bda6`) without conflict.
- The new YAML file and properties also pass on scratch merges of this head with #2845 (`f379377f9`) and #2016 (`983488065`), which change the child flags that the variable and the differential test read. Both merge without conflict.
- #1966 (`a013f520a`) conflicts only in `severe_disability_premium_young_person.yaml`, which this PR doesn't touch; #2808's head alone conflicts there with #1966.
- #2827 (`31139e822`) changes the same two hunks of `council_tax_reduction_premiums.py`. This resolution keeps both sides. The comment reads:

  ```python
          # The working-age severe disability premium takes Council Tax
          # Reduction's own family test (council_tax_reduction_severe_disability_
          # premium) and the working-age carer premium its own caring test
          # (council_tax_reduction_carer_premium); both differ from the shared
          # premiums only in Scotland. The enhanced disability premium takes the
          # scheme's own condition
          # (council_tax_reduction_enhanced_disability_premium).
  ```

  and the working-age branch ends:

  ```python
              + (
                  benunit("council_tax_reduction_enhanced_disability_premium", period)
                  - benunit("enhanced_disability_premium", period)
              )
              + (
                  benunit("council_tax_reduction_carer_premium", period)
                  - benunit("carer_premium", period)
              ),
  ```

  On a scratch merge with that resolution, the new YAML passes (31 cases) and so does the CTR YAML directory (428 cases, 12 more than this head's 416).

## Survey data

The Aggregate impact job compares `main` with this PR merged into it, so it includes #2826 and #2808. Its Council Tax Reduction rows (spending from −£0.1m in 2025-26 to −£0.2m in 2031-32, caseload from +254 to −104) and every other changed row match #2826's own report, so on the certified data this PR's five commits move no figure the report prints.

---
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Generated by Claude Code

@MaxGhenis

Copy link
Copy Markdown
Collaborator Author

Ready for hub review

Head: 16a74f81d17cbcbcd829c5111192da0b035def4c on claude/pr-2861-review-fixes-1yga5n (pushed, no PR). It branches from 9ef585def, and its first commit, a2434433, merges main at 9b456bda6 with no conflict (tree 8f3bdeef6, as the review found). #2861's branch remains at 9ef585def. The new body is in the comment above.

Commits after the merge:

  • f00ad5be: the property module (P2-1, P2-2, P3-4)
  • 2df03f2b: the YAML file (P3-1, P3-2, P3-3, P3-6, P3-7 YAML rows)
  • 16a74f81: code comments, docstrings and parameter files (P3-5, P3-7 code and parameter rows, P3-10, P3-11)

Before starting I checked the branch: its last push was 13:58Z, more than 6 hours before 21:10Z, and no comment said anyone was mid-change. I posted the pickup comment (6615519254) before pushing.

Findings

All file:line references are at 16a74f81. P stands for policyengine_uk/tests/test_council_tax_reduction_pensioner_child_disability_premium_properties.py, and Y for .../council_tax_reduction/council_tax_reduction_pensioner_child_disability_premiums.yaml.

  • P2-1. Applied as given:

    • the review's oracle at P:204-212
    • example added to the import at P:36
    • the brief's @example with its comment at P:266-282; ruff leaves it unchanged

    With 9ef585def's oracle restored, the explicit example fails. The 3- and 4-year-olds give [0]: 0.0 (ACTUAL), 4391.92 (DESIRED) and [1]: 0.0 (ACTUAL), 4391.92 (DESIRED), and the 5-year-old matches. With the new oracle it passes.

  • P2-2. Added the ten @example lines with the review's comment, between @given(...) and the def (P:336-347). At the head, this property now kills no_afip, swap_routes and wales_dcp_afip_from_2023 (table below). It also catches nil and helper_drops_dla.

  • P2-3. I read both reports:

    I extracted every table line from "Spending by benefit and service" down to the first <details>, in each report: 59 lines each, 48 rows plus 11 header lines. They match line for line. The only differences between the reports are the provenance lines, run links and a note on suppressed reform costings. The CTR figures match the review's: −£0.1m, +£67,865, +£44,867, −£28,718, −£87,455, −£85,901 and −£0.2m; caseloads +254, +255, +255, 0, 0, 0 and −104. Count enhanced PIP daily living and AFIP for the enhanced premium #2808's report has CTR only in its head-level tables, with no change row. The body's new "Survey data" section uses the review's text.

  • P3-1. Replaced the Welsh (Y:391-394) and Scottish (Y:572-575) A2c comments with the review's text. Both parameters exist.

  • P3-2. Added the Northern Ireland case at the end of Y, giving 31 cases. It passes at the head. Under ni_gets_england it fails with council_tax_reduction_pensioner_child_disability_premiums@2026: [6159.4] differs from 0.0.

  • P3-3. Added the comment above "AFIP England 2023, a child under 16" (Y:642-644).

  • P3-4. Applied all three docstring edits (P:11-13, P:23-26, P:154).

  • P3-5. Applied (_child_disability_premiums.py:20-22).

  • P3-6. Applied (Y:32-33).

  • P3-7. Every row applied:

    • Y:5-14, Y:36, Y:671-672 and Y:759-760
    • council_tax_reduction_pensioner_child_disability_premiums.py:23-24 and :71-73
    • housing_benefit_child_disability_premiums.py:43
    • the body's young-person bullet
    • lines 3-4 of all six amount files

    I left child_or_young_person.yaml alone, as it belongs to Add pensioner CTR child amounts and uncap Scotland's tariff income #2826. I checked the YAML 6-13 comments against law-amending-instruments.txt:

    • SI 2023/16: the Secretary of State made it (preamble). Reg 1(3) gives "financial years beginning on or after 1st April 2023". Reg 7(7)(c) inserts para 7(1)(c), and reg 7(8) inserts para 8(e), "is a young person who is in receipt of an AFIP".
    • WSI 2024/56: the Welsh Ministers made it. Reg 1(3) gives "on or after 1 April 2024", and reg 5(d) inserts para 8(d).
    • SSI 2013/142: the Scottish Ministers made it. Reg 12(7)(c)-(d) inserts paras 8(1)(aa) and 9(ba), both for a young person.

    The comments quote nothing beyond these.

  • P3-8. Rewritten in the body, with 31 for 30, since the NI case also fails without the variable. At the head's test files on 5acffdbd8:

    • the YAML gives 31 failed;
    • the property module fails to import, with ModuleNotFoundError: ... _child_disability_premiums;
    • with the helper copied in, the properties give 5 failed, 1 passed, and the one that passes is test_shared_enhanced_condition_implies_disabled_child_condition.
  • P3-9. Both lines applied. The merge line now sits in a new "Merge notes" section.

  • P3-10. Applied (council_tax_reduction_premiums.py:17-20).

  • P3-11. Applied in both England amount files (line 76).

  • P3-12. Count UC carer awards for severe disability and Scottish CTR premiums #2827's head is now 31139e822 (the API reports branch claude/uc-carer-awards-nits-1pezj2, not the one the brief names). git merge-tree --write-tree --name-only 16a74f81 31139e822 exits 1 and conflicts only in council_tax_reduction_premiums.py, in the same two hunks. On a scratch merge I committed the review's resolution, which ruff leaves as it is. On that merge the new YAML passes (31) and so does the CTR YAML directory (428, against the head's 416). The body's merge notes carry the resolution.

  • P3-13. Left for the hub, as the brief says.

Tests at the head (clean runs, uv sync --frozen --extra dev)

Run Result
new YAML file 31 passed
CTR YAML directory 416 passed
housing_benefit_pre_cutoff_period.yaml 4 passed
new property file, -n 4 6 passed (266.77 s)
the five property files the body names, -n 4 96 passed
policyengine_uk/tests/code_health -n 4 3,140 passed (the review had 3,135, at 9ef585def without the main merge)
.github/check_fix_pr.py Fix evidence: PASS, 16 changed executable tests, exit 0
ruff format --check ., ruff check ., --select F811,F821, git diff --check 9ef585def..HEAD all clean

I ran check_fix_pr.py on the live title, the new body and no labels. Its --changes-file came from git diff --name-status --no-renames -z between merge-base 9b456bda6 (the current main) and the head.

Mutations

I ran each on a scratch worktree of the head, with shrinking off: a local profile with the explicit, reuse and generate phases. The control run gives 31 YAML passes and 6 property passes.

Mutation New YAML (31) Properties (6)
nil 20 fail 3 fail: family total, AFIP exception, differential
no_afip 5 fail 2 fail: family total, AFIP exception
swap_routes 4 fail 2 fail: family total, AFIP exception
ni_gets_england 1 fails: the NI case 0
no_head_alone_gate 1 fails 1 fails: nil property
enhanced_any_care_rate 3 fail; HB YAML 4 of 62 fail 1 fails: family total
wales_dcp_afip_from_2023 1 fails 1 fails: AFIP exception (survived the properties before P2-2)
not_in_premiums 15 fail 0
young_person_any_16_plus 0 0: survives, an equivalent mutant
helper_drops_dla 13 fail (the review's 12 plus the NI case, whose HB output reads the helper) 3 fail: family total, helper implication, AFIP exception

Merges (git merge-tree --write-tree --name-only of the head)

No head moved during the run, except #2827's, which had already moved to 31139e822 when I started.

With Result
origin/main 9b456bda6 clean (already merged)
#2827 31139e822 conflict in council_tax_reduction_premiums.py (P3-12)
#2845 f379377f9 clean. On the scratch merge: new YAML 31 passed, properties 6 passed
#2016 983488065 clean. On the scratch merge: new YAML 31 passed, properties 6 passed
#1966 a013f520a conflict only in severe_disability_premium_young_person.yaml

Skipped, and judgement calls

  • I ran no survey-data test, having no dataset access. P2-3 rests on the two CI reports.
  • I didn't rerun the 300-unit Housing Benefit differential that the body cites, and that sentence is unchanged.
  • I added "Merge notes" and "Survey data" sections to the body. I also extended the commit list with the four new commits, and described the new explicit examples in the Tests section.
  • In the "Survey data" text I kept the review's "this PR's five commits". It refers to the five model commits, and the commits since add only tests and text.
  • The head-alone case name in Y still says "her", and so does the council_tax_reduction_premiums documentation inherited from the base. Neither is in the review, so I left them.

Generated by Claude Code

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed captured head 9ef585defd64daa7fb592b26af631c058c1be497, scoped to the five introduced commits after declared stack merge 5acffdbd82cb839c7d6246abd6b871d68ceb871f and their affected dependencies. COMPLETE — no critical findings or material evidence gaps; A1 and S1 remain open.

A1 — Correct the family-total test oracle below the DLA mobility minimum age. In test_council_tax_reduction_pensioner_child_disability_premium_properties.py, the lower-DLA-mobility entry in AWARDS is treated as qualifying across the drawn ages 0–15. child_premiums predicts a disabled-child premium for a three- or four-year-old with that category alone, while the actual DLA mobility reader requires age 5 and pays zero. The 2026 oracle therefore predicts £4,391.92 where the receipt-based premium should be zero. Correct the age/payability oracle or its generated domain. The 191 passing seeded checks did not cover this combination; they do not refute the static counterexample. This is a test-reference defect, not a demonstrated new wrong-cash result.

S1 — Use the appropriate national sources in the test comments. The Welsh and Scottish A2c comments cite the English provisions. Cite the corresponding Welsh and Scottish rules. The amounts and core statutory conditions were independently corroborated.

Late author feedback and the proposed 16a74f… candidate were assessed for relevance to this captured head. That candidate and proposed description remain unadopted and were not reviewed as the PR head. Other named coverage/editorial/prospective-merge items are qualified in the report rather than promoted to additional defects.

All 191 focused checks and three native final-accounting cases passed; all 82 independent official rate/parameter comparisons matched. The final cases trace the new premiums through CTR, council-tax benefit, household/HBAI income and spending once, with HB, tax and DLA unchanged. Existing parent/local working-age gaps remain outside this new national pensioner scope; no isolated survey score or prospective combined merge is certified.

Current-head CI is green. Approval is withheld for the findings, draft status and the stated #2826/#2808 parent-first hold. The workflow time targets were exceeded; original elapsed time is preserved and current head, body, feedback, source evidence, parent status and CI are guarded again before publication.

The Welsh and Scottish A2c cases now cite the provisions that give a
pensioner whose income does not exceed the applicable amount the whole
council tax: WSI 2013/3029 reg 22(e) and Sch 1 paras 2(1) and 4(2), and
SSI 2012/319 regs 14(5)(a)(ii) and (8)(a) and 47(1). A case name drops a
pronoun. Comments and one case name only.

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

Copy link
Copy Markdown
Collaborator Author

Thanks, juaristi22. We moved the branch to 6e96ffef8, which answers both findings in your review at 9ef585def.

  • A1. The family-total oracle now gives no disabled child premium to a child under 5 whose only award is the lower DLA mobility rate. dla_m pays that rate only from age 5 (gov.dwp.dla.mobility.lower_min_age). An explicit example checks children aged 3, 4 and 5 on every run. With the old oracle restored, the 3- and 4-year-olds fail (£4,391.92 expected, £0 from the model) and the 5-year-old passes.
  • S1. The Welsh A2c case now cites WSI 2013/3029 reg 22(e) and Sch 1 paras 2(1) and 4(2). The Scottish one cites SSI 2012/319 regs 14(5)(a)(ii) and (8)(a) and 47(1). Each also names the nation's maximum_support_rate parameter.

The head also takes up the nits in the review comment of 3 November:

  • explicit examples for each AFIP route, which catch a mutant that starts the Welsh AFIP route to the disabled child premium a year early;
  • a Northern Ireland nil case, so the YAML file has 31 cases;
  • comments, docstrings and parameter notes that name who acts;
  • a merge of main at 9b456bda6.

The body's new "Merge notes" section gives the resolution for #2827. Its "Survey data" section shows that the Aggregate impact report's CTR rows match #2826's own. We also corrected the record, TheAxiomFoundation/rulespec-uk#533: it restores the England amounts' sub-paragraph numbers and quotes the Welsh and Scottish amending regulations. This PR still lands after #2826 and #2808.

@MaxGhenis
MaxGhenis requested a review from juaristi22 November 3, 2026 23:51

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed current head 6e96ffef8246550731553561623e97d8a3bdd258. PARTIAL — A1 and S1’s original wrong-nation citation defect resolved; one description finding and one narrow source check remain. No confirmed payment defect.

The family-total oracle now respects the lower DLA mobility minimum age, with the explicit ages3/4/5 example. 51 focused tests and three-country final CTR/net-income checks passed on the matched current runtime. The additional AFIP examples and Northern Ireland nil case are adopted.

A2 — Qualify the own-commit survey-data inference. The published CTR rows match, but this PR’s report compares 1d4d020aa1→1461ec9bdb, while #2826’s report compares 46a60678ff→2d90bcc1c8. Matching rounded/suppressed rows from different stacked comparisons do not isolate this component’s causal effect. State the observed equality and comparison identities; qualify the sentence that this PR’s own commits move no printed figure unless an isolated comparison exists. This does not allege that the effect is nonzero.

G1 — Scottish citation verification remains incomplete. The new national references replace the English ones. The Welsh provisions, Scottish regulation47(1), both maximum-support parameters and the unchanged actual #533 contract were checked. I could not independently retrieve Scottish regulation14, specifically (5)(a)(ii) and (8)(a), after bounded current/dated source attempts and a retained-cache check. Their accuracy remains unverified; this is not a finding that they are wrong. An accessible official extract would close that narrow check.

The draft status, pending CI and stated #2826/#2808 merge-first requirements remain. Earlier191 passing tests are retained with their original runtime qualifications; no private population run or prospective merge is certified.

claude and others added 5 commits November 4, 2026 13:06
Resolve the three conflicts to main's side where both add tariff income:
council_tax_reduction_applicable_income adds main's
council_tax_reduction_tariff_income, the £16,000 pension credit case reads
its outputs, and invariant 4 states main's tariff recomputation. The
property file's recomputation adds tariff income once, through main's
expected_tariff_income. The docstring keeps main's text with this branch's
active wording of the war pensions sentence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6HDAHLr6RSvBAdeFM1
Delete council_tax_reduction_pensioner_tariff_income, which the merge left
unused, and point the pensioner tariff YAML and property tests at
council_tax_reduction_tariff_income. That variable also carries the Welsh
and Scottish working-age tariffs, so tariff Case 14 (a Welsh earner aged 40
with 12,000 of capital) now expects 1,248 (24 * 52 under WSI 2013/3029 Sch
6 para 33), the property test checks nil tariff income at working age only
in England, and the frozen differential now holds main's values at
9dd44e1, which add those working-age tariffs in Wales and Scotland.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6HDAHLr6RSvBAdeFM1
SSI 2012/319 reg 27(2) treats capital as yielding £1 a week for each £500,
or part, over £10,000 with no ceiling; reg 40 separately bars a reduction
above £16,000. council_tax_reduction_tariff_income now leaves the Scottish
pensioner branch uncapped and keeps the £16,000 ceiling in England and Wales.
No award moves: a Scottish pensioner with £16,500 or £20,000 of capital still
gets no reduction. A new income_from_capital.yaml case checks a Scottish
pensioner's 1,040 and an English one's 624 at £20,000, and the pension
credit property test's tariff recomputation follows reg 27(2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6HDAHLr6RSvBAdeFM1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LwQq6HDAHLr6RSvBAdeFM1
The tariff property test now asserts invariant 4 of #2826's description:
councils give no award where capital exceeds £16,000 (SI 2012/2885 reg
11(2); WSI 2013/3029 reg 30; SSI 2012/319 reg 40), so Scotland's uncapped
pensioner tariff changes no award.

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

Copy link
Copy Markdown
Collaborator Author

Thanks for the re-review.

The survey-data paragraph now names each comparison (A2). This PR's report, from the run at 6e96ffef8, compares main at 9b456bda65 with this PR merged into it (9b7d5da44e). #2826's report compares main at 46a60678ff with #2826 at 06e51a8a merged into it (2d90bcc1c8). Apart from the run details, the two print the same figures, and the paragraph now says the match doesn't isolate what this PR's own commits change.

We fetched SSI 2012/319 reg 14 from legislation.gov.uk for G1: its current text and its text as in force on 30 April 2026 match (current, 30 April 2026). Paragraphs (5)(a)(ii) and (8)(a) read:

(5) The condition referred to in paragraph (1)(a) is that—
(a) the day falls within a week in respect of which—
…
(ii) the relevant person's income does not exceed the applicable amount; or

(8) Subject to paragraph (9) below, where a relevant person is entitled to council tax reduction in respect of a day, the amount to which the person is entitled is—
(a) if paragraph (5)(a) applies, the amount which is the appropriate maximum council tax reduction in that person's case;

In Case A2c, the pensioner's income of £21,753.67 doesn't exceed the applicable amount of £25,183.60. So (5)(a)(ii) applies, and under (8)(a) the council awards the appropriate maximum council tax reduction, the whole £2,000.

Could you take another look?

@MaxGhenis
MaxGhenis requested a review from juaristi22 November 4, 2026 15:01

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed unchanged head 6e96ffef8246550731553561623e97d8a3bdd258 and the new reply. COMPLETE — all findings resolved and no material evidence gaps.

A2 resolved. The description now names each Aggregate comparison and correctly says their matching printed figures do not isolate this PR’s own commits. The current child report compares 9b456bda65→9b7d5da44e; the parent report compares 46a60678ff→2d90bcc1c8.

G1 resolved. I independently retrieved and checked the official current Scottish regulation 14 XML and its 30 April 2026 text. Their operative text matches: paragraphs (5)(a)(ii) and (8)(a) support the maximum reduction where the income condition and other entitlement conditions apply. Together with the previously verified regulation 47(1), this closes the narrow citation check for Case A2c’s £2,000 result. A1 and S1 remain resolved.

The prior 51 passing focused tests and three final CTR/net-income checks are retained at this identical head; no tests, calculations or private population analysis were repeated.

Approval remains withheld because this is a draft and the stated #2826/#2808 merge-first requirements remain. The child still contains #2826 at 06e51a8a, so this review does not certify integration of its subsequent 87cbc397 changes. Parent approval does not establish that integration.

MaxGhenis and others added 2 commits November 4, 2026 13:05
#2826 moved from 06e51a8 to 87cbc39. The merge has no conflicts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The merge has no conflicts.

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

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed adopted head 254fac3c2e68ef9da952f8c59a13fc5b35cb8be7 after the #2826 and main merges. PARTIAL — prior findings remain resolved, and no new defect is confirmed; final validation is incomplete.

62 focused checks passed, including all 31 child-premium YAML cases, all 17 parent tariff YAML cases and the nine Pension Credit properties. The serial campaign reached its 420-second limit with no failed or skipped test outcomes.

Three checks remain: the unchanged-household comparison for 2024 (unfinished), its 2026 counterpart (not run), and the prepared three-country check through final CTR and household net income (not run). These are explicit evidence gaps; the earlier head’s results are not presented as current-head validation. The next round will run only these remaining checks.

The source review remains complete, including the earlier Scottish citation check. This head now contains #2826 at 87cbc397; both stated parent merge-first requirements remain open, and the PR remains a draft. Approval is withheld.

@juaristi22 juaristi22 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completed the remaining validation at unchanged head 254fac3c2e68ef9da952f8c59a13fc5b35cb8be7. COMPLETE — prior findings remain resolved; no findings or material evidence gaps.

The two unfinished year comparisons and the three-country final CTR/household-income diagnostic all passed. With the 62 earlier passing outcomes retained, all 65 selected checks are now accounted for across the two runs; this round ran only the three remaining checks. The final diagnostic confirms that the £624 tariff lowers CTR and household income by £124.80 once, alongside the child-premium effects.

The source review remains complete. Approval is withheld while the PR is a draft and the stated parent/CI requirements remain unmet; those live conditions will be checked again before any approval.

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.

Pension-age Council Tax Reduction omits the disabled child and enhanced disability premiums

3 participants