Skip to content

Assess each Council Tax Reduction claim under its own family's scheme and exemption - #2015

Open
MaxGhenis wants to merge 6 commits into
ctr-claimant-household-headfrom
ctr-per-family-scheme
Open

MaxGhenis wants to merge 6 commits into
ctr-claimant-household-headfrom
ctr-per-family-scheme

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #2009 (ctr-claimant-household-head, at 4b84ea069), which is stacked on #2006 and #1896. Merge after #2009; this PR retargets to main then.

The bug

Since #2006 and #2009, a household whose rent is shared has several Council Tax Reduction claimants: the household head's family, and each family liable for a share of the rent. Each claims on its own share of the council tax. Two things were still decided once per household, from the head's family:

  • Which scheme. council_tax_reduction_household_has_pensioner ("any member of the head's family is State Pension age") chose between England's pensioner scheme and the council's working-age scheme.
    • It did so in simulated_council_tax_reduction_benunit, in Merton, Kingston upon Thames, Newham, Westminster and Oxford, and in council_tax_reduction_scheme_supported.
    • A working-age sharer went on the pensioner scheme when the head's family was pension-age. A pension-age sharer went on the working-age scheme in the reverse case.
  • Whose exemption. council_tax_reduction_household_has_non_dep_exemption exempted every claimant from non-dependant deductions in the councils' schemes when the head or the head's partner was blind or had a qualifying disability benefit. It ignored a sharer's own disability.

Reproduction: claimant_family_scheme.yaml. Each case is 2026, with two jointly liable families each claiming half of £1,800, no UC and no capital.

