From fbe360eaffc49626f7e18a63177cdb89b9222bcb Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 19 Oct 2026 08:34:55 -0400 Subject: [PATCH 1/2] Keep claimable filers' own exemptions under the HI and VA dependent-exemption repeal The contributed repeal of state dependent exemptions counted every head and spouse in its Hawaii and Virginia overrides, so it gave a filer whom another taxpayer can claim the exemption the baseline denies (HRS 235-54(a); Va. Code 58.1-322.03(2)(a) with IRC 151(d)(2)). An unclaimed but claimable single filer aged 22 got $1,144 in Hawaii and $930 in Virginia under the repeal against $0 in the baseline. Hawaii now counts own exemptions with head_spouse_count_not_dependent_elsewhere and keeps the baseline's aged gate (aged & head_or_spouse & ~claimable); Virginia keeps the baseline's per-person filer gate (filer & ~claimable). Virginia's $800 aged or blind exemption has no such bar and is unchanged. Co-Authored-By: Claude Opus 5.5 --- .../fix-hi-va-repeal-claimable.fixed.md | 1 + .../repeal_state_dependent_exemptions.py | 29 +- .../repeal_state_dependent_exemptions.yaml | 343 ++++++++++++++++++ 3 files changed, 367 insertions(+), 6 deletions(-) create mode 100644 changelog.d/fix-hi-va-repeal-claimable.fixed.md diff --git a/changelog.d/fix-hi-va-repeal-claimable.fixed.md b/changelog.d/fix-hi-va-repeal-claimable.fixed.md new file mode 100644 index 00000000000..0e7cd8b1237 --- /dev/null +++ b/changelog.d/fix-hi-va-repeal-claimable.fixed.md @@ -0,0 +1 @@ +Keep a claimable filer's own exemptions under the Hawaii and Virginia dependent-exemption repeal: the contributed repeal no longer gives a filer whom another taxpayer can claim the regular, aged or personal exemption that the baseline denies (HRS 235-54(a); Va. Code 58.1-322.03(2)(a)). diff --git a/policyengine_us/reforms/state_dependent_exemptions/repeal_state_dependent_exemptions.py b/policyengine_us/reforms/state_dependent_exemptions/repeal_state_dependent_exemptions.py index d05820bfb6b..e6960115eff 100644 --- a/policyengine_us/reforms/state_dependent_exemptions/repeal_state_dependent_exemptions.py +++ b/policyengine_us/reforms/state_dependent_exemptions/repeal_state_dependent_exemptions.py @@ -8,18 +8,30 @@ class hi_regular_exemptions(Variable): entity = TaxUnit label = "Hawaii regular exemptions" unit = USD - reference = "https://files.hawaii.gov/tax/forms/2022/n11ins.pdf#page=20" + reference = ( + "https://files.hawaii.gov/tax/forms/2022/n11ins.pdf#page=20", + # HRS 235-54(a): the exemption of an individual whom another + # taxpayer can claim "shall be zero", including the additional + # exemption for age 65 or over. + "https://files.hawaii.gov/tax/legal/hrs/hrs_235.pdf#page=45", + ) definition_period = YEAR defined_for = StateCode.HI def formula(tax_unit, period, parameters): - exemptions_count = tax_unit("head_spouse_count", period) + # Repeal removes dependents, preserving the baseline filer count: + # a filer who can be claimed as a dependent has no exemption. + exemptions_count = tax_unit( + "head_spouse_count_not_dependent_elsewhere", period + ) p = parameters(period).gov.states.hi.tax.income.exemptions - # Aged heads and spouses get an extra base exemption. + # Aged heads and spouses who cannot be claimed get an extra base + # exemption, as in the baseline. person = tax_unit.members head_or_spouse = person("is_tax_unit_head_or_spouse", period) + claimed = person("claimable_as_dependent_on_another_return", period) aged = person("age", period) >= p.aged_threshold - aged_head_spouse_count = tax_unit.sum(aged & head_or_spouse) + aged_head_spouse_count = tax_unit.sum(aged & head_or_spouse & ~claimed) total_exemption_count_including_aged = ( exemptions_count + aged_head_spouse_count ) @@ -200,9 +212,14 @@ class va_personal_exemption_person(Variable): ) def formula(person, period, parameters): - head_or_spouse = person("is_tax_unit_head_or_spouse", period) + # Repeal removes dependents, preserving the baseline filer gate: + # a filer who can be claimed as a dependent has no personal + # exemption allowable federally (Va. Code 58.1-322.03(2)(a); + # IRC 151(d)(2)). + filer = person("is_tax_unit_head_or_spouse", period) + claimed = person("claimable_as_dependent_on_another_return", period) amount = parameters(period).gov.states.va.tax.income.exemptions.personal - return amount * head_or_spouse + return amount * (filer & ~claimed) class wv_personal_exemption(Variable): value_type = float diff --git a/policyengine_us/tests/policy/contrib/state_dependent_exemptions/repeal_state_dependent_exemptions.yaml b/policyengine_us/tests/policy/contrib/state_dependent_exemptions/repeal_state_dependent_exemptions.yaml index 2c9f3842667..163fdaeac14 100644 --- a/policyengine_us/tests/policy/contrib/state_dependent_exemptions/repeal_state_dependent_exemptions.yaml +++ b/policyengine_us/tests/policy/contrib/state_dependent_exemptions/repeal_state_dependent_exemptions.yaml @@ -80,6 +80,349 @@ output: vt_personal_exemptions: 15_300 +# HRS 235-54(a): the exemption of an individual whom another taxpayer can claim +# is zero, including the additional exemption for age 65 or over. The repeal +# removes dependents only, so it never gives such a filer an exemption. +- name: HI repeal - unclaimed but claimable single filer - baseline + period: 2025 + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: false + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + tax_units: {tax_unit: {members: [head], filing_status: SINGLE}} + households: {household: {members: [head], state_code: HI}} + output: + hi_regular_exemptions: 0 + hi_exemptions: 0 + +- name: HI repeal - unclaimed but claimable single filer - reform + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + tax_units: {tax_unit: {members: [head], filing_status: SINGLE}} + households: {household: {members: [head], state_code: HI}} + output: + hi_regular_exemptions: 0 + hi_exemptions: 0 + +- name: HI repeal - joint return with one claimable spouse and two children keeps only the other spouse's exemption + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 40 + is_tax_unit_head: true + spouse: + age: 22 + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: true + child1: + age: 4 + is_tax_unit_dependent: true + child2: + age: 7 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [head, spouse, child1, child2] + filing_status: JOINT + households: + household: + members: [head, spouse, child1, child2] + state_code: HI + output: + # Baseline is also 1 x 1,144: the return has no dependents (IRC 152(b)(1)). + hi_regular_exemptions: 1_144 + +- name: HI repeal - joint return whose claimable spouse is within the filing exception loses only the dependents + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 22 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + spouse: + age: 40 + is_tax_unit_spouse: true + child1: + age: 4 + is_tax_unit_dependent: true + child2: + age: 7 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [head, spouse, child1, child2] + filing_status: JOINT + households: + household: + members: [head, spouse, child1, child2] + state_code: HI + output: + # Baseline: (1 own + 2 dependents) x 1,144 = 3,432. + hi_regular_exemptions: 1_144 + +- name: HI repeal - joint return with both spouses claimable + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 22 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + spouse: + age: 21 + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: true + tax_units: {tax_unit: {members: [head, spouse], filing_status: JOINT}} + households: {household: {members: [head, spouse], state_code: HI}} + output: + hi_regular_exemptions: 0 + hi_exemptions: 0 + +- name: HI repeal - aged claimable single filer gets neither the regular nor the aged exemption + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 66 + claimable_as_dependent_on_another_return: true + tax_units: {tax_unit: {members: [head], filing_status: SINGLE}} + households: {household: {members: [head], state_code: HI}} + output: + hi_regular_exemptions: 0 + +- name: HI repeal - aged couple with one claimable spouse keeps the other spouse's regular and aged exemptions + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 67 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + spouse: + age: 70 + is_tax_unit_spouse: true + tax_units: {tax_unit: {members: [head, spouse], filing_status: JOINT}} + households: {household: {members: [head, spouse], state_code: HI}} + output: + # Baseline is also (1 + 1 aged) x 1,144. + hi_regular_exemptions: 2_288 + +- name: HI repeal - aged couple with a child keeps both regular and aged exemptions and loses the dependent + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 70 + is_tax_unit_head: true + spouse: + age: 68 + is_tax_unit_spouse: true + child: + age: 15 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [head, spouse, child] + filing_status: JOINT + households: + household: + members: [head, spouse, child] + state_code: HI + output: + # (2 + 2 aged) x 1,144; the baseline adds the child for 5,720. + hi_regular_exemptions: 4_576 + +# Va. Code 58.1-322.03(2)(a) allows $930 for each personal exemption allowable +# federally, and a filer whom another taxpayer can claim has none +# (IRC 151(d)(2)). The $800 aged or blind exemption in (2)(b) has no such bar. +- name: VA repeal - unclaimed but claimable single filer - baseline + period: 2025 + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: false + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + tax_units: {tax_unit: {members: [head], filing_status: SINGLE}} + households: {household: {members: [head], state_code: VA}} + output: + va_personal_exemption: 0 + va_total_exemptions: 0 + +- name: VA repeal - unclaimed but claimable single filer - reform + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 22 + claimable_as_dependent_on_another_return: true + claimed_as_dependent_on_another_return: false + tax_units: {tax_unit: {members: [head], filing_status: SINGLE}} + households: {household: {members: [head], state_code: VA}} + output: + va_personal_exemption: 0 + va_total_exemptions: 0 + +- name: VA repeal - joint return with one claimable spouse and two children keeps only the other spouse's exemption + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 40 + is_tax_unit_head: true + spouse: + age: 22 + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: true + child1: + age: 4 + is_tax_unit_dependent: true + child2: + age: 7 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [head, spouse, child1, child2] + filing_status: JOINT + households: + household: + members: [head, spouse, child1, child2] + state_code: VA + output: + # Baseline is also 930: the return has no dependents (IRC 152(b)(1)). + va_personal_exemption: 930 + va_personal_exemption_person: [930, 0, 0, 0] + +- name: VA repeal - joint return whose claimable spouse is within the filing exception loses only the dependents + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 22 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + dependent_claimant_filing_exception: true + spouse: + age: 40 + is_tax_unit_spouse: true + child1: + age: 4 + is_tax_unit_dependent: true + child2: + age: 7 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [head, spouse, child1, child2] + filing_status: JOINT + households: + household: + members: [head, spouse, child1, child2] + state_code: VA + output: + # Baseline: 3 x 930 = 2,790. + va_personal_exemption: 930 + va_personal_exemption_person: [0, 930, 0, 0] + +- name: VA repeal - joint return with both spouses claimable + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 22 + is_tax_unit_head: true + claimable_as_dependent_on_another_return: true + spouse: + age: 21 + is_tax_unit_spouse: true + claimable_as_dependent_on_another_return: true + tax_units: {tax_unit: {members: [head, spouse], filing_status: JOINT}} + households: {household: {members: [head, spouse], state_code: VA}} + output: + va_personal_exemption: 0 + va_total_exemptions: 0 + +- name: VA repeal - aged claimable single filer keeps only the aged exemption + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 66 + claimable_as_dependent_on_another_return: true + tax_units: {tax_unit: {members: [head], filing_status: SINGLE}} + households: {household: {members: [head], state_code: VA}} + output: + va_personal_exemption: 0 + va_aged_blind_exemption: 800 + va_total_exemptions: 800 + +- name: VA repeal - joint filers with two children keep their own exemptions and lose the dependents + period: 2025 + reforms: policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions.repeal_state_dependent_exemptions + input: + gov.contrib.repeal_state_dependent_exemptions.in_effect: true + people: + head: + age: 40 + is_tax_unit_head: true + spouse: + age: 38 + is_tax_unit_spouse: true + child1: + age: 4 + is_tax_unit_dependent: true + child2: + age: 7 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [head, spouse, child1, child2] + filing_status: JOINT + households: + household: + members: [head, spouse, child1, child2] + state_code: VA + output: + # 2 x 930; the baseline adds the children for 3,720. + va_personal_exemption: 1_860 + va_personal_exemption_person: [930, 930, 0, 0] + # Test for KY family size tax credit rate - verifies state_group_str is used correctly # This test ensures state_group is derived from state_code, not set explicitly - name: Kentucky family size tax credit with reform - state_group derived from state_code From c0ceabd55b0c58604781206c598710fb98b629ce Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 19 Oct 2026 08:44:17 -0400 Subject: [PATCH 2/2] Add HI and VA repeal invariants for claimable filers Property tests over an exhaustive grid (each filer not claimable, claimable, claimed or within the claimant filing exception; singles and couples; young, aged and blind/disabled; with and without dependents) and Hypothesis batches: under the repeal each Hawaii and Virginia exemption output equals the baseline for the same return with its dependents removed, never exceeds the baseline, and no claimable filer or dependent gets a Virginia personal exemption. Co-Authored-By: Claude Opus 5.5 --- ...claimable_filer_hi_va_repeal_invariants.py | 225 ++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 policyengine_us/tests/core/test_claimable_filer_hi_va_repeal_invariants.py diff --git a/policyengine_us/tests/core/test_claimable_filer_hi_va_repeal_invariants.py b/policyengine_us/tests/core/test_claimable_filer_hi_va_repeal_invariants.py new file mode 100644 index 00000000000..0df4065abad --- /dev/null +++ b/policyengine_us/tests/core/test_claimable_filer_hi_va_repeal_invariants.py @@ -0,0 +1,225 @@ +"""Hawaii and Virginia exemptions under the contributed repeal of state +dependent exemptions, for filers who can be claimed as a dependent. + +The repeal removes the dependent exemptions and nothing else. A filer whom +another taxpayer can claim has no exemption of their own in the baseline: +Hawaii sets it, and the additional exemption for age 65 or over, to zero +(HRS 235-54(a)), and Virginia allows $930 only for each exemption allowable +federally (Va. Code 58.1-322.03(2)(a); IRC 151(d)(2)). Virginia's $800 aged or +blind exemption (58.1-322.03(2)(b)) has no such bar. + +For single filers and couples, each filer not claimable, claimable but +unclaimed, claimed, or within the claimant filing exception, with and without +dependents (an exhaustive grid and Hypothesis batches): + +1. Dependents only: each output under the repeal equals the baseline output + for the same return with its dependents removed, and each filer's Virginia + personal exemption equals the baseline's for that filer on that return. +2. Never above baseline: no output is higher under the repeal than in the + baseline. +3. No claimable filer gets a Virginia personal exemption under the repeal, + and no dependent does. +""" + +from itertools import product + +import numpy as np +import pytest +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st + +from policyengine_us import CountryTaxBenefitSystem, Simulation +from policyengine_us.reforms.state_dependent_exemptions.repeal_state_dependent_exemptions import ( + repeal_state_dependent_exemptions, +) +from policyengine_us.tests.core.test_dependent_elsewhere_head_spouse_swap_invariance import ( + adults, + dependents, +) + +STATES = ["HI", "VA"] +YEARS = [2021, 2025, 2026] +OUTPUTS = [ + "hi_regular_exemptions", + "hi_disabled_exemptions", + "hi_exemptions", + "va_personal_exemption", + "va_aged_blind_exemption", + "va_total_exemptions", +] +TOLERANCE = 0.01 +# (claimable, claimed, claimant filing exception) for each filer. +CLAIM_STATES = { + "none": (False, False, False), + "claimable": (True, False, False), + "claimed": (True, True, False), + "exception": (True, False, True), +} + + +@pytest.fixture(scope="module") +def repeal_system(): + # Built once for the module and released when its tests end. + return CountryTaxBenefitSystem(reform=repeal_state_dependent_exemptions) + + +def _grid(): + young = {"age": 22, "employment_income": 8_000.0} + old = {"age": 70, "social_security_retirement": 12_000.0} + impaired = {"age": 40, "is_blind": True, "is_disabled": True} + children = [{"age": 4}, {"age": 19, "is_full_time_student": True}] + filer_sets = [[young], [old], [impaired], [young, old], [old, old]] + filer_sets += [[young, impaired]] + units = [] + for state, filers, with_children in product(STATES, filer_sets, [False, True]): + for states in product(CLAIM_STATES, repeat=len(filers)): + claimable, claimed, exception = zip(*(CLAIM_STATES[s] for s in states)) + units.append( + { + "state": state, + "adults": filers, + "dependents": children if with_children else [], + "claimable": claimable, + "claimed": claimed, + "exception": exception, + } + ) + return units + + +@st.composite +def returns(draw): + filers = draw(st.integers(1, 2)) + claimable = tuple(draw(st.booleans()) for _ in range(filers)) + claimed = tuple(can and draw(st.booleans()) for can in claimable) + return { + "state": draw(st.sampled_from(STATES)), + "adults": [draw(adults()) for _ in range(filers)], + "dependents": draw(st.lists(dependents(), max_size=2)), + "claimable": claimable, + "claimed": claimed, + "exception": tuple( + can and not is_claimed and draw(st.booleans()) + for can, is_claimed in zip(claimable, claimed) + ), + } + + +def _situation(units, year, with_dependents=True): + people = {} + groups = { + "tax_units": {}, + "spm_units": {}, + "families": {}, + "marital_units": {}, + "households": {}, + } + for i, unit in enumerate(units): + filers = [] + for j, amounts in enumerate(unit["adults"]): + name = f"filer_{i}_{j}" + people[name] = { + **amounts, + "is_tax_unit_head": j == 0, + "is_tax_unit_spouse": j == 1, + "is_tax_unit_dependent": False, + "claimable_as_dependent_on_another_return": unit["claimable"][j], + "claimed_as_dependent_on_another_return": unit["claimed"][j], + "dependent_claimant_filing_exception": unit["exception"][j], + } + filers.append(name) + groups["marital_units"][f"filers_{i}"] = {"members": list(filers)} + members = list(filers) + for k, amounts in enumerate(unit["dependents"] if with_dependents else []): + name = f"dependent_{i}_{k}" + people[name] = { + **amounts, + "is_tax_unit_head": False, + "is_tax_unit_spouse": False, + "is_tax_unit_dependent": True, + } + members.append(name) + groups["marital_units"][name] = {"members": [name]} + for group, prefix in ( + ("tax_units", "tax_unit"), + ("spm_units", "spm_unit"), + ("families", "family"), + ): + groups[group][f"{prefix}_{i}"] = {"members": members} + groups["households"][f"household_{i}"] = { + "members": members, + "state_code": {year: unit["state"]}, + } + people = { + name: {k: {year: v} for k, v in values.items()} + for name, values in people.items() + } + return {"people": people, **groups} + + +def _calc(sim, name, year): + return np.asarray(sim.calculate(name, year), dtype=float) + + +def _describe(units, rows): + return ", ".join( + f"{units[i]['state']} filers={len(units[i]['adults'])} " + f"claimable={units[i]['claimable']} claimed={units[i]['claimed']} " + f"exception={units[i]['exception']} " + f"dependents={len(units[i]['dependents'])}" + for i in rows[:5] + ) + + +def check_repeal(units, year, system): + situation = _situation(units, year) + repeal = Simulation(situation=situation, tax_benefit_system=system) + baseline = Simulation(situation=situation) + no_dependents = Simulation(situation=_situation(units, year, False)) + for name in OUTPUTS: + reformed = _calc(repeal, name, year) + expected = _calc(no_dependents, name, year) + current = _calc(baseline, name, year) + assert np.isfinite(reformed).all(), f"{name} in {year} is not finite" + differs = np.flatnonzero(np.abs(reformed - expected) > TOLERANCE) + assert not differs.size, ( + f"{name} in {year} under the repeal differs from the baseline " + "without dependents: " + + _describe(units, differs) + + f"; repeal {reformed[differs[:5]]}, expected {expected[differs[:5]]}" + ) + rises = np.flatnonzero(reformed > current + TOLERANCE) + assert not rises.size, ( + f"{name} in {year} is higher under the repeal than in the " + "baseline: " + _describe(units, rises) + ) + # Filers keep their order in both situations, so their rows line up. + filer = _calc(repeal, "is_tax_unit_head_or_spouse", year) > 0 + claimable = _calc(repeal, "claimable_as_dependent_on_another_return", year) > 0 + person = _calc(repeal, "va_personal_exemption_person", year) + np.testing.assert_allclose( + person[filer], + _calc(no_dependents, "va_personal_exemption_person", year), + atol=TOLERANCE, + err_msg=f"va_personal_exemption_person in {year}", + ) + assert not person[~filer].any(), f"a dependent has a VA exemption in {year}" + assert not person[filer & claimable].any(), ( + f"a claimable filer has a VA personal exemption in {year}" + ) + + +@pytest.mark.parametrize("year", YEARS) +def test_hi_va_repeal_grid(year, repeal_system): + check_repeal(_grid(), year, repeal_system) + + +@settings( + max_examples=3, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], +) +@given(year=st.sampled_from(YEARS), units=st.lists(returns(), min_size=6, max_size=12)) +def test_hi_va_repeal_generated_returns(year, units, repeal_system): + check_repeal(units, year, repeal_system)