From 05c891b8caf2566d34aed0f8f2993e989d53d7dd Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 25 Aug 2026 23:55:43 +0200 Subject: [PATCH 1/8] Evaluate claims_all_entitled_benefits per benefit unit The formula summed its seven reported-benefit columns across the whole simulation (.sum() < 1), so in microdata the flag was False for every benefit unit whenever any benefit unit reported any of them, and would_claim_council_tax_reduction collapsed to FRS reporters only. Housing benefit, income support and the tax credits are unaffected: their own already-claiming eligibility gates carry the reporters-only behaviour independently of this flag. Refs PolicyEngine/policyengine-uk-data#448. Co-Authored-By: Claude Fable 5 --- changelog.d/claims-all-per-benunit.fixed.md | 1 + .../test_claims_all_entitled_benefits.py | 117 ++++++++++++++++++ .../income/claims_all_entitled_benefits.py | 14 ++- 3 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 changelog.d/claims-all-per-benunit.fixed.md create mode 100644 policyengine_uk/tests/test_claims_all_entitled_benefits.py diff --git a/changelog.d/claims-all-per-benunit.fixed.md b/changelog.d/claims-all-per-benunit.fixed.md new file mode 100644 index 0000000000..d85d6b45dc --- /dev/null +++ b/changelog.d/claims-all-per-benunit.fixed.md @@ -0,0 +1 @@ +- Evaluate `claims_all_entitled_benefits` per benefit unit instead of summing reported benefits across the whole simulation. The old array-wide sum made the flag False for every benefit unit in microdata whenever any benefit unit reported one of its seven benefits, restricting simulated Council Tax Reduction to FRS reporters. diff --git a/policyengine_uk/tests/test_claims_all_entitled_benefits.py b/policyengine_uk/tests/test_claims_all_entitled_benefits.py new file mode 100644 index 0000000000..933251462e --- /dev/null +++ b/policyengine_uk/tests/test_claims_all_entitled_benefits.py @@ -0,0 +1,117 @@ +"""Regression tests for `claims_all_entitled_benefits`. + +The flag is a benefit-unit attribute: a family that reports none of the seven +means-tested benefits the formula checks is assumed to claim everything it is +entitled to, and a family that reports any of them is assumed to have reported +completely. The formula used to sum the seven reported columns over the whole +simulation (`add(...).sum() < 1`), so in microdata it was False for every +benefit unit as soon as any benefit unit reported any of them, and the +consumers that gate on it (`would_claim_council_tax_reduction` above all) +collapsed to FRS reporters only. +""" + +import numpy as np +import pytest + +from policyengine_uk import Microsimulation, Simulation + +YEAR = 2025 + +SEVEN_REPORTED = [ + "child_tax_credit_reported", + "working_tax_credit_reported", + "universal_credit_reported", + "housing_benefit_reported", + "jsa_income_reported", + "income_support_reported", + "esa_income_reported", +] + + +def person(reported_uc=0, reported_ctr=0): + return { + "age": {YEAR: 40}, + "universal_credit_reported": {YEAR: reported_uc}, + "council_tax_benefit_reported": {YEAR: reported_ctr}, + } + + +def separate_households(reported_uc_a, reported_uc_b): + """Two benefit units in two households; `a` is index 0, `b` index 1.""" + return { + "people": {"a": person(reported_uc_a), "b": person(reported_uc_b)}, + "benunits": {"bu_a": {"members": ["a"]}, "bu_b": {"members": ["b"]}}, + "households": {"hh_a": {"members": ["a"]}, "hh_b": {"members": ["b"]}}, + } + + +def shared_household(reported_uc_a, reported_uc_b): + """Two benefit units sharing one household (e.g. a parent and an adult child).""" + return { + "people": {"a": person(reported_uc_a), "b": person(reported_uc_b)}, + "benunits": {"bu_a": {"members": ["a"]}, "bu_b": {"members": ["b"]}}, + "households": {"hh": {"members": ["a", "b"]}}, + } + + +class TestPerBenefitUnit: + def test_one_reporter_does_not_switch_off_the_other_benefit_unit(self): + sim = Simulation(situation=separate_households(5_000, 0)) + flag = sim.calculate("claims_all_entitled_benefits", YEAR) + assert flag.tolist() == [False, True] + + def test_per_benefit_unit_within_one_household(self): + sim = Simulation(situation=shared_household(5_000, 0)) + flag = sim.calculate("claims_all_entitled_benefits", YEAR) + assert flag.tolist() == [False, True] + + def test_would_claim_council_tax_reduction_follows_the_flag(self): + sim = Simulation(situation=separate_households(5_000, 0)) + would_claim = sim.calculate("would_claim_council_tax_reduction", YEAR) + assert would_claim.tolist() == [False, True] + + def test_reported_ctr_still_claims_when_the_flag_is_false(self): + situation = separate_households(5_000, 0) + situation["people"]["a"] = person(reported_uc=5_000, reported_ctr=800) + sim = Simulation(situation=situation) + assert sim.calculate("claims_all_entitled_benefits", YEAR).tolist() == [ + False, + True, + ] + assert sim.calculate("would_claim_council_tax_reduction", YEAR).tolist() == [ + True, + True, + ] + + def test_reporters_of_any_of_the_seven_are_false(self): + for variable in SEVEN_REPORTED: + situation = separate_households(0, 0) + situation["people"]["a"][variable] = {YEAR: 100} + sim = Simulation(situation=situation) + flag = sim.calculate("claims_all_entitled_benefits", YEAR) + assert flag.tolist() == [False, True], variable + + def test_single_benefit_unit_semantics_unchanged(self): + none_reported = Simulation(situation=separate_households(0, 0)) + assert none_reported.calculate("claims_all_entitled_benefits", YEAR).all() + both_report = Simulation(situation=separate_households(5_000, 5_000)) + assert not both_report.calculate("claims_all_entitled_benefits", YEAR).any() + + def test_under_one_pound_of_reported_benefits_counts_as_none(self): + sim = Simulation(situation=separate_households(0.5, 0)) + assert sim.calculate("claims_all_entitled_benefits", YEAR).tolist() == [ + True, + True, + ] + + +@pytest.mark.microsimulation +def test_flag_is_evaluated_per_benefit_unit_in_microdata(): + sim = Microsimulation() + flag = sim.calculate("claims_all_entitled_benefits", YEAR).values.astype(bool) + reported = np.zeros(len(flag)) + for variable in SEVEN_REPORTED: + reported = reported + sim.calculate(variable, YEAR, map_to="benunit").values + assert np.array_equal(flag, reported < 1) + # Both values must occur: the old formula returned a single value for all. + assert flag.any() and (~flag).any() diff --git a/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py b/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py index bb6643e7b8..e41e922baa 100644 --- a/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py +++ b/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py @@ -6,10 +6,18 @@ class claims_all_entitled_benefits(Variable): entity = BenUnit label = "Claims all eligible benefits" definition_period = YEAR - documentation = "Whether this family would claim any benefit they are entitled to" + documentation = ( + "Whether this family would claim any benefit it is entitled to. True " + "where the benefit unit reports none of the seven means-tested " + "benefits the formula checks (Child Tax Credit, Working Tax Credit, " + "Universal Credit, Housing Benefit, income-based JSA, Income Support " + "and income-related ESA); False where it reports any, in which case " + "its reported benefits are taken as the complete set. Datasets and " + "situations can override it directly." + ) def formula(benunit, period, parameters): - # Return false if we have any reported values in the simulation for benefits. + # Reporting under £1 across the seven benefits counts as reporting none. return ( add( benunit, @@ -23,6 +31,6 @@ def formula(benunit, period, parameters): "income_support_reported", "esa_income_reported", ], - ).sum() + ) < 1 ) From ef02218d71471c14aa8cca2104b31425c85106fc Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Fri, 28 Aug 2026 08:54:51 +0200 Subject: [PATCH 2/8] =?UTF-8?q?Document=20the=20=C2=A31=20reporting=20thre?= =?UTF-8?q?shold=20and=20test=20the=20single-benefit-unit=20path?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review findings on the previous commit: the docstrings, test module docstring and changelog fragment said "reports any" where the formula tests the combined reported amount < £1, and the test named for single-benefit-unit semantics actually built two benefit units. Both now match the code: documentation states the threshold, and a genuine one-benefit-unit situation covers the calculator path. Co-Authored-By: Claude Opus 4.6 --- changelog.d/claims-all-per-benunit.fixed.md | 2 +- .../test_claims_all_entitled_benefits.py | 27 ++++++++++++++++--- .../income/claims_all_entitled_benefits.py | 12 ++++----- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/changelog.d/claims-all-per-benunit.fixed.md b/changelog.d/claims-all-per-benunit.fixed.md index d85d6b45dc..502b389ae1 100644 --- a/changelog.d/claims-all-per-benunit.fixed.md +++ b/changelog.d/claims-all-per-benunit.fixed.md @@ -1 +1 @@ -- Evaluate `claims_all_entitled_benefits` per benefit unit instead of summing reported benefits across the whole simulation. The old array-wide sum made the flag False for every benefit unit in microdata whenever any benefit unit reported one of its seven benefits, restricting simulated Council Tax Reduction to FRS reporters. +- Evaluate `claims_all_entitled_benefits` per benefit unit instead of summing reported benefits across the whole simulation. The old array-wide sum made the flag False for every benefit unit in microdata whenever any benefit unit reported £1 or more across its seven benefits, restricting simulated Council Tax Reduction to FRS reporters. diff --git a/policyengine_uk/tests/test_claims_all_entitled_benefits.py b/policyengine_uk/tests/test_claims_all_entitled_benefits.py index 933251462e..206c8b7f86 100644 --- a/policyengine_uk/tests/test_claims_all_entitled_benefits.py +++ b/policyengine_uk/tests/test_claims_all_entitled_benefits.py @@ -1,9 +1,9 @@ """Regression tests for `claims_all_entitled_benefits`. -The flag is a benefit-unit attribute: a family that reports none of the seven -means-tested benefits the formula checks is assumed to claim everything it is -entitled to, and a family that reports any of them is assumed to have reported -completely. The formula used to sum the seven reported columns over the whole +The flag is a benefit-unit attribute: a family that reports under £1 in total +across the seven means-tested benefits the formula checks is assumed to claim +everything it is entitled to, and a family that reports £1 or more is assumed +to have reported completely. The formula used to sum the seven reported columns over the whole simulation (`add(...).sum() < 1`), so in microdata it was False for every benefit unit as soon as any benefit unit reported any of them, and the consumers that gate on it (`would_claim_council_tax_reduction` above all) @@ -36,6 +36,15 @@ def person(reported_uc=0, reported_ctr=0): } +def single_household(reported_uc): + """One person, one benefit unit, one household — the calculator path.""" + return { + "people": {"a": person(reported_uc)}, + "benunits": {"bu_a": {"members": ["a"]}}, + "households": {"hh_a": {"members": ["a"]}}, + } + + def separate_households(reported_uc_a, reported_uc_b): """Two benefit units in two households; `a` is index 0, `b` index 1.""" return { @@ -92,6 +101,16 @@ def test_reporters_of_any_of_the_seven_are_false(self): assert flag.tolist() == [False, True], variable def test_single_benefit_unit_semantics_unchanged(self): + none_reported = Simulation(situation=single_household(0)) + assert none_reported.calculate( + "claims_all_entitled_benefits", YEAR + ).tolist() == [True] + reporter = Simulation(situation=single_household(5_000)) + assert reporter.calculate("claims_all_entitled_benefits", YEAR).tolist() == [ + False + ] + + def test_homogeneous_benefit_units_agree(self): none_reported = Simulation(situation=separate_households(0, 0)) assert none_reported.calculate("claims_all_entitled_benefits", YEAR).all() both_report = Simulation(situation=separate_households(5_000, 5_000)) diff --git a/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py b/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py index e41e922baa..c8f172da37 100644 --- a/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py +++ b/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py @@ -8,12 +8,12 @@ class claims_all_entitled_benefits(Variable): definition_period = YEAR documentation = ( "Whether this family would claim any benefit it is entitled to. True " - "where the benefit unit reports none of the seven means-tested " - "benefits the formula checks (Child Tax Credit, Working Tax Credit, " - "Universal Credit, Housing Benefit, income-based JSA, Income Support " - "and income-related ESA); False where it reports any, in which case " - "its reported benefits are taken as the complete set. Datasets and " - "situations can override it directly." + "where the benefit unit reports under £1 in total across the seven " + "means-tested benefits the formula checks (Child Tax Credit, Working " + "Tax Credit, Universal Credit, Housing Benefit, income-based JSA, " + "Income Support and income-related ESA); False where it reports £1 " + "or more, in which case its reported benefits are taken as the " + "complete set. Datasets and situations can override it directly." ) def formula(benunit, period, parameters): From 071309a29fd7309909f00db599a10588e321fb06 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 12 Oct 2026 06:43:27 -0400 Subject: [PATCH 3/8] Keep council tax reduction reporters-only under d1390 --- changelog.d/claims-all-per-benunit.fixed.md | 2 +- .../housing_benefit/pension_age_premiums.yaml | 2 + ...sion_age_severe_disability_conditions.yaml | 9 ++ .../pension_credit_carer_income.yaml | 4 + .../claimant_family_scheme.yaml | 29 +++++ .../claimant_household_head.yaml | 35 ++++++ .../council_tax_reduction.yaml | 36 ++++++ ...l_tax_reduction_carer_support_payment.yaml | 12 ++ .../council_tax_reduction_pension_credit.yaml | 24 ++++ .../council_tax_reduction_pensioner.yaml | 5 + ...eduction_pensioner_earnings_disregard.yaml | 1 + .../ctr_reporters_only.yaml | 104 ++++++++++++++++++ .../joint_liability.yaml | 29 +++++ .../integration/entitledto_scenarios.yaml | 1 + ...efit_cap_and_ctr_pension_age_properties.py | 5 +- .../test_claims_all_entitled_benefits.py | 87 ++++++++++++++- ...l_tax_reduction_carer_income_properties.py | 1 + ...ction_claimant_family_scheme_properties.py | 2 + ...uncil_tax_reduction_claimant_properties.py | 1 + ...tax_reduction_pension_credit_properties.py | 6 +- ...pensioner_earnings_disregard_properties.py | 1 + ...ge_severe_disability_premium_properties.py | 5 +- ..._pension_credit_carer_income_properties.py | 5 +- ..._savings_credit_only_receipt_properties.py | 4 +- .../would_claim_council_tax_reduction.py | 9 +- .../income/claims_all_entitled_benefits.py | 3 +- 26 files changed, 403 insertions(+), 19 deletions(-) create mode 100644 policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_reporters_only.yaml diff --git a/changelog.d/claims-all-per-benunit.fixed.md b/changelog.d/claims-all-per-benunit.fixed.md index 502b389ae1..fcd0b133f8 100644 --- a/changelog.d/claims-all-per-benunit.fixed.md +++ b/changelog.d/claims-all-per-benunit.fixed.md @@ -1 +1 @@ -- Evaluate `claims_all_entitled_benefits` per benefit unit instead of summing reported benefits across the whole simulation. The old array-wide sum made the flag False for every benefit unit in microdata whenever any benefit unit reported £1 or more across its seven benefits, restricting simulated Council Tax Reduction to FRS reporters. +- Evaluate `claims_all_entitled_benefits` per benefit unit, while keeping Council Tax Reduction explicitly limited to reporters by default until calibrated take-up inputs land (policyengine-uk-data#448; d1390). Explicit Council Tax Reduction claim inputs continue to override its default. diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_premiums.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_premiums.yaml index f48a31b1f6..4cfe23e14e 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_premiums.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_premiums.yaml @@ -22,6 +22,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true households: household: members: [claimant] @@ -53,6 +54,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true households: household: members: [claimant] diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_severe_disability_conditions.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_severe_disability_conditions.yaml index fee4343f7b..1e1e5ab83f 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_severe_disability_conditions.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_severe_disability_conditions.yaml @@ -23,6 +23,7 @@ benunits: pensioners: members: [claimant, partner] + would_claim_council_tax_reduction: true households: household: members: [claimant, partner] @@ -53,6 +54,7 @@ benunits: pensioners: members: [claimant, partner] + would_claim_council_tax_reduction: true households: household: members: [claimant, partner] @@ -85,6 +87,7 @@ benunits: pensioners: members: [claimant, partner] + would_claim_council_tax_reduction: true households: household: members: [claimant, partner] @@ -116,8 +119,10 @@ benunits: pensioner: members: [claimant] + would_claim_council_tax_reduction: true other_family: members: [resident] + would_claim_council_tax_reduction: true households: household: members: [claimant, resident] @@ -153,8 +158,10 @@ benunits: pensioner: members: [claimant] + would_claim_council_tax_reduction: true other_family: members: [daughter, grandson] + would_claim_council_tax_reduction: true households: household: members: [claimant, daughter, grandson] @@ -195,6 +202,7 @@ benunits: pensioner: members: [claimant] + would_claim_council_tax_reduction: true # HB(SPC) reg 55(6) and England CTR Sch 1 para 8(6): AA exempts # the claimant from deductions. Supply these independently of the # current generic deduction formulas to isolate the premium rule. @@ -202,6 +210,7 @@ council_tax_reduction_non_dep_deductions: 0 other_family: members: [carer] + would_claim_council_tax_reduction: true households: household: members: [claimant, carer] diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_carer_income.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_carer_income.yaml index 15ac062765..59ddd2f3c3 100644 --- a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_carer_income.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_carer_income.yaml @@ -189,9 +189,11 @@ benunits: benunit_1: members: [claimant_1, carer_1] + would_claim_council_tax_reduction: true housing_benefit_applicable_income_disregard: 0 benunit_2: members: [claimant_2, carer_2] + would_claim_council_tax_reduction: true housing_benefit_applicable_income_disregard: 0 households: household_1: @@ -253,9 +255,11 @@ benunits: benunit_1: members: [claimant_1, carer_1] + would_claim_council_tax_reduction: true housing_benefit_applicable_income_disregard: 0 benunit_2: members: [claimant_2, carer_2] + would_claim_council_tax_reduction: true housing_benefit_applicable_income_disregard: 0 households: household_1: diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_family_scheme.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_family_scheme.yaml index 793efe1508..6a42c7c022 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_family_scheme.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_family_scheme.yaml @@ -23,10 +23,12 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false # 500 a week. @@ -65,10 +67,12 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 26_000 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 15_000 @@ -110,15 +114,18 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 0 son_family: members: [adult_son] + would_claim_council_tax_reduction: true would_claim_uc: false households: home: @@ -157,6 +164,7 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 sharer_family: @@ -199,6 +207,7 @@ council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 0 @@ -232,6 +241,7 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 child_family: @@ -302,6 +312,7 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 sharer_family: @@ -425,10 +436,12 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 15_000 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 8_000 @@ -467,10 +480,12 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 8_000 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 15_000 @@ -505,10 +520,12 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 15_000 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 8_000 @@ -543,10 +560,12 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 8_000 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 15_000 @@ -590,6 +609,7 @@ benunits: family: members: [grandmother, young_mother, young_father, baby] + would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 households: @@ -662,6 +682,7 @@ would_claim_uc: false sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false households: @@ -743,6 +764,7 @@ would_claim_uc: false sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false # Too much income for any reduction. @@ -791,11 +813,13 @@ council_tax_reduction_applicable_income: 0 student_family: members: [student] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 0 pensioner_family: members: [pensioner] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 0 @@ -837,11 +861,13 @@ council_tax_reduction_applicable_income: 0 student_family: members: [student] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 0 pensioner_family: members: [pensioner] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 0 @@ -877,6 +903,7 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 sharer_family: @@ -912,6 +939,7 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 sharer_family: @@ -956,6 +984,7 @@ benunits: family: members: [grandmother, young_mother, young_father, baby] + would_claim_council_tax_reduction: true would_claim_uc: false income_support: 3_000 council_tax_reduction_applicable_income: 0 diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_household_head.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_household_head.yaml index 78dfcecba1..99dbd0b390 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_household_head.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_household_head.yaml @@ -25,9 +25,11 @@ benunits: friend_family: members: [friend] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 householder_family: members: [householder] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 households: home: @@ -58,9 +60,11 @@ benunits: first_family: members: [first] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 second_family: members: [second] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 households: home: @@ -91,9 +95,11 @@ benunits: householder_family: members: [householder] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 friend_family: members: [friend] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 households: home: @@ -121,10 +127,12 @@ benunits: friend_family: members: [friend] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true householder_family: members: [householder] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -156,10 +164,12 @@ benunits: householder_family: members: [householder] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true friend_family: members: [friend] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -189,10 +199,12 @@ benunits: householder_family: members: [householder] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true friend_family: members: [friend] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -222,10 +234,12 @@ benunits: householder_family: members: [householder] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true friend_family: members: [friend] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -255,10 +269,12 @@ benunits: householder_family: members: [householder] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true friend_family: members: [friend] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -289,9 +305,11 @@ benunits: householder_family: members: [householder] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 parent_family: members: [parent] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 households: home: @@ -327,9 +345,11 @@ benunits: householder_family: members: [householder] + would_claim_council_tax_reduction: true would_claim_uc: false parent_family: members: [parent] + would_claim_council_tax_reduction: true households: home: members: [householder, parent] @@ -425,9 +445,11 @@ benunits: householder_family: members: [householder] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 households: @@ -466,13 +488,16 @@ benunits: eldest_family: members: [eldest] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 other_family: members: [other_adult] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 households: home: @@ -508,12 +533,15 @@ benunits: older_family: members: [older_flagged] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 younger_family: members: [younger_flagged] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 households: @@ -549,9 +577,11 @@ benunits: householder_family: members: [householder] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 child_family: members: [child_sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 households: @@ -584,9 +614,11 @@ benunits: householder_family: members: [householder] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 young_family: members: [young_sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 households: @@ -625,6 +657,7 @@ benunits: family: members: [grandmother, young_mother, young_father, baby] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 households: home: @@ -696,8 +729,10 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true cotenant_family: members: [cotenant] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 households: diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction.yaml index daaec21e26..fb8ce71b34 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction.yaml @@ -82,6 +82,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true households: household: members: [claimant] @@ -104,6 +105,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -158,10 +160,12 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] + would_claim_council_tax_reduction: true households: household: members: [claimant, non_dep] @@ -186,10 +190,12 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] + would_claim_council_tax_reduction: true would_claim_uc: true households: household: @@ -211,6 +217,7 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_maximum_amount: 5_000 @@ -238,6 +245,7 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_reported_capital: 0 @@ -262,6 +270,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -312,6 +321,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true council_tax_reduction_applicable_amount: 0 @@ -342,10 +352,12 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] + would_claim_council_tax_reduction: true households: household: members: [claimant, non_dep] @@ -367,6 +379,7 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_maximum_amount: 5_000 @@ -394,6 +407,7 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_reported_capital: 0 @@ -418,6 +432,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -468,6 +483,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true council_tax_reduction_applicable_amount: 10_000 @@ -499,10 +515,12 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] + would_claim_council_tax_reduction: true households: household: members: [claimant, non_dep] @@ -528,10 +546,12 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] + would_claim_council_tax_reduction: true households: household: members: [claimant, non_dep] @@ -552,6 +572,7 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_reported_capital: 0 @@ -576,6 +597,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -626,6 +648,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true council_tax_reduction_applicable_amount: 0 @@ -657,10 +680,12 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] + would_claim_council_tax_reduction: true households: household: members: [claimant, non_dep] @@ -682,6 +707,7 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_maximum_amount: 5_000 @@ -709,6 +735,7 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_reported_capital: 0 @@ -733,6 +760,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -757,6 +785,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true council_tax_reduction_applicable_income: 25_001 @@ -780,6 +809,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true council_tax_reduction_applicable_income: 25_200 @@ -804,6 +834,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true council_tax_reduction_applicable_income: 24_960 @@ -827,6 +858,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_maximum_amount: 24_960 @@ -881,10 +913,12 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] + would_claim_council_tax_reduction: true households: household: members: [claimant, non_dep] @@ -907,10 +941,12 @@ benunits: claimant_benunit: members: [claimant] + would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] + would_claim_council_tax_reduction: true income_support: 1 households: household: diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_carer_support_payment.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_carer_support_payment.yaml index 186b79ccc3..c499ed3770 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_carer_support_payment.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_carer_support_payment.yaml @@ -40,6 +40,7 @@ benunits: benunit: members: [carer] + would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -75,6 +76,7 @@ benunits: benunit: members: [carer] + would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -100,6 +102,7 @@ benunits: benunit: members: [carer] + would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -128,6 +131,7 @@ benunits: benunit: members: [carer] + would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -171,6 +175,7 @@ benunits: benunit: members: [carer] + would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -203,6 +208,7 @@ benunits: benunit: members: [carer] + would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -232,6 +238,7 @@ benunits: benunit: members: [carer] + would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -261,6 +268,7 @@ benunits: benunit: members: [carer] + would_claim_council_tax_reduction: true households: household: members: [carer] @@ -300,6 +308,7 @@ benunits: benunit: members: [claimant, partner] + would_claim_council_tax_reduction: true households: household: members: [claimant, partner] @@ -351,6 +360,7 @@ benunits: benunit: members: [claimant, partner] + would_claim_council_tax_reduction: true is_married: false households: household: @@ -393,6 +403,7 @@ benunits: benunit: members: [claimant, partner] + would_claim_council_tax_reduction: true households: household: members: [claimant, partner] @@ -423,6 +434,7 @@ benunits: benunit: members: [carer] + would_claim_council_tax_reduction: true households: household: members: [carer] diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pension_credit.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pension_credit.yaml index e07ff2f6f8..884c2dd1be 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pension_credit.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pension_credit.yaml @@ -23,6 +23,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true minimum_guarantee: 18_500 households: @@ -55,6 +56,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true minimum_guarantee: 18_500 households: @@ -83,6 +85,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true minimum_guarantee: 18_500 would_claim_pc: false @@ -113,6 +116,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -140,6 +144,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -168,6 +173,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true would_claim_pc: false households: @@ -198,6 +204,7 @@ benunits: benunit: members: [claimant, partner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -226,9 +233,11 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true son_benunit: members: [son] + would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -267,6 +276,7 @@ benunits: benunit: members: [claimant, partner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true would_claim_uc: false households: @@ -295,6 +305,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -319,6 +330,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true minimum_guarantee: 18_500 households: @@ -345,6 +357,7 @@ benunits: benunit: members: [claimant] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true would_claim_uc: false households: @@ -373,6 +386,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -397,6 +411,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true minimum_guarantee: 18_500 households: @@ -424,6 +439,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -455,6 +471,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -486,6 +503,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true would_claim_pc: false households: @@ -518,6 +536,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -547,6 +566,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -572,6 +592,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -603,6 +624,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -644,6 +666,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -683,6 +706,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner.yaml index e791a4029a..570439652a 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner.yaml @@ -131,6 +131,7 @@ benunits: benunit: members: [older, younger] + would_claim_council_tax_reduction: true universal_credit_pre_benefit_cap: 10_000 households: household: @@ -165,9 +166,11 @@ benunits: couple: members: [older, younger] + would_claim_council_tax_reduction: true universal_credit_pre_benefit_cap: 10_000 son: members: [son] + would_claim_council_tax_reduction: true households: household: members: [older, younger, son] @@ -228,6 +231,7 @@ benunits: benunit: members: [pensioner, young_person] + would_claim_council_tax_reduction: true households: household: members: [pensioner, young_person] @@ -316,6 +320,7 @@ benunits: benunit: members: [older, younger, child] + would_claim_council_tax_reduction: true universal_credit_pre_benefit_cap: 30_000 child_benefit: 3_000 uc_deductions: 0 diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner_earnings_disregard.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner_earnings_disregard.yaml index c077000081..0ca538b7be 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner_earnings_disregard.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner_earnings_disregard.yaml @@ -430,6 +430,7 @@ benunits: benunit: members: [pensioner] + would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_reporters_only.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_reporters_only.yaml new file mode 100644 index 0000000000..d787334607 --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_reporters_only.yaml @@ -0,0 +1,104 @@ +- name: WALES entitled non-reporting family under default reporters-only + period: 2026 + input: + age: 35 + country: WALES + local_authority: CARDIFF + council_tax: 1800 + savings: 0 + would_claim_uc: false + claims_all_entitled_benefits: true + output: + council_tax_benefit_reported: 0 + would_claim_council_tax_reduction: false + simulated_council_tax_reduction_benunit: 0 + council_tax_benefit: 0 + council_tax_reduction: 0 + +- name: WALES entitled non-reporting family under explicit CTR claim + period: 2026 + input: + age: 35 + country: WALES + local_authority: CARDIFF + council_tax: 1800 + savings: 0 + would_claim_uc: false + claims_all_entitled_benefits: true + would_claim_council_tax_reduction: true + output: + council_tax_benefit_reported: 0 + would_claim_council_tax_reduction: true + simulated_council_tax_reduction_benunit: 1800 + council_tax_benefit: 1800 + council_tax_reduction: 1800 + +- name: SCOTLAND entitled non-reporting family under default reporters-only + period: 2026 + input: + age: 35 + country: SCOTLAND + local_authority: CITY_OF_EDINBURGH + council_tax: 1800 + savings: 0 + would_claim_uc: false + claims_all_entitled_benefits: true + output: + council_tax_benefit_reported: 0 + would_claim_council_tax_reduction: false + simulated_council_tax_reduction_benunit: 0 + council_tax_benefit: 0 + council_tax_reduction: 0 + +- name: SCOTLAND entitled non-reporting family under explicit CTR claim + period: 2026 + input: + age: 35 + country: SCOTLAND + local_authority: CITY_OF_EDINBURGH + council_tax: 1800 + savings: 0 + would_claim_uc: false + claims_all_entitled_benefits: true + would_claim_council_tax_reduction: true + output: + council_tax_benefit_reported: 0 + would_claim_council_tax_reduction: true + simulated_council_tax_reduction_benunit: 1800 + council_tax_benefit: 1800 + council_tax_reduction: 1800 + +- name: ENGLAND entitled non-reporting family under default reporters-only + period: 2026 + input: + age: 70 + country: ENGLAND + local_authority: MAIDSTONE + council_tax: 1800 + savings: 0 + would_claim_uc: false + claims_all_entitled_benefits: true + output: + council_tax_benefit_reported: 0 + would_claim_council_tax_reduction: false + simulated_council_tax_reduction_benunit: 0 + council_tax_benefit: 0 + council_tax_reduction: 0 + +- name: ENGLAND entitled non-reporting family under explicit CTR claim + period: 2026 + input: + age: 70 + country: ENGLAND + local_authority: MAIDSTONE + council_tax: 1800 + savings: 0 + would_claim_uc: false + claims_all_entitled_benefits: true + would_claim_council_tax_reduction: true + output: + council_tax_benefit_reported: 0 + would_claim_council_tax_reduction: true + simulated_council_tax_reduction_benunit: 1800 + council_tax_benefit: 1800 + council_tax_reduction: 1800 diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/joint_liability.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/joint_liability.yaml index b6a6a07a24..1c76f31290 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/joint_liability.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/joint_liability.yaml @@ -24,17 +24,21 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_1_family: members: [sharer_1] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 sharer_2_family: members: [sharer_2] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 son_family: members: [adult_son] + would_claim_council_tax_reduction: true households: home: members: [head, sharer_1, sharer_2, adult_son] @@ -69,9 +73,11 @@ benunits: couple: members: [head, partner] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 households: @@ -105,9 +111,11 @@ benunits: couple: members: [head, partner] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 son_family: members: [adult_son] + would_claim_council_tax_reduction: true households: home: members: [head, partner, adult_son] @@ -137,9 +145,11 @@ benunits: householder_family: members: [householder] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 lodger_family: members: [lodger] + would_claim_council_tax_reduction: true households: home: members: [householder, lodger] @@ -170,8 +180,10 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true father_family: members: [father] + would_claim_council_tax_reduction: true households: home: members: [head, father] @@ -207,13 +219,16 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 cotenant_family: members: [cotenant] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 father_family: members: [father] + would_claim_council_tax_reduction: true households: home: members: [head, cotenant, father] @@ -244,9 +259,11 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 student_family: members: [student] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true households: home: @@ -277,9 +294,11 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 households: @@ -320,8 +339,10 @@ benunits: couple: members: [head, partner] + would_claim_council_tax_reduction: true sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true households: home: @@ -363,8 +384,10 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true couple: members: [sharer, sharer_partner] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true households: home: @@ -401,13 +424,16 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 non_dependant_family: members: [non_dependant] + would_claim_council_tax_reduction: true households: home: members: [head, sharer, non_dependant] @@ -446,13 +472,16 @@ benunits: head_family: members: [head] + would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] + would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 non_dependant_family: members: [non_dependant] + would_claim_council_tax_reduction: true households: home: members: [head, sharer, non_dependant] diff --git a/policyengine_uk/tests/policy/integration/entitledto_scenarios.yaml b/policyengine_uk/tests/policy/integration/entitledto_scenarios.yaml index 95c2636d94..98d298f0e4 100644 --- a/policyengine_uk/tests/policy/integration/entitledto_scenarios.yaml +++ b/policyengine_uk/tests/policy/integration/entitledto_scenarios.yaml @@ -90,6 +90,7 @@ benunits: benunit: members: [pensioner_1, pensioner_2] + would_claim_council_tax_reduction: true households: household: members: [pensioner_1, pensioner_2] diff --git a/policyengine_uk/tests/test_benefit_cap_and_ctr_pension_age_properties.py b/policyengine_uk/tests/test_benefit_cap_and_ctr_pension_age_properties.py index 2e997d22cb..758b72e1f0 100644 --- a/policyengine_uk/tests/test_benefit_cap_and_ctr_pension_age_properties.py +++ b/policyengine_uk/tests/test_benefit_cap_and_ctr_pension_age_properties.py @@ -192,8 +192,9 @@ def situation(units): benunit = { "members": names, "would_claim_uc": {PERIOD: unit["would_claim_uc"]}, - # claims_all_entitled_benefits sums reported benefits across the - # whole simulation, so it is set per family. + "would_claim_council_tax_reduction": { + PERIOD: unit["hb_reported"] == 0 or unit["ctb_reported"] > 0 + }, "claims_all_entitled_benefits": { PERIOD: unit["hb_reported"] == 0 and unit["ctb_reported"] == 0 }, diff --git a/policyengine_uk/tests/test_claims_all_entitled_benefits.py b/policyengine_uk/tests/test_claims_all_entitled_benefits.py index 206c8b7f86..947a237808 100644 --- a/policyengine_uk/tests/test_claims_all_entitled_benefits.py +++ b/policyengine_uk/tests/test_claims_all_entitled_benefits.py @@ -6,16 +6,20 @@ to have reported completely. The formula used to sum the seven reported columns over the whole simulation (`add(...).sum() < 1`), so in microdata it was False for every benefit unit as soon as any benefit unit reported any of them, and the -consumers that gate on it (`would_claim_council_tax_reduction` above all) -collapsed to FRS reporters only. +consumers that gate on it collapsed to reporters only. Council Tax Reduction +now has its own explicit reporters-only default until calibrated data take-up +lands (uk-data#448; d1390). """ import numpy as np import pytest +from hypothesis import example, given, settings, strategies as st from policyengine_uk import Microsimulation, Simulation -YEAR = 2025 +pytestmark = pytest.mark.usefixtures("cloned_uk_tax_benefit_system") + +YEAR = 2026 SEVEN_REPORTED = [ "child_tax_credit_reported", @@ -74,10 +78,10 @@ def test_per_benefit_unit_within_one_household(self): flag = sim.calculate("claims_all_entitled_benefits", YEAR) assert flag.tolist() == [False, True] - def test_would_claim_council_tax_reduction_follows_the_flag(self): + def test_ctr_default_does_not_follow_the_all_benefits_flag(self): sim = Simulation(situation=separate_households(5_000, 0)) would_claim = sim.calculate("would_claim_council_tax_reduction", YEAR) - assert would_claim.tolist() == [False, True] + assert would_claim.tolist() == [False, False] def test_reported_ctr_still_claims_when_the_flag_is_false(self): situation = separate_households(5_000, 0) @@ -89,7 +93,7 @@ def test_reported_ctr_still_claims_when_the_flag_is_false(self): ] assert sim.calculate("would_claim_council_tax_reduction", YEAR).tolist() == [ True, - True, + False, ] def test_reporters_of_any_of_the_seven_are_false(self): @@ -134,3 +138,74 @@ def test_flag_is_evaluated_per_benefit_unit_in_microdata(): assert np.array_equal(flag, reported < 1) # Both values must occur: the old formula returned a single value for all. assert flag.any() and (~flag).any() + + +# Each generated family is independently eligible or ineligible and may have +# reported CTR or an explicit take-up input. Other families cannot enable it. +CTR_FAMILIES = st.lists( + st.tuples( + st.integers(min_value=18, max_value=90), + st.sampled_from(("ENGLAND", "SCOTLAND", "WALES")), + st.integers(min_value=0, max_value=50_000), + st.integers(min_value=0, max_value=50_000), + st.booleans(), + st.sampled_from((None, False, True)), + st.sampled_from((0, 100)), + ), + min_size=1, + max_size=4, +) + + +@given(families=CTR_FAMILIES) +@example(families=[(40, "SCOTLAND", 0, 0, True, None, 0)]) +@example( + families=[ + (40, "WALES", 0, 0, True, None, 0), + (40, "WALES", 0, 0, True, True, 0), + (70, "ENGLAND", 0, 0, False, None, 100), + ] +) +@settings(max_examples=30, deadline=None) +def test_ctr_is_zero_for_every_nonreporter_without_an_explicit_claim_flag(families): + situation = {"people": {}, "benunits": {}, "households": {}} + must_be_zero = [] + councils = { + "ENGLAND": "MAIDSTONE", + "SCOTLAND": "CITY_OF_EDINBURGH", + "WALES": "CARDIFF", + } + for index, (age, country, income, savings, claims_all, flag, reported) in enumerate( + families + ): + name = f"person_{index}" + situation["people"][name] = { + "age": {YEAR: age}, + "employment_income": {YEAR: income}, + "council_tax_benefit_reported": {YEAR: reported}, + } + benunit = { + "members": [name], + "claims_all_entitled_benefits": {YEAR: claims_all}, + "would_claim_uc": {YEAR: False}, + } + if flag is not None: + benunit["would_claim_council_tax_reduction"] = {YEAR: flag} + situation["benunits"][f"bu_{index}"] = benunit + situation["households"][f"hh_{index}"] = { + "members": [name], + "country": {YEAR: country}, + "local_authority": {YEAR: councils[country]}, + "council_tax": {YEAR: 1_800}, + "savings": {YEAR: savings}, + } + must_be_zero.append(reported == 0 and flag is not True) + sim = Simulation(situation=situation) + mask = np.array(must_be_zero, dtype=bool) + assert not sim.calculate("would_claim_council_tax_reduction", YEAR)[mask].any() + for variable in ( + "simulated_council_tax_reduction_benunit", + "council_tax_benefit", + "council_tax_reduction", + ): + assert (sim.calculate(variable, YEAR)[mask] == 0).all(), variable diff --git a/policyengine_uk/tests/test_council_tax_reduction_carer_income_properties.py b/policyengine_uk/tests/test_council_tax_reduction_carer_income_properties.py index e317bf68e5..ddcbcde9e4 100644 --- a/policyengine_uk/tests/test_council_tax_reduction_carer_income_properties.py +++ b/policyengine_uk/tests/test_council_tax_reduction_carer_income_properties.py @@ -208,6 +208,7 @@ def situation(families): benunits[f"b{i}_{k}_{c}"] = { "members": names, "would_claim_uc": {YEAR: False}, + "would_claim_council_tax_reduction": {YEAR: True}, } households[f"h{i}_{k}_{c}"] = { "members": names, diff --git a/policyengine_uk/tests/test_council_tax_reduction_claimant_family_scheme_properties.py b/policyengine_uk/tests/test_council_tax_reduction_claimant_family_scheme_properties.py index 9849322beb..4b10b241b0 100644 --- a/policyengine_uk/tests/test_council_tax_reduction_claimant_family_scheme_properties.py +++ b/policyengine_uk/tests/test_council_tax_reduction_claimant_family_scheme_properties.py @@ -268,6 +268,7 @@ def build(population, alone=False, perturb_others=False, awards=None): "liable_for_share_of_household_rent": fam["role"] == "sharer" and not alone, "claims_all_entitled_benefits": True, + "would_claim_council_tax_reduction": True, "would_claim_uc": True, } if awards is not None: @@ -618,6 +619,7 @@ def council_situation(homes, with_disability): "members": [pid], "liable_for_share_of_household_rent": f == 1, "claims_all_entitled_benefits": True, + "would_claim_council_tax_reduction": True, "would_claim_uc": False, } ids.append(pid) diff --git a/policyengine_uk/tests/test_council_tax_reduction_claimant_properties.py b/policyengine_uk/tests/test_council_tax_reduction_claimant_properties.py index 6424555e09..4a82a8c483 100644 --- a/policyengine_uk/tests/test_council_tax_reduction_claimant_properties.py +++ b/policyengine_uk/tests/test_council_tax_reduction_claimant_properties.py @@ -192,6 +192,7 @@ def build(population, age_override=None): "members": ids, "liable_for_share_of_household_rent": fam["sharer"] and f > 0, "claims_all_entitled_benefits": True, + "would_claim_council_tax_reduction": True, "would_claim_uc": True, } members.extend(ids) diff --git a/policyengine_uk/tests/test_council_tax_reduction_pension_credit_properties.py b/policyengine_uk/tests/test_council_tax_reduction_pension_credit_properties.py index e6d1de97c7..3d3a295f06 100644 --- a/policyengine_uk/tests/test_council_tax_reduction_pension_credit_properties.py +++ b/policyengine_uk/tests/test_council_tax_reduction_pension_credit_properties.py @@ -206,9 +206,8 @@ def situation( claim_pc = unit["would_claim_pc"] if would_claim_pc is None else would_claim_pc benunit = { "members": names, - # claims_all_entitled_benefits sums reported benefits across the - # whole simulation, so set it for every family. "claims_all_entitled_benefits": {YEAR: True}, + "would_claim_council_tax_reduction": {YEAR: True}, "would_claim_pc": {YEAR: claim_pc}, "would_claim_uc": {YEAR: unit.get("would_claim_uc", False)}, } @@ -227,6 +226,7 @@ def situation( benunits[f"n{i}"] = { "members": [name], "claims_all_entitled_benefits": {YEAR: True}, + "would_claim_council_tax_reduction": {YEAR: True}, "would_claim_uc": {YEAR: False}, } benunit_index += 1 @@ -526,6 +526,7 @@ def test_savings_credit_only_award_counts_the_frozen_savings_credit(): "benunit": { "members": ["pensioner"], "claims_all_entitled_benefits": {YEAR: True}, + "would_claim_council_tax_reduction": {YEAR: True}, } }, "households": { @@ -572,6 +573,7 @@ def freeze_case(age, state_pension, private_pension, savings, reform): "benunit": { "members": ["pensioner"], "claims_all_entitled_benefits": {YEAR: True}, + "would_claim_council_tax_reduction": {YEAR: True}, } }, "households": { diff --git a/policyengine_uk/tests/test_council_tax_reduction_pensioner_earnings_disregard_properties.py b/policyengine_uk/tests/test_council_tax_reduction_pensioner_earnings_disregard_properties.py index 0db11ccbd2..248f755484 100644 --- a/policyengine_uk/tests/test_council_tax_reduction_pensioner_earnings_disregard_properties.py +++ b/policyengine_uk/tests/test_council_tax_reduction_pensioner_earnings_disregard_properties.py @@ -126,6 +126,7 @@ def situation(units, year, earnings_bump=0.0, no_income_related_benefits=False): benunits[f"b{i}"] = { "members": names, "claims_all_entitled_benefits": {year: True}, + "would_claim_council_tax_reduction": {year: True}, } if no_income_related_benefits: for benefit in ("income_support", "jsa_income", "esa_income"): diff --git a/policyengine_uk/tests/test_pension_age_severe_disability_premium_properties.py b/policyengine_uk/tests/test_pension_age_severe_disability_premium_properties.py index a0deb726ef..db7a77dff7 100644 --- a/policyengine_uk/tests/test_pension_age_severe_disability_premium_properties.py +++ b/policyengine_uk/tests/test_pension_age_severe_disability_premium_properties.py @@ -116,7 +116,10 @@ def situation(families): person[variable] = {YEAR: value} people[name] = person names.append(name) - benunits[f"b{i}_{k}"] = {"members": names} + benunits[f"b{i}_{k}"] = { + "members": names, + "would_claim_council_tax_reduction": {YEAR: True}, + } households[f"h{i}_{k}"] = { "members": names, "country": {YEAR: "ENGLAND"}, diff --git a/policyengine_uk/tests/test_pension_credit_carer_income_properties.py b/policyengine_uk/tests/test_pension_credit_carer_income_properties.py index b0d4fcf75c..af48f85d76 100644 --- a/policyengine_uk/tests/test_pension_credit_carer_income_properties.py +++ b/policyengine_uk/tests/test_pension_credit_carer_income_properties.py @@ -156,7 +156,10 @@ def situation(families): person["carers_allowance_reported"] = {YEAR: 1} people[name] = person names.append(name) - benunits[f"b{i}_{k}"] = {"members": names} + benunits[f"b{i}_{k}"] = { + "members": names, + "would_claim_council_tax_reduction": {YEAR: True}, + } households[f"h{i}_{k}"] = { "members": names, "country": {YEAR: fam["country"]}, diff --git a/policyengine_uk/tests/test_savings_credit_only_receipt_properties.py b/policyengine_uk/tests/test_savings_credit_only_receipt_properties.py index 98133c2046..f7a735f6c9 100644 --- a/policyengine_uk/tests/test_savings_credit_only_receipt_properties.py +++ b/policyengine_uk/tests/test_savings_credit_only_receipt_properties.py @@ -220,9 +220,8 @@ def situation(units, would_claim_pc=None): claims = unit["would_claim_pc"] if would_claim_pc is None else would_claim_pc benunits[f"b{i}"] = { "members": names, - # claims_all_entitled_benefits sums reported benefits across the - # whole simulation, so set it for every family. "claims_all_entitled_benefits": {YEAR: True}, + "would_claim_council_tax_reduction": {YEAR: True}, "would_claim_pc": {YEAR: claims}, "would_claim_uc": {YEAR: False}, } @@ -427,6 +426,7 @@ def single_pensioner(savings=0.0, other_property=0.0): "benunit": { "members": ["pensioner"], "claims_all_entitled_benefits": {YEAR: True}, + "would_claim_council_tax_reduction": {YEAR: True}, } }, "households": { diff --git a/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/would_claim_council_tax_reduction.py b/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/would_claim_council_tax_reduction.py index 68fdd511c9..f0d375f521 100644 --- a/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/would_claim_council_tax_reduction.py +++ b/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/would_claim_council_tax_reduction.py @@ -6,11 +6,14 @@ class would_claim_council_tax_reduction(Variable): entity = BenUnit label = "Would claim Council Tax Reduction" documentation = ( - "Whether this benefit unit would claim Council Tax Reduction if eligible." + "Whether this benefit unit would claim Council Tax Reduction if eligible. " + "By default only families reporting it claim; datasets and situations " + "can override this directly." ) definition_period = YEAR def formula(benunit, period, parameters): - claims_all_entitled_benefits = benunit("claims_all_entitled_benefits", period) reported_ctr = benunit("council_tax_benefit_reported", period) > 0 - return claims_all_entitled_benefits | reported_ctr + # Reporters only under Max's d1390 ruling, until calibrated take-up + # inputs land: https://github.com/PolicyEngine/policyengine-uk-data/issues/448 + return reported_ctr diff --git a/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py b/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py index c8f172da37..f662855d4b 100644 --- a/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py +++ b/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py @@ -13,7 +13,8 @@ class claims_all_entitled_benefits(Variable): "Tax Credit, Universal Credit, Housing Benefit, income-based JSA, " "Income Support and income-related ESA); False where it reports £1 " "or more, in which case its reported benefits are taken as the " - "complete set. Datasets and situations can override it directly." + "complete set. Datasets and situations can override it directly. " + "Council Tax Reduction has a separate reporters-only take-up default." ) def formula(benunit, period, parameters): From f142c1ffdb0c26390c319c6f018f8196df6a1fcd Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 20 Oct 2026 08:21:46 -0400 Subject: [PATCH 4/8] Pin supported dataset provenance routes and document core rebuild limitation --- .../tests/test_data_source_provenance.py | 115 ++++++++++++++++++ policyengine_uk/utils/data_source.py | 11 +- 2 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 policyengine_uk/tests/test_data_source_provenance.py diff --git a/policyengine_uk/tests/test_data_source_provenance.py b/policyengine_uk/tests/test_data_source_provenance.py new file mode 100644 index 0000000000..d4d2d701c0 --- /dev/null +++ b/policyengine_uk/tests/test_data_source_provenance.py @@ -0,0 +1,115 @@ +"""Pin data provenance through supported builders using only synthetic data.""" + +import pandas as pd +import pytest + +from policyengine_core.simulations import Simulation as CoreSimulation +from policyengine_uk import Microsimulation, Simulation +from policyengine_uk.data import UKMultiYearDataset, UKSingleYearDataset +from policyengine_uk.system import system +from policyengine_uk.utils.data_source import built_from_data + + +YEAR = 2026 +SITUATION = { + "people": {"adult": {"age": {YEAR: 70}}}, + "benunits": {"family": {"members": ["adult"]}}, + "households": { + "home": { + "members": ["adult"], + "region": {YEAR: "NORTH_WEST"}, + "tenure_type": {YEAR: "RENT_PRIVATELY"}, + "rent": {YEAR: 8000}, + "council_tax": {YEAR: 1800}, + } + }, +} + + +@pytest.fixture(scope="module") +def mock_dataset(): + return UKMultiYearDataset( + datasets=[ + UKSingleYearDataset( + person=pd.DataFrame( + { + "person_id": [1], + "person_benunit_id": [1], + "person_household_id": [1], + "age": [70], + } + ), + benunit=pd.DataFrame({"benunit_id": [1]}), + household=pd.DataFrame( + { + "household_id": [1], + "region": ["NORTH_WEST"], + "tenure_type": ["RENT_PRIVATELY"], + "rent": [8000], + "council_tax": [1800], + } + ), + fiscal_year=YEAR, + ) + ] + ) + + +@pytest.fixture(scope="module") +def mock_frame(): + return pd.DataFrame( + { + f"person_id__{YEAR}": [1], + f"person_benunit_id__{YEAR}": [1], + f"person_household_id__{YEAR}": [1], + f"benunit_id__{YEAR}": [1], + f"household_id__{YEAR}": [1], + f"age__{YEAR}": [70], + f"region__{YEAR}": ["NORTH_WEST"], + f"tenure_type__{YEAR}": ["RENT_PRIVATELY"], + f"rent__{YEAR}": [8000], + f"council_tax__{YEAR}": [1800], + } + ) + + +@pytest.fixture( + scope="module", + params=[Simulation, Microsimulation, CoreSimulation], + ids=["uk-simulation", "uk-microsimulation", "core-simulation"], +) +def source_simulations(request, mock_dataset, mock_frame): + simulation_class = request.param + if simulation_class is CoreSimulation: + return { + "data": CoreSimulation(tax_benefit_system=system, dataset=mock_frame), + "situation": CoreSimulation(tax_benefit_system=system, situation=SITUATION), + } + return { + "data": simulation_class(dataset=mock_dataset), + "situation": simulation_class(situation=SITUATION), + } + + +@pytest.mark.parametrize("source, expected", [("data", True), ("situation", False)]) +@pytest.mark.parametrize("derivation", ["original", "clone", "branch"]) +def test_built_from_data_keeps_source_when_copying( + source_simulations, source, expected, derivation +): + simulation = source_simulations[source] + if derivation == "clone": + simulation = simulation.clone() + elif derivation == "branch": + simulation = simulation.get_branch() + + assert built_from_data(simulation) is expected + + +@pytest.mark.parametrize("simulation_class", [Simulation, Microsimulation]) +def test_built_from_data_tracks_uk_situation_rebuild(simulation_class, mock_dataset): + simulation = simulation_class(dataset=mock_dataset) + assert built_from_data(simulation) is True + + simulation.build_from_situation(SITUATION) + + assert built_from_data(simulation) is False diff --git a/policyengine_uk/utils/data_source.py b/policyengine_uk/utils/data_source.py index e9008e1f91..b26f96b116 100644 --- a/policyengine_uk/utils/data_source.py +++ b/policyengine_uk/utils/data_source.py @@ -7,8 +7,15 @@ def built_from_data(simulation) -> bool: carries little weight and is still data. policyengine_uk.Simulation records it as ``built_from_dataset``, and its builders keep it current. A policyengine-core Simulation built over the UK system records - ``is_over_dataset``, which core's SimulationBuilder leaves set if it later - overwrites that simulation in place with a situation. + ``is_over_dataset``. + + Known limitation in policyengine-core 3.33.2: directly overwriting a + data-built simulation with ``SimulationBuilder.build_from_dict`` leaves + its source flags and dataset unchanged and records no new situation + marker. This helper therefore still returns True for that unsupported + overwrite, its clones and branches, and a UK simulation overwritten by + the core builder. Use UK's ``build_from_situation`` for in-place rebuilds; + it resets the source flag correctly. """ flag = getattr(simulation, "built_from_dataset", None) if flag is None: From cfb0e7279a6a0e429c0a4b9a174c14dc1cd524ac Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 20 Oct 2026 08:26:29 -0400 Subject: [PATCH 5/8] Preserve household CTR and HB while keeping survey take-up reporters-only --- changelog.d/claims-all-per-benunit.fixed.md | 2 +- .../programs/gov/dwp/housing-benefit.ipynb | 2 +- docs/engineering/skills/dataset-sources.md | 14 ++ .../gov/dwp/housing_benefit/takeup.yaml | 8 +- .../housing_benefit/pension_age_premiums.yaml | 2 - ...sion_age_severe_disability_conditions.yaml | 9 - .../pension_credit_carer_income.yaml | 4 - .../claimant_family_scheme.yaml | 29 ---- .../claimant_household_head.yaml | 35 ---- .../council_tax_reduction.yaml | 36 ---- ...l_tax_reduction_carer_support_payment.yaml | 12 -- .../council_tax_reduction_pension_credit.yaml | 24 --- .../council_tax_reduction_pensioner.yaml | 5 - ...eduction_pensioner_earnings_disregard.yaml | 1 - .../ctr_reporters_only.yaml | 104 ------------ .../council_tax_reduction/ctr_takeup.yaml | 156 ++++++++++++++++++ .../joint_liability.yaml | 29 ---- .../integration/entitledto_scenarios.yaml | 1 - ...efit_cap_and_ctr_pension_age_properties.py | 3 - .../test_claims_all_entitled_benefits.py | 141 ++++++++++++++-- ...l_tax_reduction_carer_income_properties.py | 1 - ...ction_claimant_family_scheme_properties.py | 2 - ...uncil_tax_reduction_claimant_properties.py | 1 - ...tax_reduction_pension_credit_properties.py | 4 - ...pensioner_earnings_disregard_properties.py | 1 - ..._benefit_savings_credit_only_properties.py | 12 +- ...ge_severe_disability_premium_properties.py | 5 +- ..._pension_credit_carer_income_properties.py | 5 +- ..._savings_credit_only_receipt_properties.py | 2 - .../would_claim_housing_benefit.py | 15 +- .../would_claim_council_tax_reduction.py | 15 +- .../income/claims_all_entitled_benefits.py | 5 +- 32 files changed, 332 insertions(+), 353 deletions(-) delete mode 100644 policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_reporters_only.yaml create mode 100644 policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_takeup.yaml diff --git a/changelog.d/claims-all-per-benunit.fixed.md b/changelog.d/claims-all-per-benunit.fixed.md index fcd0b133f8..0ad45bcc46 100644 --- a/changelog.d/claims-all-per-benunit.fixed.md +++ b/changelog.d/claims-all-per-benunit.fixed.md @@ -1 +1 @@ -- Evaluate `claims_all_entitled_benefits` per benefit unit, while keeping Council Tax Reduction explicitly limited to reporters by default until calibrated take-up inputs land (policyengine-uk-data#448; d1390). Explicit Council Tax Reduction claim inputs continue to override its default. +- Evaluated `claims_all_entitled_benefits` per benefit unit. Kept main's Council Tax Reduction and Housing Benefit take-up rules for hand-entered households, while limiting data-built defaults to reporters (d1390 and d1455) until calibrated take-up inputs land (policyengine-uk-data#448). Explicit take-up inputs continue to override these defaults. diff --git a/docs/book/programs/gov/dwp/housing-benefit.ipynb b/docs/book/programs/gov/dwp/housing-benefit.ipynb index 277482eaf4..9694aed06a 100644 --- a/docs/book/programs/gov/dwp/housing-benefit.ipynb +++ b/docs/book/programs/gov/dwp/housing-benefit.ipynb @@ -28,7 +28,7 @@ "\n", "**Guarantee Credit passport.** If the claimant or partner is in receipt of a guarantee credit (`in_receipt_of_guarantee_credit`: the benunit is eligible for Pension Credit, claims it, and its guarantee credit is positive, so the Pension Credit paid includes a guarantee credit), the whole of their capital and income is disregarded ([SI 2006/214 reg. 26](https://www.legislation.gov.uk/uksi/2006/214/regulation/26); Northern Ireland: [SR 2006/406 reg. 24](https://www.legislation.gov.uk/nisr/2006/406/regulation/24)). `housing_benefit_assessable_capital`, `housing_benefit_tariff_income` and `housing_benefit_applicable_income` are then zero, so the capital limit cannot bite and no income is tapered. A guarantee credit computed for a family that does not claim Pension Credit (`would_claim_pc`), or that PolicyEngine does not treat as eligible for it (`is_pension_credit_eligible`), does not count. The passport applies within the pension-age regulations (`housing_benefit_pension_age_regulations_apply`). `is_pension_credit_eligible` retains mixed-age couples covered by the [SI 2019/37 art. 4](https://www.legislation.gov.uk/uksi/2019/37/article/4) saving through `meets_pension_credit_age_conditions`; these couples keep the passport when they receive Guarantee Credit. When Pension Credit is frozen, receipt follows the baseline award, including its Guarantee Credit component. Savings Credit alone follows the separate assessment in [reg. 27](https://www.legislation.gov.uk/uksi/2006/214/regulation/27), including its capital limit, and does not give this passport.\n", "\n", - "Take-up is handled by `would_claim_housing_benefit`, which is true for benunits that report Housing Benefit and, when no reported benefits are supplied (as in household calculations), for everyone. In the Enhanced FRS take-up therefore follows reported claims." + "Take-up is handled per benefit unit by `would_claim_housing_benefit`. In data-built simulations, including the Enhanced FRS, its default is true only for families reporting positive Housing Benefit (d1455, following the CTR survey ruling d1390). In hand-entered household calculations, it is true when the family reports Housing Benefit or its `claims_all_entitled_benefits` flag is true. That flag tests seven reported benefits within the family; it does not test Pension Credit, Child Benefit or Council Tax Reduction. Dataset and situation inputs can override the take-up flag directly." ] }, { diff --git a/docs/engineering/skills/dataset-sources.md b/docs/engineering/skills/dataset-sources.md index 6b54e39151..f44da7277e 100644 --- a/docs/engineering/skills/dataset-sources.md +++ b/docs/engineering/skills/dataset-sources.md @@ -60,3 +60,17 @@ without downloading or opening private survey files. Use real H5 files only when the test specifically needs schema or data behavior. If the artifact is private, large, or credential-dependent, skip cleanly or keep the verification outside the ordinary PR test suite. + +## Data provenance and benefit take-up + +`policyengine_uk.utils.data_source.built_from_data` distinguishes dataset-built +simulations from hand-entered situations, including supported clones, branches +and UK `build_from_situation` rebuilds. Council Tax Reduction and Housing Benefit +use this distinction for their take-up defaults: data-built simulations use +positive reported claims only (d1390 and d1455); situations also use their +per-benefit-unit `claims_all_entitled_benefits` flag. Explicit inputs override +these defaults, including a future calibrated dataset column (uk-data#448). + +Do not rebuild an existing data-built simulation by calling core's +`SimulationBuilder.build_from_dict` directly. In core 3.33.2 this leaves stale +dataset provenance, which copies inherit. Use UK `build_from_situation` instead. diff --git a/policyengine_uk/parameters/gov/dwp/housing_benefit/takeup.yaml b/policyengine_uk/parameters/gov/dwp/housing_benefit/takeup.yaml index 26c847e978..74d8d770d4 100644 --- a/policyengine_uk/parameters/gov/dwp/housing_benefit/takeup.yaml +++ b/policyengine_uk/parameters/gov/dwp/housing_benefit/takeup.yaml @@ -1,7 +1,9 @@ description: Share of eligible Housing Benefit recipients that participate. Not used by - the model, which takes Housing Benefit take-up from reported claims in survey data and - assumes full take-up in household calculations. Pension-age families can make new - claims; working-age families only continue existing awards. + the model. Data-built simulations default to positive reported Housing Benefit claims + only (d1455 following d1390). Hand-entered households use positive reported Housing + Benefit or their per-benefit-unit claims_all_entitled_benefits flag. Direct take-up + inputs override either default. Pension-age families can make new claims; + working-age families only continue existing awards. metadata: economy: false label: Housing benefit take-up rate diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_premiums.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_premiums.yaml index 4cfe23e14e..f48a31b1f6 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_premiums.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_premiums.yaml @@ -22,7 +22,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true households: household: members: [claimant] @@ -54,7 +53,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true households: household: members: [claimant] diff --git a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_severe_disability_conditions.yaml b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_severe_disability_conditions.yaml index 1e1e5ab83f..fee4343f7b 100644 --- a/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_severe_disability_conditions.yaml +++ b/policyengine_uk/tests/policy/baseline/finance/benefit/family/housing_benefit/pension_age_severe_disability_conditions.yaml @@ -23,7 +23,6 @@ benunits: pensioners: members: [claimant, partner] - would_claim_council_tax_reduction: true households: household: members: [claimant, partner] @@ -54,7 +53,6 @@ benunits: pensioners: members: [claimant, partner] - would_claim_council_tax_reduction: true households: household: members: [claimant, partner] @@ -87,7 +85,6 @@ benunits: pensioners: members: [claimant, partner] - would_claim_council_tax_reduction: true households: household: members: [claimant, partner] @@ -119,10 +116,8 @@ benunits: pensioner: members: [claimant] - would_claim_council_tax_reduction: true other_family: members: [resident] - would_claim_council_tax_reduction: true households: household: members: [claimant, resident] @@ -158,10 +153,8 @@ benunits: pensioner: members: [claimant] - would_claim_council_tax_reduction: true other_family: members: [daughter, grandson] - would_claim_council_tax_reduction: true households: household: members: [claimant, daughter, grandson] @@ -202,7 +195,6 @@ benunits: pensioner: members: [claimant] - would_claim_council_tax_reduction: true # HB(SPC) reg 55(6) and England CTR Sch 1 para 8(6): AA exempts # the claimant from deductions. Supply these independently of the # current generic deduction formulas to isolate the premium rule. @@ -210,7 +202,6 @@ council_tax_reduction_non_dep_deductions: 0 other_family: members: [carer] - would_claim_council_tax_reduction: true households: household: members: [claimant, carer] diff --git a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_carer_income.yaml b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_carer_income.yaml index 59ddd2f3c3..15ac062765 100644 --- a/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_carer_income.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/dwp/pension_credit/pension_credit_carer_income.yaml @@ -189,11 +189,9 @@ benunits: benunit_1: members: [claimant_1, carer_1] - would_claim_council_tax_reduction: true housing_benefit_applicable_income_disregard: 0 benunit_2: members: [claimant_2, carer_2] - would_claim_council_tax_reduction: true housing_benefit_applicable_income_disregard: 0 households: household_1: @@ -255,11 +253,9 @@ benunits: benunit_1: members: [claimant_1, carer_1] - would_claim_council_tax_reduction: true housing_benefit_applicable_income_disregard: 0 benunit_2: members: [claimant_2, carer_2] - would_claim_council_tax_reduction: true housing_benefit_applicable_income_disregard: 0 households: household_1: diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_family_scheme.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_family_scheme.yaml index 6a42c7c022..793efe1508 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_family_scheme.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_family_scheme.yaml @@ -23,12 +23,10 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false # 500 a week. @@ -67,12 +65,10 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 26_000 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 15_000 @@ -114,18 +110,15 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 0 son_family: members: [adult_son] - would_claim_council_tax_reduction: true would_claim_uc: false households: home: @@ -164,7 +157,6 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 sharer_family: @@ -207,7 +199,6 @@ council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 0 @@ -241,7 +232,6 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 child_family: @@ -312,7 +302,6 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 sharer_family: @@ -436,12 +425,10 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 15_000 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 8_000 @@ -480,12 +467,10 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 8_000 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 15_000 @@ -520,12 +505,10 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 15_000 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 8_000 @@ -560,12 +543,10 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 8_000 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 15_000 @@ -609,7 +590,6 @@ benunits: family: members: [grandmother, young_mother, young_father, baby] - would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 households: @@ -682,7 +662,6 @@ would_claim_uc: false sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false households: @@ -764,7 +743,6 @@ would_claim_uc: false sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false # Too much income for any reduction. @@ -813,13 +791,11 @@ council_tax_reduction_applicable_income: 0 student_family: members: [student] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 0 pensioner_family: members: [pensioner] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 0 @@ -861,13 +837,11 @@ council_tax_reduction_applicable_income: 0 student_family: members: [student] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 0 pensioner_family: members: [pensioner] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true would_claim_uc: false council_tax_reduction_applicable_income: 0 @@ -903,7 +877,6 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 sharer_family: @@ -939,7 +912,6 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true would_claim_uc: false council_tax_reduction_applicable_income: 0 sharer_family: @@ -984,7 +956,6 @@ benunits: family: members: [grandmother, young_mother, young_father, baby] - would_claim_council_tax_reduction: true would_claim_uc: false income_support: 3_000 council_tax_reduction_applicable_income: 0 diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_household_head.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_household_head.yaml index 99dbd0b390..78dfcecba1 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_household_head.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/claimant_household_head.yaml @@ -25,11 +25,9 @@ benunits: friend_family: members: [friend] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 householder_family: members: [householder] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 households: home: @@ -60,11 +58,9 @@ benunits: first_family: members: [first] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 second_family: members: [second] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 households: home: @@ -95,11 +91,9 @@ benunits: householder_family: members: [householder] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 friend_family: members: [friend] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 households: home: @@ -127,12 +121,10 @@ benunits: friend_family: members: [friend] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true householder_family: members: [householder] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -164,12 +156,10 @@ benunits: householder_family: members: [householder] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true friend_family: members: [friend] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -199,12 +189,10 @@ benunits: householder_family: members: [householder] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true friend_family: members: [friend] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -234,12 +222,10 @@ benunits: householder_family: members: [householder] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true friend_family: members: [friend] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -269,12 +255,10 @@ benunits: householder_family: members: [householder] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true friend_family: members: [friend] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -305,11 +289,9 @@ benunits: householder_family: members: [householder] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 parent_family: members: [parent] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 households: home: @@ -345,11 +327,9 @@ benunits: householder_family: members: [householder] - would_claim_council_tax_reduction: true would_claim_uc: false parent_family: members: [parent] - would_claim_council_tax_reduction: true households: home: members: [householder, parent] @@ -445,11 +425,9 @@ benunits: householder_family: members: [householder] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 households: @@ -488,16 +466,13 @@ benunits: eldest_family: members: [eldest] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 other_family: members: [other_adult] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 households: home: @@ -533,15 +508,12 @@ benunits: older_family: members: [older_flagged] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 younger_family: members: [younger_flagged] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 households: @@ -577,11 +549,9 @@ benunits: householder_family: members: [householder] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 child_family: members: [child_sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 households: @@ -614,11 +584,9 @@ benunits: householder_family: members: [householder] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 young_family: members: [young_sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 households: @@ -657,7 +625,6 @@ benunits: family: members: [grandmother, young_mother, young_father, baby] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 households: home: @@ -729,10 +696,8 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true cotenant_family: members: [cotenant] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 households: diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction.yaml index fb8ce71b34..daaec21e26 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction.yaml @@ -82,7 +82,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true households: household: members: [claimant] @@ -105,7 +104,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -160,12 +158,10 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] - would_claim_council_tax_reduction: true households: household: members: [claimant, non_dep] @@ -190,12 +186,10 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] - would_claim_council_tax_reduction: true would_claim_uc: true households: household: @@ -217,7 +211,6 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_maximum_amount: 5_000 @@ -245,7 +238,6 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_reported_capital: 0 @@ -270,7 +262,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -321,7 +312,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true council_tax_reduction_applicable_amount: 0 @@ -352,12 +342,10 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] - would_claim_council_tax_reduction: true households: household: members: [claimant, non_dep] @@ -379,7 +367,6 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_maximum_amount: 5_000 @@ -407,7 +394,6 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_reported_capital: 0 @@ -432,7 +418,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -483,7 +468,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true council_tax_reduction_applicable_amount: 10_000 @@ -515,12 +499,10 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] - would_claim_council_tax_reduction: true households: household: members: [claimant, non_dep] @@ -546,12 +528,10 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] - would_claim_council_tax_reduction: true households: household: members: [claimant, non_dep] @@ -572,7 +552,6 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_reported_capital: 0 @@ -597,7 +576,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -648,7 +626,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true council_tax_reduction_applicable_amount: 0 @@ -680,12 +657,10 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] - would_claim_council_tax_reduction: true households: household: members: [claimant, non_dep] @@ -707,7 +682,6 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_maximum_amount: 5_000 @@ -735,7 +709,6 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_reported_capital: 0 @@ -760,7 +733,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true households: @@ -785,7 +757,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true council_tax_reduction_applicable_income: 25_001 @@ -809,7 +780,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true council_tax_reduction_applicable_income: 25_200 @@ -834,7 +804,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true council_tax_reduction_applicable_income: 24_960 @@ -858,7 +827,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: true claims_all_entitled_benefits: true uc_maximum_amount: 24_960 @@ -913,12 +881,10 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] - would_claim_council_tax_reduction: true households: household: members: [claimant, non_dep] @@ -941,12 +907,10 @@ benunits: claimant_benunit: members: [claimant] - would_claim_council_tax_reduction: true would_claim_uc: false claims_all_entitled_benefits: true non_dep_benunit: members: [non_dep] - would_claim_council_tax_reduction: true income_support: 1 households: household: diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_carer_support_payment.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_carer_support_payment.yaml index c499ed3770..186b79ccc3 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_carer_support_payment.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_carer_support_payment.yaml @@ -40,7 +40,6 @@ benunits: benunit: members: [carer] - would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -76,7 +75,6 @@ benunits: benunit: members: [carer] - would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -102,7 +100,6 @@ benunits: benunit: members: [carer] - would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -131,7 +128,6 @@ benunits: benunit: members: [carer] - would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -175,7 +171,6 @@ benunits: benunit: members: [carer] - would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -208,7 +203,6 @@ benunits: benunit: members: [carer] - would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -238,7 +232,6 @@ benunits: benunit: members: [carer] - would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -268,7 +261,6 @@ benunits: benunit: members: [carer] - would_claim_council_tax_reduction: true households: household: members: [carer] @@ -308,7 +300,6 @@ benunits: benunit: members: [claimant, partner] - would_claim_council_tax_reduction: true households: household: members: [claimant, partner] @@ -360,7 +351,6 @@ benunits: benunit: members: [claimant, partner] - would_claim_council_tax_reduction: true is_married: false households: household: @@ -403,7 +393,6 @@ benunits: benunit: members: [claimant, partner] - would_claim_council_tax_reduction: true households: household: members: [claimant, partner] @@ -434,7 +423,6 @@ benunits: benunit: members: [carer] - would_claim_council_tax_reduction: true households: household: members: [carer] diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pension_credit.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pension_credit.yaml index 884c2dd1be..e07ff2f6f8 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pension_credit.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pension_credit.yaml @@ -23,7 +23,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true minimum_guarantee: 18_500 households: @@ -56,7 +55,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true minimum_guarantee: 18_500 households: @@ -85,7 +83,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true minimum_guarantee: 18_500 would_claim_pc: false @@ -116,7 +113,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -144,7 +140,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -173,7 +168,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true would_claim_pc: false households: @@ -204,7 +198,6 @@ benunits: benunit: members: [claimant, partner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -233,11 +226,9 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true son_benunit: members: [son] - would_claim_council_tax_reduction: true would_claim_uc: false households: household: @@ -276,7 +267,6 @@ benunits: benunit: members: [claimant, partner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true would_claim_uc: false households: @@ -305,7 +295,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -330,7 +319,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true minimum_guarantee: 18_500 households: @@ -357,7 +345,6 @@ benunits: benunit: members: [claimant] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true would_claim_uc: false households: @@ -386,7 +373,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -411,7 +397,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true minimum_guarantee: 18_500 households: @@ -439,7 +424,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -471,7 +455,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -503,7 +486,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true would_claim_pc: false households: @@ -536,7 +518,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -566,7 +547,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -592,7 +572,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -624,7 +603,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -666,7 +644,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: @@ -706,7 +683,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner.yaml index 4438cea174..f19bc2277c 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner.yaml @@ -131,7 +131,6 @@ benunits: benunit: members: [older, younger] - would_claim_council_tax_reduction: true universal_credit_pre_benefit_cap: 10_000 households: household: @@ -166,11 +165,9 @@ benunits: couple: members: [older, younger] - would_claim_council_tax_reduction: true universal_credit_pre_benefit_cap: 10_000 son: members: [son] - would_claim_council_tax_reduction: true households: household: members: [older, younger, son] @@ -231,7 +228,6 @@ benunits: benunit: members: [pensioner, young_person] - would_claim_council_tax_reduction: true households: household: members: [pensioner, young_person] @@ -322,7 +318,6 @@ benunits: benunit: members: [older, younger, child] - would_claim_council_tax_reduction: true universal_credit_pre_benefit_cap: 30_000 child_benefit: 3_000 uc_deductions: 0 diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner_earnings_disregard.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner_earnings_disregard.yaml index 0ca538b7be..c077000081 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner_earnings_disregard.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/council_tax_reduction_pensioner_earnings_disregard.yaml @@ -430,7 +430,6 @@ benunits: benunit: members: [pensioner] - would_claim_council_tax_reduction: true claims_all_entitled_benefits: true households: household: diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_reporters_only.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_reporters_only.yaml deleted file mode 100644 index d787334607..0000000000 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_reporters_only.yaml +++ /dev/null @@ -1,104 +0,0 @@ -- name: WALES entitled non-reporting family under default reporters-only - period: 2026 - input: - age: 35 - country: WALES - local_authority: CARDIFF - council_tax: 1800 - savings: 0 - would_claim_uc: false - claims_all_entitled_benefits: true - output: - council_tax_benefit_reported: 0 - would_claim_council_tax_reduction: false - simulated_council_tax_reduction_benunit: 0 - council_tax_benefit: 0 - council_tax_reduction: 0 - -- name: WALES entitled non-reporting family under explicit CTR claim - period: 2026 - input: - age: 35 - country: WALES - local_authority: CARDIFF - council_tax: 1800 - savings: 0 - would_claim_uc: false - claims_all_entitled_benefits: true - would_claim_council_tax_reduction: true - output: - council_tax_benefit_reported: 0 - would_claim_council_tax_reduction: true - simulated_council_tax_reduction_benunit: 1800 - council_tax_benefit: 1800 - council_tax_reduction: 1800 - -- name: SCOTLAND entitled non-reporting family under default reporters-only - period: 2026 - input: - age: 35 - country: SCOTLAND - local_authority: CITY_OF_EDINBURGH - council_tax: 1800 - savings: 0 - would_claim_uc: false - claims_all_entitled_benefits: true - output: - council_tax_benefit_reported: 0 - would_claim_council_tax_reduction: false - simulated_council_tax_reduction_benunit: 0 - council_tax_benefit: 0 - council_tax_reduction: 0 - -- name: SCOTLAND entitled non-reporting family under explicit CTR claim - period: 2026 - input: - age: 35 - country: SCOTLAND - local_authority: CITY_OF_EDINBURGH - council_tax: 1800 - savings: 0 - would_claim_uc: false - claims_all_entitled_benefits: true - would_claim_council_tax_reduction: true - output: - council_tax_benefit_reported: 0 - would_claim_council_tax_reduction: true - simulated_council_tax_reduction_benunit: 1800 - council_tax_benefit: 1800 - council_tax_reduction: 1800 - -- name: ENGLAND entitled non-reporting family under default reporters-only - period: 2026 - input: - age: 70 - country: ENGLAND - local_authority: MAIDSTONE - council_tax: 1800 - savings: 0 - would_claim_uc: false - claims_all_entitled_benefits: true - output: - council_tax_benefit_reported: 0 - would_claim_council_tax_reduction: false - simulated_council_tax_reduction_benunit: 0 - council_tax_benefit: 0 - council_tax_reduction: 0 - -- name: ENGLAND entitled non-reporting family under explicit CTR claim - period: 2026 - input: - age: 70 - country: ENGLAND - local_authority: MAIDSTONE - council_tax: 1800 - savings: 0 - would_claim_uc: false - claims_all_entitled_benefits: true - would_claim_council_tax_reduction: true - output: - council_tax_benefit_reported: 0 - would_claim_council_tax_reduction: true - simulated_council_tax_reduction_benunit: 1800 - council_tax_benefit: 1800 - council_tax_reduction: 1800 diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_takeup.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_takeup.yaml new file mode 100644 index 0000000000..be3dbcbc9c --- /dev/null +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/ctr_takeup.yaml @@ -0,0 +1,156 @@ +# Hand-entered households retain the default and explicit take-up rules. +# Survey reporters-only behavior is covered with MOCK data in Python tests. +- name: WALES entitled non-reporting family entered by hand claims CTR by default + period: 2026 + input: + age: 35 + country: WALES + local_authority: CARDIFF + council_tax: 1800 + savings: 0 + would_claim_uc: false + claims_all_entitled_benefits: true + output: + council_tax_benefit_reported: 0 + would_claim_council_tax_reduction: true + simulated_council_tax_reduction_benunit: 1800 + council_tax_benefit: 1800 + council_tax_reduction: 1800 + +- name: WALES entitled non-reporting family under explicit CTR claim + period: 2026 + input: + age: 35 + country: WALES + local_authority: CARDIFF + council_tax: 1800 + savings: 0 + would_claim_uc: false + claims_all_entitled_benefits: true + would_claim_council_tax_reduction: true + output: + council_tax_benefit_reported: 0 + would_claim_council_tax_reduction: true + simulated_council_tax_reduction_benunit: 1800 + council_tax_benefit: 1800 + council_tax_reduction: 1800 + +- name: SCOTLAND entitled non-reporting family entered by hand claims CTR by default + period: 2026 + input: + age: 35 + country: SCOTLAND + local_authority: CITY_OF_EDINBURGH + council_tax: 1800 + savings: 0 + would_claim_uc: false + claims_all_entitled_benefits: true + output: + council_tax_benefit_reported: 0 + would_claim_council_tax_reduction: true + simulated_council_tax_reduction_benunit: 1800 + council_tax_benefit: 1800 + council_tax_reduction: 1800 + +- name: SCOTLAND entitled non-reporting family under explicit CTR claim + period: 2026 + input: + age: 35 + country: SCOTLAND + local_authority: CITY_OF_EDINBURGH + council_tax: 1800 + savings: 0 + would_claim_uc: false + claims_all_entitled_benefits: true + would_claim_council_tax_reduction: true + output: + council_tax_benefit_reported: 0 + would_claim_council_tax_reduction: true + simulated_council_tax_reduction_benunit: 1800 + council_tax_benefit: 1800 + council_tax_reduction: 1800 + +- name: ENGLAND entitled non-reporting family entered by hand claims CTR by default + period: 2026 + input: + age: 70 + country: ENGLAND + local_authority: MAIDSTONE + council_tax: 1800 + savings: 0 + would_claim_uc: false + claims_all_entitled_benefits: true + output: + council_tax_benefit_reported: 0 + would_claim_council_tax_reduction: true + simulated_council_tax_reduction_benunit: 1800 + council_tax_benefit: 1800 + council_tax_reduction: 1800 + +- name: ENGLAND entitled non-reporting family under explicit CTR claim + period: 2026 + input: + age: 70 + country: ENGLAND + local_authority: MAIDSTONE + council_tax: 1800 + savings: 0 + would_claim_uc: false + claims_all_entitled_benefits: true + would_claim_council_tax_reduction: true + output: + council_tax_benefit_reported: 0 + would_claim_council_tax_reduction: true + simulated_council_tax_reduction_benunit: 1800 + council_tax_benefit: 1800 + council_tax_reduction: 1800 + +# Vahid's calculator probes from PR 1831 review 5514292316. These households +# supply no benefit reports, claimant roles, or take-up inputs. +- name: North West pensioner calculator household retains full CTR without reports + period: 2026 + absolute_error_margin: 0.01 + input: + age: 70 + region: NORTH_WEST + rent: 8_000 + tenure_type: RENT_PRIVATELY + council_tax: 1_800 + employment_income: 0 + output: + council_tax_benefit_reported: 0 + claims_all_entitled_benefits: true + would_claim_council_tax_reduction: true + council_tax_reduction: 1_800 + +- name: Welsh pensioner calculator household retains full CTR without reports + period: 2026 + absolute_error_margin: 0.01 + input: + age: 70 + region: WALES + rent: 8_000 + tenure_type: RENT_PRIVATELY + council_tax: 1_800 + employment_income: 0 + output: + council_tax_benefit_reported: 0 + claims_all_entitled_benefits: true + would_claim_council_tax_reduction: true + council_tax_reduction: 1_800 + +- name: Scottish working-age calculator household retains CTR without reports + period: 2026 + absolute_error_margin: 0.01 + input: + age: 30 + region: SCOTLAND + rent: 8_000 + tenure_type: RENT_PRIVATELY + council_tax: 1_800 + employment_income: 0 + output: + council_tax_benefit_reported: 0 + claims_all_entitled_benefits: true + would_claim_council_tax_reduction: true + council_tax_reduction: 633.96 diff --git a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/joint_liability.yaml b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/joint_liability.yaml index 1c76f31290..b6a6a07a24 100644 --- a/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/joint_liability.yaml +++ b/policyengine_uk/tests/policy/baseline/gov/local_authorities/council_tax_reduction/joint_liability.yaml @@ -24,21 +24,17 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_1_family: members: [sharer_1] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 sharer_2_family: members: [sharer_2] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 son_family: members: [adult_son] - would_claim_council_tax_reduction: true households: home: members: [head, sharer_1, sharer_2, adult_son] @@ -73,11 +69,9 @@ benunits: couple: members: [head, partner] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 households: @@ -111,11 +105,9 @@ benunits: couple: members: [head, partner] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 son_family: members: [adult_son] - would_claim_council_tax_reduction: true households: home: members: [head, partner, adult_son] @@ -145,11 +137,9 @@ benunits: householder_family: members: [householder] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 lodger_family: members: [lodger] - would_claim_council_tax_reduction: true households: home: members: [householder, lodger] @@ -180,10 +170,8 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true father_family: members: [father] - would_claim_council_tax_reduction: true households: home: members: [head, father] @@ -219,16 +207,13 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 cotenant_family: members: [cotenant] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 father_family: members: [father] - would_claim_council_tax_reduction: true households: home: members: [head, cotenant, father] @@ -259,11 +244,9 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 student_family: members: [student] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true households: home: @@ -294,11 +277,9 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 households: @@ -339,10 +320,8 @@ benunits: couple: members: [head, partner] - would_claim_council_tax_reduction: true sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true households: home: @@ -384,10 +363,8 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true couple: members: [sharer, sharer_partner] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true households: home: @@ -424,16 +401,13 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 non_dependant_family: members: [non_dependant] - would_claim_council_tax_reduction: true households: home: members: [head, sharer, non_dependant] @@ -472,16 +446,13 @@ benunits: head_family: members: [head] - would_claim_council_tax_reduction: true council_tax_reduction_applicable_income: 0 sharer_family: members: [sharer] - would_claim_council_tax_reduction: true liable_for_share_of_household_rent: true council_tax_reduction_applicable_income: 0 non_dependant_family: members: [non_dependant] - would_claim_council_tax_reduction: true households: home: members: [head, sharer, non_dependant] diff --git a/policyengine_uk/tests/policy/integration/entitledto_scenarios.yaml b/policyengine_uk/tests/policy/integration/entitledto_scenarios.yaml index 07e5cb315d..41c2963f3d 100644 --- a/policyengine_uk/tests/policy/integration/entitledto_scenarios.yaml +++ b/policyengine_uk/tests/policy/integration/entitledto_scenarios.yaml @@ -93,7 +93,6 @@ benunits: benunit: members: [pensioner_1, pensioner_2] - would_claim_council_tax_reduction: true households: household: members: [pensioner_1, pensioner_2] diff --git a/policyengine_uk/tests/test_benefit_cap_and_ctr_pension_age_properties.py b/policyengine_uk/tests/test_benefit_cap_and_ctr_pension_age_properties.py index 94018f4828..298b11d1ee 100644 --- a/policyengine_uk/tests/test_benefit_cap_and_ctr_pension_age_properties.py +++ b/policyengine_uk/tests/test_benefit_cap_and_ctr_pension_age_properties.py @@ -220,9 +220,6 @@ def situation(units): benunit = { "members": names, "would_claim_uc": {PERIOD: unit["would_claim_uc"]}, - "would_claim_council_tax_reduction": { - PERIOD: unit["hb_reported"] == 0 or unit["ctb_reported"] > 0 - }, "claims_all_entitled_benefits": { PERIOD: unit["hb_reported"] == 0 and unit["ctb_reported"] == 0 }, diff --git a/policyengine_uk/tests/test_claims_all_entitled_benefits.py b/policyengine_uk/tests/test_claims_all_entitled_benefits.py index 947a237808..22f646f676 100644 --- a/policyengine_uk/tests/test_claims_all_entitled_benefits.py +++ b/policyengine_uk/tests/test_claims_all_entitled_benefits.py @@ -7,15 +7,17 @@ simulation (`add(...).sum() < 1`), so in microdata it was False for every benefit unit as soon as any benefit unit reported any of them, and the consumers that gate on it collapsed to reporters only. Council Tax Reduction -now has its own explicit reporters-only default until calibrated data take-up -lands (uk-data#448; d1390). +and Housing Benefit have reporters-only defaults on data-built simulations +(d1390 and d1455); hand-entered situations keep the per-family flag. """ import numpy as np +import pandas as pd import pytest from hypothesis import example, given, settings, strategies as st from policyengine_uk import Microsimulation, Simulation +from policyengine_uk.data import UKMultiYearDataset, UKSingleYearDataset pytestmark = pytest.mark.usefixtures("cloned_uk_tax_benefit_system") @@ -78,10 +80,10 @@ def test_per_benefit_unit_within_one_household(self): flag = sim.calculate("claims_all_entitled_benefits", YEAR) assert flag.tolist() == [False, True] - def test_ctr_default_does_not_follow_the_all_benefits_flag(self): + def test_situation_ctr_default_follows_each_familys_flag(self): sim = Simulation(situation=separate_households(5_000, 0)) would_claim = sim.calculate("would_claim_council_tax_reduction", YEAR) - assert would_claim.tolist() == [False, False] + assert would_claim.tolist() == [False, True] def test_reported_ctr_still_claims_when_the_flag_is_false(self): situation = separate_households(5_000, 0) @@ -93,7 +95,7 @@ def test_reported_ctr_still_claims_when_the_flag_is_false(self): ] assert sim.calculate("would_claim_council_tax_reduction", YEAR).tolist() == [ True, - False, + True, ] def test_reporters_of_any_of_the_seven_are_false(self): @@ -140,8 +142,118 @@ def test_flag_is_evaluated_per_benefit_unit_in_microdata(): assert flag.any() and (~flag).any() +def mock_dataset(situation): + """Synthetic post-ingestion MOCK tables using the normal UK data schema.""" + tables = {} + person_ids = {name: i + 1 for i, name in enumerate(situation["people"])} + memberships = {} + for plural, entity in ( + ("people", "person"), + ("benunits", "benunit"), + ("households", "household"), + ): + rows = [] + for index, (_, inputs) in enumerate(situation[plural].items(), start=1): + row = {f"{entity}_id": index} + for name, value in inputs.items(): + if name == "members": + for member in value: + memberships.setdefault(person_ids[member], {})[ + f"person_{entity}_id" + ] = index + else: + row[name] = value[YEAR] if isinstance(value, dict) else value + rows.append(row) + tables[entity] = pd.DataFrame(rows).fillna(0) + for column in ("person_benunit_id", "person_household_id"): + tables["person"][column] = [ + memberships[person_id][column] for person_id in person_ids.values() + ] + return UKMultiYearDataset( + datasets=[UKSingleYearDataset(**tables, fiscal_year=YEAR)] + ) + + +def pensioner_households(): + situation = separate_households(0, 0) + for person_inputs in situation["people"].values(): + person_inputs["age"] = {YEAR: 70} + for home in situation["households"].values(): + home.update( + region={YEAR: "NORTH_WEST"}, + tenure_type={YEAR: "RENT_PRIVATELY"}, + rent={YEAR: 8_000}, + council_tax={YEAR: 1_800}, + ) + return situation + + +@pytest.mark.parametrize("simulation_class", [Simulation, Microsimulation]) +@pytest.mark.parametrize( + "takeup, reported, benefit, expected_award", + [ + ( + "would_claim_council_tax_reduction", + "council_tax_benefit_reported", + "council_tax_reduction", + 1_800, + ), + ( + "would_claim_housing_benefit", + "housing_benefit_reported", + "housing_benefit", + 8_000, + ), + ], +) +def test_mock_data_takeup_is_reporters_only( + simulation_class, takeup, reported, benefit, expected_award +): + situation = pensioner_households() + situation["people"]["b"][reported] = {YEAR: 100} + simulation = simulation_class(dataset=mock_dataset(situation)) + assert simulation.calculate(takeup, YEAR).tolist() == [False, True] + np.testing.assert_allclose(simulation.calculate(benefit, YEAR), [0, expected_award]) + # The non-reporter is entitled: an explicit input enables its award. + for family in situation["benunits"].values(): + family[takeup] = {YEAR: True} + explicit = simulation_class(dataset=mock_dataset(situation)) + np.testing.assert_allclose( + explicit.calculate(benefit, YEAR), [expected_award, expected_award] + ) + + +def test_hand_entered_housing_benefit_keeps_main_takeup(): + simulation = Simulation(situation=pensioner_households()) + assert simulation.calculate("would_claim_housing_benefit", YEAR).tolist() == [ + True, + True, + ] + np.testing.assert_allclose( + simulation.calculate("housing_benefit", YEAR), [8_000, 8_000] + ) + + +@pytest.mark.parametrize( + "reported", + [ + "pension_credit_reported", + "child_benefit_reported", + "council_tax_benefit_reported", + ], +) +def test_reports_outside_the_seven_leave_the_all_benefits_flag_true(reported): + situation = separate_households(0, 0) + situation["people"]["a"][reported] = {YEAR: 100} + simulation = Simulation(situation=situation) + assert simulation.calculate("claims_all_entitled_benefits", YEAR).tolist() == [ + True, + True, + ] + + # Each generated family is independently eligible or ineligible and may have -# reported CTR or an explicit take-up input. Other families cannot enable it. +# reported CTR. No explicit take-up column is supplied; other families cannot enable it. CTR_FAMILIES = st.lists( st.tuples( st.integers(min_value=18, max_value=90), @@ -149,7 +261,6 @@ def test_flag_is_evaluated_per_benefit_unit_in_microdata(): st.integers(min_value=0, max_value=50_000), st.integers(min_value=0, max_value=50_000), st.booleans(), - st.sampled_from((None, False, True)), st.sampled_from((0, 100)), ), min_size=1, @@ -158,12 +269,12 @@ def test_flag_is_evaluated_per_benefit_unit_in_microdata(): @given(families=CTR_FAMILIES) -@example(families=[(40, "SCOTLAND", 0, 0, True, None, 0)]) +@example(families=[(40, "SCOTLAND", 0, 0, True, 0)]) @example( families=[ - (40, "WALES", 0, 0, True, None, 0), - (40, "WALES", 0, 0, True, True, 0), - (70, "ENGLAND", 0, 0, False, None, 100), + (40, "WALES", 0, 0, True, 0), + (40, "WALES", 0, 0, True, 100), + (70, "ENGLAND", 0, 0, False, 100), ] ) @settings(max_examples=30, deadline=None) @@ -175,7 +286,7 @@ def test_ctr_is_zero_for_every_nonreporter_without_an_explicit_claim_flag(famili "SCOTLAND": "CITY_OF_EDINBURGH", "WALES": "CARDIFF", } - for index, (age, country, income, savings, claims_all, flag, reported) in enumerate( + for index, (age, country, income, savings, claims_all, reported) in enumerate( families ): name = f"person_{index}" @@ -189,8 +300,6 @@ def test_ctr_is_zero_for_every_nonreporter_without_an_explicit_claim_flag(famili "claims_all_entitled_benefits": {YEAR: claims_all}, "would_claim_uc": {YEAR: False}, } - if flag is not None: - benunit["would_claim_council_tax_reduction"] = {YEAR: flag} situation["benunits"][f"bu_{index}"] = benunit situation["households"][f"hh_{index}"] = { "members": [name], @@ -199,8 +308,8 @@ def test_ctr_is_zero_for_every_nonreporter_without_an_explicit_claim_flag(famili "council_tax": {YEAR: 1_800}, "savings": {YEAR: savings}, } - must_be_zero.append(reported == 0 and flag is not True) - sim = Simulation(situation=situation) + must_be_zero.append(reported == 0) + sim = Simulation(dataset=mock_dataset(situation)) mask = np.array(must_be_zero, dtype=bool) assert not sim.calculate("would_claim_council_tax_reduction", YEAR)[mask].any() for variable in ( diff --git a/policyengine_uk/tests/test_council_tax_reduction_carer_income_properties.py b/policyengine_uk/tests/test_council_tax_reduction_carer_income_properties.py index ddcbcde9e4..e317bf68e5 100644 --- a/policyengine_uk/tests/test_council_tax_reduction_carer_income_properties.py +++ b/policyengine_uk/tests/test_council_tax_reduction_carer_income_properties.py @@ -208,7 +208,6 @@ def situation(families): benunits[f"b{i}_{k}_{c}"] = { "members": names, "would_claim_uc": {YEAR: False}, - "would_claim_council_tax_reduction": {YEAR: True}, } households[f"h{i}_{k}_{c}"] = { "members": names, diff --git a/policyengine_uk/tests/test_council_tax_reduction_claimant_family_scheme_properties.py b/policyengine_uk/tests/test_council_tax_reduction_claimant_family_scheme_properties.py index 4b10b241b0..9849322beb 100644 --- a/policyengine_uk/tests/test_council_tax_reduction_claimant_family_scheme_properties.py +++ b/policyengine_uk/tests/test_council_tax_reduction_claimant_family_scheme_properties.py @@ -268,7 +268,6 @@ def build(population, alone=False, perturb_others=False, awards=None): "liable_for_share_of_household_rent": fam["role"] == "sharer" and not alone, "claims_all_entitled_benefits": True, - "would_claim_council_tax_reduction": True, "would_claim_uc": True, } if awards is not None: @@ -619,7 +618,6 @@ def council_situation(homes, with_disability): "members": [pid], "liable_for_share_of_household_rent": f == 1, "claims_all_entitled_benefits": True, - "would_claim_council_tax_reduction": True, "would_claim_uc": False, } ids.append(pid) diff --git a/policyengine_uk/tests/test_council_tax_reduction_claimant_properties.py b/policyengine_uk/tests/test_council_tax_reduction_claimant_properties.py index 4a82a8c483..6424555e09 100644 --- a/policyengine_uk/tests/test_council_tax_reduction_claimant_properties.py +++ b/policyengine_uk/tests/test_council_tax_reduction_claimant_properties.py @@ -192,7 +192,6 @@ def build(population, age_override=None): "members": ids, "liable_for_share_of_household_rent": fam["sharer"] and f > 0, "claims_all_entitled_benefits": True, - "would_claim_council_tax_reduction": True, "would_claim_uc": True, } members.extend(ids) diff --git a/policyengine_uk/tests/test_council_tax_reduction_pension_credit_properties.py b/policyengine_uk/tests/test_council_tax_reduction_pension_credit_properties.py index 61dd8e6ccc..8de7c8e4cd 100644 --- a/policyengine_uk/tests/test_council_tax_reduction_pension_credit_properties.py +++ b/policyengine_uk/tests/test_council_tax_reduction_pension_credit_properties.py @@ -207,7 +207,6 @@ def situation( benunit = { "members": names, "claims_all_entitled_benefits": {YEAR: True}, - "would_claim_council_tax_reduction": {YEAR: True}, "would_claim_pc": {YEAR: claim_pc}, "would_claim_uc": {YEAR: unit.get("would_claim_uc", False)}, } @@ -226,7 +225,6 @@ def situation( benunits[f"n{i}"] = { "members": [name], "claims_all_entitled_benefits": {YEAR: True}, - "would_claim_council_tax_reduction": {YEAR: True}, "would_claim_uc": {YEAR: False}, } benunit_index += 1 @@ -532,7 +530,6 @@ def test_savings_credit_only_award_counts_the_frozen_savings_credit(): "benunit": { "members": ["pensioner"], "claims_all_entitled_benefits": {YEAR: True}, - "would_claim_council_tax_reduction": {YEAR: True}, } }, "households": { @@ -579,7 +576,6 @@ def freeze_case(age, state_pension, private_pension, savings, reform): "benunit": { "members": ["pensioner"], "claims_all_entitled_benefits": {YEAR: True}, - "would_claim_council_tax_reduction": {YEAR: True}, } }, "households": { diff --git a/policyengine_uk/tests/test_council_tax_reduction_pensioner_earnings_disregard_properties.py b/policyengine_uk/tests/test_council_tax_reduction_pensioner_earnings_disregard_properties.py index 248f755484..0db11ccbd2 100644 --- a/policyengine_uk/tests/test_council_tax_reduction_pensioner_earnings_disregard_properties.py +++ b/policyengine_uk/tests/test_council_tax_reduction_pensioner_earnings_disregard_properties.py @@ -126,7 +126,6 @@ def situation(units, year, earnings_bump=0.0, no_income_related_benefits=False): benunits[f"b{i}"] = { "members": names, "claims_all_entitled_benefits": {year: True}, - "would_claim_council_tax_reduction": {year: True}, } if no_income_related_benefits: for benefit in ("income_support", "jsa_income", "esa_income"): diff --git a/policyengine_uk/tests/test_housing_benefit_savings_credit_only_properties.py b/policyengine_uk/tests/test_housing_benefit_savings_credit_only_properties.py index d3e80d7b14..6d19738615 100644 --- a/policyengine_uk/tests/test_housing_benefit_savings_credit_only_properties.py +++ b/policyengine_uk/tests/test_housing_benefit_savings_credit_only_properties.py @@ -136,10 +136,7 @@ def situation(families): person[variable] = {YEAR: value} people[name] = person names.append(name) - benunits[f"b{i}_{k}"] = { - "members": names, - "would_claim_council_tax_reduction": {YEAR: True}, - } + benunits[f"b{i}_{k}"] = {"members": names} households[f"h{i}_{k}"] = { "members": names, "country": {YEAR: fam["country"]}, @@ -289,12 +286,7 @@ def test_income_follows_the_route_for_the_award(families): def single_pensioner(**person): return { "people": {"pensioner": person}, - "benunits": { - "benunit": { - "members": ["pensioner"], - "would_claim_council_tax_reduction": {YEAR: True}, - } - }, + "benunits": {"benunit": {"members": ["pensioner"]}}, "households": { "household": { "members": ["pensioner"], diff --git a/policyengine_uk/tests/test_pension_age_severe_disability_premium_properties.py b/policyengine_uk/tests/test_pension_age_severe_disability_premium_properties.py index db7a77dff7..a0deb726ef 100644 --- a/policyengine_uk/tests/test_pension_age_severe_disability_premium_properties.py +++ b/policyengine_uk/tests/test_pension_age_severe_disability_premium_properties.py @@ -116,10 +116,7 @@ def situation(families): person[variable] = {YEAR: value} people[name] = person names.append(name) - benunits[f"b{i}_{k}"] = { - "members": names, - "would_claim_council_tax_reduction": {YEAR: True}, - } + benunits[f"b{i}_{k}"] = {"members": names} households[f"h{i}_{k}"] = { "members": names, "country": {YEAR: "ENGLAND"}, diff --git a/policyengine_uk/tests/test_pension_credit_carer_income_properties.py b/policyengine_uk/tests/test_pension_credit_carer_income_properties.py index af48f85d76..b0d4fcf75c 100644 --- a/policyengine_uk/tests/test_pension_credit_carer_income_properties.py +++ b/policyengine_uk/tests/test_pension_credit_carer_income_properties.py @@ -156,10 +156,7 @@ def situation(families): person["carers_allowance_reported"] = {YEAR: 1} people[name] = person names.append(name) - benunits[f"b{i}_{k}"] = { - "members": names, - "would_claim_council_tax_reduction": {YEAR: True}, - } + benunits[f"b{i}_{k}"] = {"members": names} households[f"h{i}_{k}"] = { "members": names, "country": {YEAR: fam["country"]}, diff --git a/policyengine_uk/tests/test_savings_credit_only_receipt_properties.py b/policyengine_uk/tests/test_savings_credit_only_receipt_properties.py index f7a735f6c9..98d8f646c7 100644 --- a/policyengine_uk/tests/test_savings_credit_only_receipt_properties.py +++ b/policyengine_uk/tests/test_savings_credit_only_receipt_properties.py @@ -221,7 +221,6 @@ def situation(units, would_claim_pc=None): benunits[f"b{i}"] = { "members": names, "claims_all_entitled_benefits": {YEAR: True}, - "would_claim_council_tax_reduction": {YEAR: True}, "would_claim_pc": {YEAR: claims}, "would_claim_uc": {YEAR: False}, } @@ -426,7 +425,6 @@ def single_pensioner(savings=0.0, other_property=0.0): "benunit": { "members": ["pensioner"], "claims_all_entitled_benefits": {YEAR: True}, - "would_claim_council_tax_reduction": {YEAR: True}, } }, "households": { diff --git a/policyengine_uk/variables/gov/dwp/housing_benefit/would_claim_housing_benefit.py b/policyengine_uk/variables/gov/dwp/housing_benefit/would_claim_housing_benefit.py index 6c9df4b9b7..c07780f754 100644 --- a/policyengine_uk/variables/gov/dwp/housing_benefit/would_claim_housing_benefit.py +++ b/policyengine_uk/variables/gov/dwp/housing_benefit/would_claim_housing_benefit.py @@ -1,14 +1,23 @@ from policyengine_uk.model_api import * +from policyengine_uk.utils.data_source import built_from_data class would_claim_housing_benefit(Variable): value_type = bool entity = BenUnit label = "Would claim the Housing Benefit" - documentation = "Whether this family would claim Housing Benefit if eligible" + documentation = ( + "Whether this family would claim Housing Benefit if eligible. " + "Data-built simulations default to reporting families only; hand-entered " + "situations also claim when claims_all_entitled_benefits is true. " + "Datasets and situations can override this directly." + ) definition_period = YEAR def formula(benunit, period, parameters): - claims_all_entitled_benefits = benunit("claims_all_entitled_benefits", period) reported_hb = add(benunit, period, ["housing_benefit_reported"]) > 0 - return claims_all_entitled_benefits | reported_hb + # d1455 applies d1390's survey reporters-only rule to HB. Hand-entered + # situations retain main's per-family take-up rule (PR 1831 review). + if built_from_data(benunit.simulation): + return reported_hb + return benunit("claims_all_entitled_benefits", period) | reported_hb diff --git a/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/would_claim_council_tax_reduction.py b/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/would_claim_council_tax_reduction.py index f0d375f521..403f3c7fe9 100644 --- a/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/would_claim_council_tax_reduction.py +++ b/policyengine_uk/variables/gov/local_authorities/council_tax_reduction/would_claim_council_tax_reduction.py @@ -1,4 +1,5 @@ from policyengine_uk.model_api import * +from policyengine_uk.utils.data_source import built_from_data class would_claim_council_tax_reduction(Variable): @@ -7,13 +8,17 @@ class would_claim_council_tax_reduction(Variable): label = "Would claim Council Tax Reduction" documentation = ( "Whether this benefit unit would claim Council Tax Reduction if eligible. " - "By default only families reporting it claim; datasets and situations " - "can override this directly." + "Data-built simulations default to reporting families only; hand-entered " + "situations also claim when claims_all_entitled_benefits is true. " + "Datasets and situations can override this directly." ) definition_period = YEAR def formula(benunit, period, parameters): reported_ctr = benunit("council_tax_benefit_reported", period) > 0 - # Reporters only under Max's d1390 ruling, until calibrated take-up - # inputs land: https://github.com/PolicyEngine/policyengine-uk-data/issues/448 - return reported_ctr + # Survey take-up is reporters-only under d1390 until calibrated inputs + # land: https://github.com/PolicyEngine/policyengine-uk-data/issues/448 + # Calculator households retain main's rule (Vahid's PR 1831 review). + if built_from_data(benunit.simulation): + return reported_ctr + return benunit("claims_all_entitled_benefits", period) | reported_ctr diff --git a/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py b/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py index f662855d4b..71c834e680 100644 --- a/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py +++ b/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py @@ -14,7 +14,10 @@ class claims_all_entitled_benefits(Variable): "Income Support and income-related ESA); False where it reports £1 " "or more, in which case its reported benefits are taken as the " "complete set. Datasets and situations can override it directly. " - "Council Tax Reduction has a separate reporters-only take-up default." + "Council Tax Reduction, Pension Credit and Child Benefit are not among " + "these seven: reporting only Pension Credit still leaves this flag true. " + "Council Tax Reduction and Housing Benefit separately default to " + "reporters only on data-built simulations." ) def formula(benunit, period, parameters): From 94d5ebe3291b8c2b259e12e71dc751cf87ab3a57 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 20 Oct 2026 10:32:23 -0400 Subject: [PATCH 6/8] Isolate benefit-cap fixtures from Housing Benefit take-up --- .../tests/test_benefit_cap_specified_benefits_properties.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/policyengine_uk/tests/test_benefit_cap_specified_benefits_properties.py b/policyengine_uk/tests/test_benefit_cap_specified_benefits_properties.py index 7d428435e8..3bf095361d 100644 --- a/policyengine_uk/tests/test_benefit_cap_specified_benefits_properties.py +++ b/policyengine_uk/tests/test_benefit_cap_specified_benefits_properties.py @@ -403,6 +403,9 @@ def capped_family(scheme): **CAPPED_FAMILY, "universal_credit_pre_benefit_cap": 30_000 if scheme == "uc" else 0, "housing_benefit_pre_benefit_cap": 30_000 if scheme == "hb" else 0, + # This supplied award exercises the cap independently of take-up; + # another member's reports must not mask its final Housing Benefit. + "would_claim_housing_benefit": scheme == "hb", } From f56cfc50cfb52d8a66341e90af821af355122ead Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Tue, 20 Oct 2026 21:41:02 -0400 Subject: [PATCH 7/8] Keep main's survey take-up for tax credits and Income Support claims_all_entitled_benefits is now false for every family on data-built simulations, and is still tested per family in hand-entered situations. Main summed the seven reported benefits over the whole simulation, so on survey data the flag was false everywhere. Tested per family on data, every non-reporting survey family turned true. would_claim_CTC, _WTC and _IS read the flag, and tax credits pre-minimum is gated only by take-up, so tax credits leaked into CTR and HB means tests, tax credit awards and the 2024 Winter Fuel Payment benefit test (review r6). The gate sits in the flag, so every reader keeps main's survey value, and a dataset-supplied flag still overrides it. Tests: review r6's MOCK reproducer, which fails on 94d5ebe32; a property test that on data every take-up flag reading the flag equals the family's own report, and every downstream output equals explicit reported-only take-up; the microdata test now checks main's survey value. Co-Authored-By: Claude Opus 5.5 --- changelog.d/claims-all-per-benunit.fixed.md | 2 +- docs/engineering/skills/dataset-sources.md | 5 +- .../test_claims_all_entitled_benefits.py | 258 +++++++++++++++++- .../income/claims_all_entitled_benefits.py | 34 ++- 4 files changed, 272 insertions(+), 27 deletions(-) diff --git a/changelog.d/claims-all-per-benunit.fixed.md b/changelog.d/claims-all-per-benunit.fixed.md index 0ad45bcc46..9ae40e94d8 100644 --- a/changelog.d/claims-all-per-benunit.fixed.md +++ b/changelog.d/claims-all-per-benunit.fixed.md @@ -1 +1 @@ -- Evaluated `claims_all_entitled_benefits` per benefit unit. Kept main's Council Tax Reduction and Housing Benefit take-up rules for hand-entered households, while limiting data-built defaults to reporters (d1390 and d1455) until calibrated take-up inputs land (policyengine-uk-data#448). Explicit take-up inputs continue to override these defaults. +- Evaluated `claims_all_entitled_benefits` per benefit unit in hand-entered situations, so one family's reported benefits no longer switch off another family's take-up. Data-built simulations keep main's result, false for every family, so survey take-up of tax credits and Income Support still follows reported claims; Council Tax Reduction and Housing Benefit take-up there is limited to reporters (d1390 and d1455) until calibrated take-up inputs land (policyengine-uk-data#448). Explicit take-up inputs continue to override these defaults. diff --git a/docs/engineering/skills/dataset-sources.md b/docs/engineering/skills/dataset-sources.md index f44da7277e..17dcc889c3 100644 --- a/docs/engineering/skills/dataset-sources.md +++ b/docs/engineering/skills/dataset-sources.md @@ -68,7 +68,10 @@ simulations from hand-entered situations, including supported clones, branches and UK `build_from_situation` rebuilds. Council Tax Reduction and Housing Benefit use this distinction for their take-up defaults: data-built simulations use positive reported claims only (d1390 and d1455); situations also use their -per-benefit-unit `claims_all_entitled_benefits` flag. Explicit inputs override +per-benefit-unit `claims_all_entitled_benefits` flag. That flag is itself false +for every family on data-built simulations, as it was on main for any dataset +with a reporting family, so Child Tax Credit, Working Tax Credit and Income +Support take-up also follow reported claims there. Explicit inputs override these defaults, including a future calibrated dataset column (uk-data#448). Do not rebuild an existing data-built simulation by calling core's diff --git a/policyengine_uk/tests/test_claims_all_entitled_benefits.py b/policyengine_uk/tests/test_claims_all_entitled_benefits.py index 22f646f676..c91ab5bfa8 100644 --- a/policyengine_uk/tests/test_claims_all_entitled_benefits.py +++ b/policyengine_uk/tests/test_claims_all_entitled_benefits.py @@ -6,9 +6,12 @@ to have reported completely. The formula used to sum the seven reported columns over the whole simulation (`add(...).sum() < 1`), so in microdata it was False for every benefit unit as soon as any benefit unit reported any of them, and the -consumers that gate on it collapsed to reporters only. Council Tax Reduction -and Housing Benefit have reporters-only defaults on data-built simulations -(d1390 and d1455); hand-entered situations keep the per-family flag. +consumers that gate on it collapsed to reporters only. Hand-entered situations +now test each family on its own. Data-built simulations keep main's survey +result, False for every family, so Child Tax Credit, Working Tax Credit and +Income Support take-up follow reported claims there; Council Tax Reduction and +Housing Benefit are reporters-only on data-built simulations in any case +(d1390 and d1455). """ import numpy as np @@ -131,18 +134,30 @@ def test_under_one_pound_of_reported_benefits_counts_as_none(self): @pytest.mark.microsimulation -def test_flag_is_evaluated_per_benefit_unit_in_microdata(): +def test_survey_takeup_follows_reports_in_microdata(): + """On the survey the flag keeps main's value, false for every family, so + the legacy take-up flags that read it are reporters only (review r6).""" sim = Microsimulation() - flag = sim.calculate("claims_all_entitled_benefits", YEAR).values.astype(bool) - reported = np.zeros(len(flag)) - for variable in SEVEN_REPORTED: - reported = reported + sim.calculate(variable, YEAR, map_to="benunit").values - assert np.array_equal(flag, reported < 1) - # Both values must occur: the old formula returned a single value for all. - assert flag.any() and (~flag).any() + for year in (2024, YEAR): + flag = sim.calculate("claims_all_entitled_benefits", year).values + assert not flag.astype(bool).any(), year + for takeup, reported in ( + ("would_claim_CTC", "child_tax_credit_reported"), + ("would_claim_WTC", "working_tax_credit_reported"), + ): + reports = sim.calculate(reported, year, map_to="benunit").values > 0 + claims = sim.calculate(takeup, year).values.astype(bool) + assert np.array_equal(claims, reports), (takeup, year) + is_reports = ( + sim.calculate("income_support_reported", year).values + * sim.calculate("is_claimant_or_partner", year).values + ) + reported_is = sim.map_result(is_reports, "person", "benunit") > 0 + claims_is = sim.calculate("would_claim_IS", year).values.astype(bool) + assert np.array_equal(claims_is, reported_is), year -def mock_dataset(situation): +def mock_dataset(situation, year=YEAR): """Synthetic post-ingestion MOCK tables using the normal UK data schema.""" tables = {} person_ids = {name: i + 1 for i, name in enumerate(situation["people"])} @@ -162,7 +177,7 @@ def mock_dataset(situation): f"person_{entity}_id" ] = index else: - row[name] = value[YEAR] if isinstance(value, dict) else value + row[name] = value[year] if isinstance(value, dict) else value rows.append(row) tables[entity] = pd.DataFrame(rows).fillna(0) for column in ("person_benunit_id", "person_household_id"): @@ -170,7 +185,7 @@ def mock_dataset(situation): memberships[person_id][column] for person_id in person_ids.values() ] return UKMultiYearDataset( - datasets=[UKSingleYearDataset(**tables, fiscal_year=YEAR)] + datasets=[UKSingleYearDataset(**tables, fiscal_year=year)] ) @@ -318,3 +333,218 @@ def test_ctr_is_zero_for_every_nonreporter_without_an_explicit_claim_flag(famili "council_tax_reduction", ): assert (sim.calculate(variable, YEAR)[mask] == 0).all(), variable + + +# Tax credits pay awards until 5 April 2025, so 2024 is a year in which the +# legacy take-up flags still reach an award. +TAX_CREDIT_YEAR = 2024 + + +def tax_credit_families(): + """Review r6's MOCK probe: a non-reporting lone parent and a non-reporting + working pensioner, beside a family that reports Child Tax Credit and CTR.""" + year = TAX_CREDIT_YEAR + renting = { + "region": {year: "NORTH_WEST"}, + "tenure_type": {year: "RENT_PRIVATELY"}, + "rent": {year: 8_000}, + "council_tax": {year: 1_800}, + } + return { + "people": { + "parent": { + "age": {year: 30}, + "employment_income": {year: 12_000}, + "weekly_hours": {year: 20}, + }, + "child": {"age": {year: 5}}, + "pensioner": { + "age": {year: 68}, + "employment_income": {year: 9_000}, + "weekly_hours": {year: 20}, + }, + "reporter": { + "age": {year: 35}, + "employment_income": {year: 12_000}, + "weekly_hours": {year: 20}, + "child_tax_credit_reported": {year: 3_000}, + "council_tax_benefit_reported": {year: 500}, + }, + "reporter_child": {"age": {year: 6}}, + }, + "benunits": { + "bu_parent": { + "members": ["parent", "child"], + "would_claim_uc": {year: False}, + }, + "bu_pensioner": { + "members": ["pensioner"], + "would_claim_uc": {year: False}, + }, + "bu_reporter": { + "members": ["reporter", "reporter_child"], + "would_claim_uc": {year: False}, + }, + }, + "households": { + "hh_parent": {"members": ["parent", "child"], **renting}, + "hh_pensioner": { + "members": ["pensioner"], + "region": {year: "NORTH_WEST"}, + "tenure_type": {year: "OWNED_OUTRIGHT"}, + "council_tax": {year: 1_800}, + }, + "hh_reporter": {"members": ["reporter", "reporter_child"], **renting}, + }, + } + + +def test_data_built_nonreporters_get_no_tax_credits(): + """Survey runs keep main's take-up for tax credits (review r6). Tested per + family on data, the lone parent's flag turned true, so would_claim_CTC + did too, and £3,455 of tax credits reached its CTR and HB means tests, + its tax credit award and the 2024 Winter Fuel Payment benefit test.""" + year = TAX_CREDIT_YEAR + situation = tax_credit_families() + data = Simulation(dataset=mock_dataset(situation, year)) + assert data.calculate("claims_all_entitled_benefits", year).tolist() == [ + False, + False, + False, + ] + assert data.calculate("would_claim_CTC", year).tolist() == [False, False, True] + for takeup in ("would_claim_WTC", "would_claim_IS"): + assert not data.calculate(takeup, year).any(), takeup + tax_credits = data.calculate("tax_credits", year) + assert tax_credits[:2].tolist() == [0, 0] + assert tax_credits[2] > 0 + # People: parent, child, pensioner, reporter, reporter_child. + assert data.calculate("tax_credit_award", year)[0] == 0 + assert not data.calculate("is_on_winter_fuel_payment_relevant_benefit", year)[0] + # The same families entered by hand keep the per-family flag. + hand = Simulation(situation=situation) + assert hand.calculate("claims_all_entitled_benefits", year).tolist() == [ + True, + True, + False, + ] + + +# Each take-up flag that reads claims_all_entitled_benefits, and the report +# that sets it on data-built simulations. +TAKEUP_REPORTS = { + "would_claim_CTC": "child_tax_credit_reported", + "would_claim_WTC": "working_tax_credit_reported", + "would_claim_IS": "income_support_reported", + "would_claim_housing_benefit": "housing_benefit_reported", + "would_claim_council_tax_reduction": "council_tax_benefit_reported", +} + +# Outputs downstream of the take-up flags: tax credits, their award and the +# means tests and benefit tests that read them, and household net income. +TAKEUP_OUTPUTS = ( + "tax_credits", + "child_tax_credit", + "working_tax_credit", + "income_support", + "housing_benefit", + "council_tax_reduction", + "council_tax_reduction_applicable_income", + "housing_benefit_applicable_income", + "tax_credit_award", + "is_on_winter_fuel_payment_relevant_benefit", + "household_net_income", +) + +LEGACY_FAMILIES = st.lists( + st.fixed_dictionaries( + { + "age": st.integers(min_value=18, max_value=80), + "children": st.integers(min_value=0, max_value=2), + "earnings": st.integers(min_value=0, max_value=40_000), + "hours": st.sampled_from((0, 10, 20, 35)), + "renter": st.booleans(), + "reports": st.frozensets( + st.sampled_from(SEVEN_REPORTED + ["council_tax_benefit_reported"]) + ), + } + ), + min_size=1, + max_size=3, +) + + +def legacy_families(families, year, takeup=None): + """One benefit unit and household per family; the adult reports £100 of + each benefit in `reports`. `takeup` adds explicit take-up columns.""" + situation = {"people": {}, "benunits": {}, "households": {}} + for index, family in enumerate(families): + adult = f"adult_{index}" + members = [adult] + situation["people"][adult] = { + "age": {year: family["age"]}, + "employment_income": {year: family["earnings"]}, + "weekly_hours": {year: family["hours"]}, + **{report: {year: 100} for report in sorted(family["reports"])}, + } + for child in range(family["children"]): + name = f"child_{index}_{child}" + situation["people"][name] = {"age": {year: 4 + child}} + members.append(name) + benunit = {"members": members} + for variable, values in (takeup or {}).items(): + benunit[variable] = {year: bool(values[index])} + situation["benunits"][f"bu_{index}"] = benunit + situation["households"][f"hh_{index}"] = { + "members": members, + "region": {year: "NORTH_WEST"}, + "tenure_type": { + year: "RENT_PRIVATELY" if family["renter"] else "OWNED_OUTRIGHT" + }, + "rent": {year: 8_000 if family["renter"] else 0}, + "council_tax": {year: 1_800}, + } + return situation + + +NO_REPORTS = dict(age=30, children=1, earnings=12_000, hours=20, renter=True) + + +@given(families=LEGACY_FAMILIES, year=st.sampled_from((TAX_CREDIT_YEAR, YEAR))) +# No family reports anything: main's simulation-wide sum set every flag true +# here, so this example differs from main by design (reports-only on data). +@example(families=[{**NO_REPORTS, "reports": frozenset()}], year=TAX_CREDIT_YEAR) +@example( + families=[ + {**NO_REPORTS, "reports": frozenset()}, + { + **NO_REPORTS, + "reports": frozenset( + {"child_tax_credit_reported", "council_tax_benefit_reported"} + ), + }, + ], + year=TAX_CREDIT_YEAR, +) +@settings(max_examples=10, deadline=None) +def test_data_built_takeup_equals_reported_only(families, year): + """On data, every take-up flag that reads claims_all_entitled_benefits is + the family's own report, and every downstream output equals the same data + with those reported-only take-up flags given as explicit inputs.""" + reported = { + takeup: [report in family["reports"] for family in families] + for takeup, report in TAKEUP_REPORTS.items() + } + default = Simulation(dataset=mock_dataset(legacy_families(families, year), year)) + explicit = Simulation( + dataset=mock_dataset(legacy_families(families, year, reported), year) + ) + assert not default.calculate("claims_all_entitled_benefits", year).any() + for takeup, expected in reported.items(): + assert default.calculate(takeup, year).tolist() == expected, takeup + for variable in TAKEUP_OUTPUTS: + np.testing.assert_array_equal( + default.calculate(variable, year), + explicit.calculate(variable, year), + err_msg=variable, + ) diff --git a/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py b/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py index 71c834e680..545a7153a5 100644 --- a/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py +++ b/policyengine_uk/variables/household/income/claims_all_entitled_benefits.py @@ -1,4 +1,5 @@ from policyengine_uk.model_api import * +from policyengine_uk.utils.data_source import built_from_data class claims_all_entitled_benefits(Variable): @@ -7,20 +8,31 @@ class claims_all_entitled_benefits(Variable): label = "Claims all eligible benefits" definition_period = YEAR documentation = ( - "Whether this family would claim any benefit it is entitled to. True " - "where the benefit unit reports under £1 in total across the seven " - "means-tested benefits the formula checks (Child Tax Credit, Working " - "Tax Credit, Universal Credit, Housing Benefit, income-based JSA, " - "Income Support and income-related ESA); False where it reports £1 " - "or more, in which case its reported benefits are taken as the " - "complete set. Datasets and situations can override it directly. " - "Council Tax Reduction, Pension Credit and Child Benefit are not among " - "these seven: reporting only Pension Credit still leaves this flag true. " - "Council Tax Reduction and Housing Benefit separately default to " - "reporters only on data-built simulations." + "Whether this family would claim any benefit it is entitled to. In " + "hand-entered situations it is true where the benefit unit reports " + "under £1 in total across the seven means-tested benefits the formula " + "checks (Child Tax Credit, Working Tax Credit, Universal Credit, " + "Housing Benefit, income-based JSA, Income Support and income-related " + "ESA), and false where it reports £1 or more, in which case its " + "reported benefits are taken as the complete set. Council Tax " + "Reduction, Pension Credit and Child Benefit are not among these " + "seven: reporting only Pension Credit still leaves this flag true. In " + "data-built simulations it is false for every family, so take-up of " + "the benefits that read it follows reported claims. Datasets and " + "situations can override it directly, except that Council Tax " + "Reduction and Housing Benefit ignore it on data-built simulations." ) def formula(benunit, period, parameters): + # Survey runs keep main's result: no family is assumed to claim a + # benefit it does not report, so would_claim_CTC, _WTC and _IS follow + # reported claims (CTR and HB are reporters-only there anyway, d1390 + # and d1455). Main got there through a sum over the whole simulation, + # which any reporting family made false for every family. Tested per + # family instead, every non-reporting survey family would turn true + # and claim tax credits and Income Support (PR 1831 review r6). + if built_from_data(benunit.simulation): + return benunit.filled_array(False) # Reporting under £1 across the seven benefits counts as reporting none. return ( add( From 928a82d7dd5a5cf370760c8b625cbc4b7b3f7915 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Thu, 22 Oct 2026 02:37:41 -0400 Subject: [PATCH 8/8] Keep the take-up properties' examples under a saturated host Both properties now suppress Hypothesis's too_slow check, as most of the repo's property tests do. On this host at load 170-240, one draw stalled for 4.9 s in the CTR property and one for 11.8 s in the tax credit property, between simulations. The check allows 30 s over the first ten inputs. Every example and every other check is kept. Round 7 saw the CTR property fail once in a parallel batch, and no traceback was printed. That run's cause cannot be recovered, so this removes one measured candidate rather than a confirmed one. Co-Authored-By: Claude Opus 5.5 --- .../tests/test_claims_all_entitled_benefits.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/policyengine_uk/tests/test_claims_all_entitled_benefits.py b/policyengine_uk/tests/test_claims_all_entitled_benefits.py index c91ab5bfa8..5f85663716 100644 --- a/policyengine_uk/tests/test_claims_all_entitled_benefits.py +++ b/policyengine_uk/tests/test_claims_all_entitled_benefits.py @@ -17,7 +17,7 @@ import numpy as np import pandas as pd import pytest -from hypothesis import example, given, settings, strategies as st +from hypothesis import HealthCheck, example, given, settings, strategies as st from policyengine_uk import Microsimulation, Simulation from policyengine_uk.data import UKMultiYearDataset, UKSingleYearDataset @@ -282,6 +282,12 @@ def test_reports_outside_the_seven_leave_the_all_benefits_flag_true(reported): max_size=4, ) +# The draws are cheap, but on a saturated host one stalled for 4.9 s (and +# 11.8 s in the tax credit property below) between simulations, against the +# speed check's 30 s for its first ten inputs. Suppress only that timing +# check, keeping every example and every other check. +TIMING_TOLERANT = dict(deadline=None, suppress_health_check=[HealthCheck.too_slow]) + @given(families=CTR_FAMILIES) @example(families=[(40, "SCOTLAND", 0, 0, True, 0)]) @@ -292,7 +298,7 @@ def test_reports_outside_the_seven_leave_the_all_benefits_flag_true(reported): (70, "ENGLAND", 0, 0, False, 100), ] ) -@settings(max_examples=30, deadline=None) +@settings(max_examples=30, **TIMING_TOLERANT) def test_ctr_is_zero_for_every_nonreporter_without_an_explicit_claim_flag(families): situation = {"people": {}, "benunits": {}, "households": {}} must_be_zero = [] @@ -526,7 +532,7 @@ def legacy_families(families, year, takeup=None): ], year=TAX_CREDIT_YEAR, ) -@settings(max_examples=10, deadline=None) +@settings(max_examples=10, **TIMING_TOLERANT) def test_data_built_takeup_equals_reported_only(families, year): """On data, every take-up flag that reads claims_all_entitled_benefits is the family's own report, and every downstream output equals the same data