Case Base: per family; household This PR: per family; household
Oxford: head 70, sharer 40 with £500 a week £900, £0; £900 £900, £675 (Oxford's 75% band); £1,575
Oxford: head 40 with £500 a week, sharer 70 with £15,000 a year £675, £900 (Oxford's bands); £1,575 £675, £562.40 (pensioner scheme); £1,237.40
Merton: head 70, sharer 40, non-dependant son earning £577 a week £0, £0. Both are on the pensioner scheme, whose national-scale deduction for the son exceeds each award; £0 £0 (unchanged), £554.20 (Merton's scheme, less half of the son's £13.30 a week); £554.20
Maidstone (unmodelled): head 70, sharer 40 reporting £300 £900, £900 (both simulated as pensioners); £1,800 £900, £300 (the sharer keeps its report); £1,200
Maidstone: head 40 reporting £300, sharer 70 £300, £0 (the sharer's pensioner claim is ignored); £300 £300, £900; £1,200
Newham: the head has PIP daily living; sharer and son as above £630, £630 (the head's PIP exempts the sharer); £1,260 £630, £42.14 (the sharer bears half of the son's £22.61 a week); £672.14
Newham: the sharer has PIP daily living £42.14, £42.14 (the sharer's own PIP is ignored); £84.28 £42.14, £630; £672.14

Wales and Scotland each have one scheme in the model on this base, and each family's applicable amount was already its own, so those cases do not change.

The law

Read on legislation.gov.uk on 2026-10-01 (revised text):

  • "Pensioner" is per person and partner.

    • England: SI 2012/2885 reg 3(1) and SI 2012/2886 Sch para 3(2). A person is a pensioner if "he has attained the qualifying age for state pension credit" and neither he nor, "if he has a partner, his partner" is on IS, income-based JSA, income-related ESA or UC.
    • Wales: SI 2013/3029 reg 3(1) is the same. Classes A-B (regs 22-23) and Schedules 1-5 are for pensioners; classes C-D (regs 24-25) and Schedules 6-10 are for persons who are not.
    • Scotland: SSI 2021/249 reg 3(1) applies to "a person who ... has not attained pensionable age", or who has but is on a qualifying income-related benefit or UC. SSI 2012/319 reg 12(1) applies to "a person who has attained the qualifying age for state pension credit".
  • Jointly liable people apply separately. Two or more residents can be jointly and severally liable (LGFA 1992 s.6(3), s.75(3)). Each is then in a class in their own right, defined by their own pensioner status (SI 2012/2885 reg 11 and Sch 1 para 1; SI 2013/3029 regs 22-25).

  • The non-dependant exemption is the applicant's. "No deduction is to be made in respect of any non-dependants occupying an applicant's dwelling if the applicant or his partner is" blind, or receives in respect of himself Attendance Allowance, the DLA care component, the PIP daily living component, AFIP, or the Scottish and ADP equivalents:

    It does not exempt another applicant in the same dwelling.

Changes

  • is_council_tax_reduction_applicant_or_partner (Person) and council_tax_reduction_head_applies_alone (BenUnit), taken byte for byte from Means-test the Council Tax Reduction applicant and partner, not the benefit unit's claimant #2078, which is also stacked on Give Council Tax Reduction to the household head's family, not the oldest adult's #2009 and needs the same people for the means test. They identify the people whose circumstances set a claim's scheme and exemption.
    • Where the family's liable person (Give Council Tax Reduction to the household head's family, not the oldest adult's #2009's council_tax_reduction_liable_person) is its claimant or partner, these are the claimant and partner, whatever their ages.
    • Where the liable person is a household head who is not the family's claimant or partner, the head applies alone. An example is a grandparent heading a family formed around a couple of 17-year-old parents.
    • In a family that cannot claim, these are its claimant and partner.
  • council_tax_reduction_pensioner (new, BenUnit) replaces council_tax_reduction_household_has_pensioner: the applicant or partner has reached State Pension age.
  • council_tax_reduction_applicant_has_non_dep_exemption (new, BenUnit) replaces council_tax_reduction_household_has_non_dep_exemption. The conditions are unchanged; it reads the applicant and partner.
  • Scheme selection per family. The national scheme (simulated_council_tax_reduction_benunit), the four _legacy councils and Oxford take each claim's own pensioner flag.
  • council_tax_reduction_scheme_supported is now BenUnit.
  • council_tax_benefit reconciles simulated and reported reductions within a household. Now that schemes are per family, one household can hold a simulated claim beside a family whose scheme is not simulated.
    • A claiming family gets the simulated reduction where its own scheme is simulated, and its reported reduction otherwise.
    • A jointly liable claimant's reported reduction is limited to its own share of the council tax (Sch 1 para 7(3)-(4)), the most any scheme could give it.
    • A family that cannot claim keeps a reported reduction only where no claim in its household is simulated. This uses the new Household flag council_tax_reduction_household_has_simulated_claim; one bill needs a household-level reconciliation. In households without sharers this is exactly the base behaviour.
  • Councils' non-dependant deductions.
    • The person-level amounts (*_council_tax_reduction_individual_non_dep_deduction) depend only on the non-dependant's own family and the council area. A pension-age head's family no longer zeroes them.
    • local_non_dep_deductions applies each applicant's own exemption. normal_gross_income_non_dep_deduction no longer takes the claimant's exemption.
  • config.py gains is_*_area(local_authority, country) for each modelled council; is_*_working_age is built on it.
  • Existing tests that read the household flags now read the per-family ones. A changelog fragment.

National schemes and the exemption

On this base, the national schemes (England pensioners, Wales, Scotland) apply no applicant exemption at all; only the councils' schemes do. #2007 adds it to the national schemes, reading council_tax_reduction_household_has_non_dep_exemption. It also reads council_tax_reduction_household_has_pensioner in three places:

  • council_tax_reduction_individual_non_dep_deduction, to pick England's national scale;
  • council_tax_reduction_non_dep_deduction_exempt, to pick England's UC limb;
  • council_tax_reduction_non_dep_deductions, for when Wales deducts both members of a non-dependant couple on UC (WSI 2013/3029 Sch 6 para 5(3)).

Whichever of #2007 and this stack lands second should:

  1. Read the applicant's own council_tax_reduction_applicant_has_non_dep_exemption for applicant_exempt.
  2. Base Wales's both-members rule on the applicant's scheme, not the non-dependant's.
  3. In both person-level variables (council_tax_reduction_individual_non_dep_deduction and council_tax_reduction_non_dep_deduction_exempt), select England's pensioner parameters by country only, as this PR does for the councils. Each claim's own scheme already decides whether its award uses them. Apply Housing Benefit and national Council Tax Reduction non-dependant deductions as legislated #2007's two tests that pin "no national deduction in English working-age households" should instead check that the working-age award is unaffected.

The national exemption is not added here, so the two PRs do not both claim that change.

Invariants (property-tested)

policyengine_uk/tests/test_council_tax_reduction_claimant_family_scheme_properties.py uses Hypothesis.

  • The generated populations have up to 6 households. Each has a flagged head's family, up to two sharer families and at most one non-dependant.
  • All eight scheme types appear (Maidstone, the five councils, Edinburgh and Cardiff). Ages straddle State Pension age, disability inputs cover all five exempting conditions, and families carry random reported reductions.
  • The tests are derandomized, with 20 examples each.
  1. Own members. A family is a pensioner exactly when its applicant or partner is over State Pension age. It is exempt exactly when its applicant or partner is blind or gets AA, DLA care, PIP daily living or AFIP. This is a differential check against a direct computation from the person-level inputs.
  2. As if alone. Each family's pensioner flag, exemption and simulated-scheme flag are what they would be if it lived alone.
  3. Scheme. A family's scheme is simulated exactly when it is in Scotland or Wales, is a pensioner, or is in a modelled council. In England, only pensioner families are paid by the national scheme, and only working-age families by a council's.
  4. Others do not matter. Replace the ages and disability benefits of every other claiming family. A family's flags, its councils' awards, its joint-liability share, its simulated award and its council_tax_benefit (reported reductions included) stay unchanged.
  5. Fallback. council_tax_benefit is exactly the rule above, for every family.
  6. Bounds. A family that cannot claim gets no simulated reduction. A household with a simulated claim never gets more than its council tax.
  7. The exemption is the applicant's own. The test puts a working-age head and a sharer under each modelled council, with a non-dependant in remunerative work, so both claims bear a deduction.
    • Giving one claimant an exempting benefit removes that claimant's deductions.
    • It leaves the other claim's exemption, deductions, council award and council_tax_benefit unchanged.

On the base (4b84ea069), run without the new flags, properties 4 and 7 both fail. In property 4, a claiming family's council award moved when the other families changed. In property 7, one claimant's exempting benefit changed the other claim's deductions, and a claimant's own benefit did not remove its own. The hand-minimized forms are the Oxford, Merton and Newham YAML cases.

Tests

  • YAML. claimant_family_scheme.yaml has 16 cases:

    • Oxford, both ways round;
    • Merton, with a non-dependant of both claimants;
    • Maidstone, both ways round, with reported CTR;
    • a family that cannot claim beside a simulated claim (the review's £3,000-against-£1,800 case);
    • a household where no claim is simulated;
    • a jointly liable claimant's report capped at its share;
    • Newham, with the exemption on each side;
    • Wales and Scotland, both ways round;
    • a grandparent head who applies as a pensioner although her family's claimant and partner are 17-year-old parents;
    • a 17-year-old partner whose PIP still exempts the applicant.

    On the base (4b84ea069), with the branch-only variables removed from the expected outputs, the 7 Oxford, Merton, Maidstone and Newham scheme and exemption cases fail. The other 9 pass, as they should:

  • Updated. claimant_household_head.yaml (2 cases) and legacy_claimant_non_dep_exemption.yaml (4 cases) read the per-family flags.

  • Run locally on the head:

    The full suites ran clean on the first version (ae3e5e0ea): YAML 1,523 passed, pytest 2,047 passed and 45 skipped. On this head they run in CI.

  • CI. CI does not run on PRs whose base is not main, so the "Code changes" workflow is dispatched on this branch: run 37019227983 on 9efdea22d (running).

Enhanced FRS impact

These are real Microsimulation runs of base 4b84ea069 (#2009's head) against branch 7ac22effc on the same dataset, six runs in all. 9efdea22d only replaces the applicant variable with #2078's identical one.

  • Aggregates only.
  • A cell behind fewer than 10 survey households is suppressed, and so is any cell from which it could be recovered by subtraction, including the branch's total.
  • Survey households are counted by a (region, sorted ages) fingerprint, which merges the enhanced FRS's clones with their sources.
Production enhanced FRS 2024-25 (e433e532…), 2026-27 #2006's companion build (efrs_payer.h5, ed1a29912656…), 2025-26 and 2026-27
CTR, base £2.3610bn £2.1315bn, £2.1822bn
Change none, in any family suppressed in both years: it rests on fewer than 10 survey households
Families that cannot claim no change no change
Wales, Scotland, Northern Ireland no change no change
Households with a simulated claim whose CTR exceeds the council tax none none, on base or branch
People entering or leaving poverty (BHC, AHC) none none

What the runs show:

  • No sharers, no change. The production file has no sharer families, and households without sharers behave exactly as on the base.
  • The payer build's remaining change is the share cap alone. Every changed family is a jointly liable claimant whose reported CTR exceeded its share of the council tax. Every change is a decrease, and no family's scheme switches.
  • Sharers on a different scheme from the head's family. Fewer than 10 survey households have one, and their CTR does not change.
  • Sharers whose exemption differs from the head's. 6k families (11 survey households). Their CTR does not change either: no household in either file is assigned to the five councils, and the national schemes apply no exemption on this base.

The first version of this PR measured −£4.8m on the payer build. The review traced all of it to the per-family fallback for families that cannot claim. That version kept their reported CTR beside a simulated claim that already covered the bill, and dropped it where the base kept it. The reconciliation above removes both effects.

Not caused by this PR. On the base, about 516k households (215 survey households) in the payer build already receive more CTR than their modelled council tax, because their reported CTR exceeds the dataset's council tax. None of them has a simulated claim; this PR leaves them as they are. A follow-up task has been queued to find the cause.

Review

Subfleet review r1 of ae3e5e0ea returned REQUEST_CHANGES:

  1. Blocking: reported reductions added on top of a simulated claim. Fixed by the reconciliation in council_tax_benefit, with the three YAML cases and properties 5-6.
  2. Complementary suppression was incomplete. compare.py now withholds the branch value of any total whose change is suppressed, and the over-the-bill counts are reported as changes. The published figures above are a single non-overlapping set.
  3. Two mechanism claims were wrong. A simulated sharer gets its simulated award, not its report; the take-up explanation above is corrected. Non-claimant fallback is described as its own policy choice, separate from Give Council Tax Reduction to the household head's family, not the oldest adult's #2009's claimant rule.
  4. Exemption independence was weakly exercised. Fixed by property 7, which fails on the base.
  5. The Apply Housing Benefit and national Council Tax Reduction non-dependant deductions as legislated #2007 notes missed council_tax_reduction_non_dep_deduction_exempt. Added above.

The legal reading (scheme and exemption per applicant and partner) was confirmed. Review r2 of this head is running; its verdict will be added here.

Coordination with other open PRs

axiom: TheAxiomFoundation/rulespec-uk#410 queued

🤖 Generated with Claude Code

… and exemption

In a shared-rent household every family liable for the rent claims, but the
pensioner scheme and the non-dependant exemption were picked once per
household from the head's family. SI 2012/2885 reg 3 (and SI 2012/2886 Sch
para 3, SI 2013/3029 reg 3, SSI 2021/249 reg 3, SSI 2012/319 reg 12) define
"pensioner" per person and partner, and the exemption applies where "the
applicant or his partner" is blind or gets a listed benefit (SI 2012/2885 Sch 1
para 8(6) and equivalents).

- council_tax_reduction_pensioner (BenUnit) replaces the household flag; the
  name and entity match #1944 and #1966, which extend the same definition.
- council_tax_reduction_applicant_has_non_dep_exemption (BenUnit) replaces
  the household exemption; the councils' schemes apply it per claim.
- council_tax_reduction_scheme_supported is per family, so each family falls
  back to its reported reduction only where its own scheme is unmodelled.
- Councils' person-level non-dependant deductions no longer depend on the
  head's family; each claimant's own scheme decides whether to use them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 2, 2026
SI 2012/2885 Sch 1 para 8(6) exempts "an applicant's dwelling if the
applicant or his partner is" blind or on one of the listed benefits. With
jointly liable sharers each family is its own applicant, but the composed
aggregator read the household-level exemption, which looks only at the
oldest adult's family. A blind head therefore exempted a sighted sharer's
claim, and a blind sharer exempted nothing.

council_tax_reduction_applicant_has_non_dep_exemption is the benefit-unit
exemption over is_claimant_or_partner, with the same name and formula as
#2015's, which applies it to the local schemes. The national aggregator now
uses it; the local schemes keep the household variable here.

YAML: a blind head does not exempt a jointly liable sharer, a blind sharer is
exempt while the head is not, and a blind sharer's own adult son costs no one
a deduction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 2, 2026 08:08
With the scheme chosen per family, one household can hold a simulated claim
and a family whose scheme is not simulated. Review r1 found that a family
that cannot claim then kept its reported reduction beside a head whose
simulated award already covered the whole bill: £3,000 against £1,800.

- A family that cannot claim keeps a reported reduction only where no claim
  in its household is simulated (new household flag
  council_tax_reduction_household_has_simulated_claim). Without sharers this
  is the base behaviour.
- A jointly liable claimant's reported reduction is limited to its own share
  of the council tax (SI 2012/2885 Sch 1 para 7(3)-(4)), the most any scheme
  could give it.

Tests: three YAML cases; the property tests now generate reported
reductions, check the fallback and the household bound, and toggle one
claimant's exempting benefit to show it leaves the other claim unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#2009 now names the liable people directly. A household head can be liable
without being the claimant or partner of their family (a grandparent heading
a family formed around a young couple), so "the applicant or his partner"
(SI 2012/2885 reg 3, Sch 1 para 8(6)) is not always the family's claimant and
partner. New person-level council_tax_reduction_applicant_or_partner: the
liable member, and the other member of the couple where the liable member is
the claimant or partner, whatever the partner's age; in a family that cannot
claim, its claimant and partner. The pensioner flag and the applicant
exemption read it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#2078 (also stacked on #2009) adds
is_council_tax_reduction_applicant_or_partner and
council_tax_reduction_head_applies_alone for the CTR means test. They define
the same people as this PR's council_tax_reduction_applicant_or_partner: the
claimant and partner where the liable person is one of them, the liable head
alone otherwise, and the claimant and partner in a family that cannot claim.
Take #2078's two files byte for byte, so whichever PR lands second merges
without conflict, and point the pensioner flag and the applicant exemption
at it.

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

Copy link
Copy Markdown
Collaborator Author

Coordination note from #2062 (issue #2059), also stacked on #2009.

This PR's council_tax_reduction_head_applies_alone and is_council_tax_reduction_applicant_or_partner read council_tax_reduction_household_head. #2062 removes that variable and adds is_resolved_household_head, with the same formula (the eldest flagged member, else the eldest member; exactly one per household), which every programme now reads.

Whichever of the two PRs lands second renames those reads to is_resolved_household_head and changes nothing else. #2078 adds the same two files and has agreed the same with #2062. A missed read fails as VariableNotFound, so it cannot pass CI. #2062's landing job does the rename if this PR lands first.

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.

1 participant