diff --git a/changelog.d/tx-ceap-categorical-receipt.fixed.md b/changelog.d/tx-ceap-categorical-receipt.fixed.md new file mode 100644 index 00000000000..487e52a6dc5 --- /dev/null +++ b/changelog.d/tx-ceap-categorical-receipt.fixed.md @@ -0,0 +1 @@ +Key categorical eligibility and receipt checks on calculated benefits: TX CEAP (42 USC 8624(b)(2)(A)), the Medicaid community engagement TANF pass-through, the SNAP work registration TANF exemption (7 CFR 273.7(b)(1)(iii)), and the Oklahoma sales tax relief credit TANF exclusion. diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/medicaid_community_engagement_pass_through_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/medicaid_community_engagement_pass_through_eligible.yaml index 50d53c99241..32e272d4de2 100644 --- a/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/medicaid_community_engagement_pass_through_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hhs/medicaid/eligibility/medicaid_community_engagement_pass_through_eligible.yaml @@ -26,7 +26,7 @@ spm_units: spm_unit: members: [person1] - is_tanf_enrolled: true + tanf: 100 meets_tanf_work_requirements: true households: household: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ok/tax/income/ok_stc.yaml b/policyengine_us/tests/policy/baseline/gov/states/ok/tax/income/ok_stc.yaml index 9fdae1540a5..2e35a986b08 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ok/tax/income/ok_stc.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ok/tax/income/ok_stc.yaml @@ -49,7 +49,7 @@ spm_units: spm_unit: members: [head, child] - is_tanf_enrolled: true + tanf: 1_200 households: household: members: [head, child] @@ -58,7 +58,7 @@ # Actual TANF recipients excluded (TANF includes sales tax relief) ok_stc: 0 -- name: OK STC - 2025 - modeled-TANF-eligible family still gets credit +- name: OK STC - 2025 - family not receiving TANF still gets credit period: 2025 input: people: @@ -78,14 +78,15 @@ spm_units: spm_unit: members: [head, spouse, child1, child2, child3, child4] + # The family does not actually receive TANF; zero out the modeled + # amount, as an API user who knows actual receipt would. + tanf: 0 households: household: members: [head, spouse, child1, child2, child3, child4] state_code: OK output: - # Family is not enrolled in TANF (is_tanf_enrolled defaults to false), - # so the credit applies even though the model would impute TANF - # eligibility. 6 exemptions * $40 = $240. See policyengine-taxsim#988. + # 6 exemptions * $40 = $240. See policyengine-taxsim#988. ok_stc: 240 # 2025 Sales Tax Credit Tests @@ -219,3 +220,29 @@ # elderly $50,000 limit and restoring the $40-per-person credit. ok_gross_income: 38_565.84 ok_stc: 80 + +- name: TANF recipients are excluded from the credit. + period: 2024 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 15_000 + person2: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + tanf: 1_200 + households: + household: + members: [person1, person2] + state_code: OK + output: + # Income qualifies under Pathway 1, but TANF receipt excludes the unit. + ok_stc: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/tx/tdhca/ceap/tx_ceap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/tx/tdhca/ceap/tx_ceap_eligible.yaml index 4c60f9e22fe..a2982654b00 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/tx/tdhca/ceap/tx_ceap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/tx/tdhca/ceap/tx_ceap_eligible.yaml @@ -17,7 +17,8 @@ employment_income: 60_000 spm_unit_size: 4 state_code: TX - is_snap_eligible: false + # Isolate the income pathway: BBCE can make these incomes SNAP-positive. + snap: 0 output: tx_ceap_eligible: false @@ -60,17 +61,47 @@ employment_income: 50_000 spm_unit_size: 4 state_code: TX - is_snap_eligible: false + # Isolate the income pathway: BBCE makes this income SNAP-positive. + snap: 0 output: tx_ceap_eligible: false -- name: Case 7, SNAP-eligible household above income limit is categorically eligible. +- name: Case 7, household receiving SNAP above the income limit is categorically eligible. absolute_error_margin: 0.1 period: 2024 input: employment_income: 80_000 spm_unit_size: 1 state_code: TX - is_snap_eligible: true + snap: 2_400 + output: + tx_ceap_eligible: true + +- name: Case 8, household receiving TANF above the income limit is categorically eligible. + period: 2024 + input: + employment_income: 80_000 + spm_unit_size: 1 + state_code: TX + tanf: 1_200 + output: + tx_ceap_eligible: true + +- name: Case 9, household with a member receiving SSI above the income limit is categorically eligible. + period: 2024 + input: + people: + person1: + employment_income: 80_000 + ssi: 0 + person2: + ssi: 9_000 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: TX output: tx_ceap_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.yaml index 989f6389dc0..0328ca10863 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.yaml @@ -117,7 +117,7 @@ # --- (iii) Subject to and complying with TANF work requirements --- -- name: Case 9, TANF enrollee complying with TANF work requirements is exempt. +- name: Case 9, TANF recipient complying with TANF work requirements is exempt. period: 2026-01 input: people: @@ -128,11 +128,11 @@ spm_units: spm_unit: members: [person1] - is_tanf_enrolled: true + tanf: 100 output: is_snap_work_registration_exempt_non_age: true -- name: Case 10, complying with TANF work requirements but not enrolled in TANF is not exempt. +- name: Case 10, complying with TANF work requirements but not receiving TANF is not exempt. period: 2026-01 input: people: @@ -143,11 +143,11 @@ spm_units: spm_unit: members: [person1] - is_tanf_enrolled: false + tanf: 0 output: is_snap_work_registration_exempt_non_age: false -- name: Case 11, TANF enrollee not complying with TANF work requirements is not exempt. +- name: Case 11, TANF recipient not complying with TANF work requirements is not exempt. period: 2026-01 input: people: @@ -158,7 +158,7 @@ spm_units: spm_unit: members: [person1] - is_tanf_enrolled: true + tanf: 100 output: is_snap_work_registration_exempt_non_age: false diff --git a/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_community_engagement_pass_through_eligible.py b/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_community_engagement_pass_through_eligible.py index df5768470a9..d29502f24eb 100644 --- a/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_community_engagement_pass_through_eligible.py +++ b/policyengine_us/variables/gov/hhs/medicaid/eligibility/medicaid_community_engagement_pass_through_eligible.py @@ -14,7 +14,7 @@ class medicaid_community_engagement_pass_through_eligible(Variable): def formula(person, period, parameters): snap_work = parameters(period).gov.usda.snap.work_requirements snap = person.spm_unit("snap", period) > 0 - tanf = person.spm_unit("is_tanf_enrolled", period) + tanf = person.spm_unit("tanf", period) > 0 age = person("monthly_age", period) # Cast to bool: single_amount bool brackets return int (0/1), which diff --git a/policyengine_us/variables/gov/states/ok/tax/income/credits/ok_stc.py b/policyengine_us/variables/gov/states/ok/tax/income/credits/ok_stc.py index c4988fec04d..eb3eedaf0f9 100644 --- a/policyengine_us/variables/gov/states/ok/tax/income/credits/ok_stc.py +++ b/policyengine_us/variables/gov/states/ok/tax/income/credits/ok_stc.py @@ -63,11 +63,9 @@ class ok_stc(Variable): def formula(tax_unit, period, parameters): # For details, see Form 538-S in the 511 packets referenced above p = parameters(period).gov.states.ok.tax.income.credits.sales_tax - # Exclusion: TANF recipients are not eligible. Use actual enrollment - # (is_tanf_enrolled) rather than the modeled ok_tanf benefit, so that - # tax filers who are not receiving TANF still qualify even when the - # model would impute TANF eligibility for them. - tanf_ineligible = add(tax_unit, period, ["is_tanf_enrolled"]) > 0 + # Exclusion: TANF recipients are not eligible, keyed on the + # calculated tanf benefit. + tanf_ineligible = add(tax_unit, period, ["tanf"]) > 0 # Get gross household income for eligibility tests income = tax_unit("ok_gross_income", period) # Pathway 1: Low income (gross income <= $20,000) diff --git a/policyengine_us/variables/gov/states/tx/tdhca/ceap/tx_ceap_eligible.py b/policyengine_us/variables/gov/states/tx/tdhca/ceap/tx_ceap_eligible.py index ea200411c75..2ea6afba4b4 100644 --- a/policyengine_us/variables/gov/states/tx/tdhca/ceap/tx_ceap_eligible.py +++ b/policyengine_us/variables/gov/states/tx/tdhca/ceap/tx_ceap_eligible.py @@ -31,12 +31,12 @@ def formula(spm_unit, period, parameters): income_limit = max_(fpg_limit, smi_limit) income_eligible = income <= income_limit - # Categorical eligibility per 42 USC 8624(b)(2)(A) - # and FY 2024 State Plan Section 1.4 - tanf = spm_unit("is_tanf_enrolled", period) - snap = spm_unit("is_snap_eligible", period) - person = spm_unit.members - ssi = spm_unit.any(person("is_ssi_eligible", period)) + # Categorical eligibility per 42 USC 8624(b)(2)(A) and FY 2024 + # State Plan Section 1.4: households where a member receives + # TANF, SNAP, or SSI. + tanf = spm_unit("tanf", period) > 0 + snap = spm_unit("snap", period) > 0 + ssi = add(spm_unit, period, ["ssi"]) > 0 categorically_eligible = tanf | snap | ssi return income_eligible | categorically_eligible diff --git a/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.py b/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.py index 257b5ee023e..db8873890e9 100644 --- a/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.py +++ b/policyengine_us/variables/gov/usda/snap/eligibility/work_requirements/is_snap_work_registration_exempt_non_age.py @@ -21,13 +21,12 @@ def formula(person, period, parameters): # (ii) Physically or mentally unfit for employment is_disabled = person("is_disabled", period) # (iii) Subject to and complying with TANF work requirements. - # TANF enrollment is an existing SPM-unit input; person-level - # compliance is a documented input the data layer may not yet - # populate (PolicyEngine/populace#244). We gate on enrollment - # because a person cannot be subject to TANF work requirements - # without receiving TANF. - complying_with_tanf_work_requirements = person.spm_unit( - "is_tanf_enrolled", period + # Person-level compliance is a documented input the data layer + # may not yet populate (PolicyEngine/populace#244). We gate on + # calculated TANF receipt because a person cannot be subject to + # TANF work requirements without receiving TANF. + complying_with_tanf_work_requirements = ( + person.spm_unit("tanf", period) > 0 ) & person("is_complying_with_tanf_work_requirements", period) # (iv) Responsible for care of dependent child under 6 is_dependent = person("is_tax_unit_dependent", period)