diff --git a/changelog.d/statute-bugs-ccap-tanf-snap-ssi.fixed.md b/changelog.d/statute-bugs-ccap-tanf-snap-ssi.fixed.md new file mode 100644 index 00000000000..0886adcea9f --- /dev/null +++ b/changelog.d/statute-bugs-ccap-tanf-snap-ssi.fixed.md @@ -0,0 +1 @@ +Follow the rules on four benefit calculations: Missouri TANF payments are lowered to the whole dollar (13 CSR 40-2.310(14)); SNAP income limits in Guam and the Virgin Islands use the contiguous-state poverty guidelines (7 CFR 273.9(a)); Hawaii CCAP counts Hawaii TANF payments from August 6, 2021 (HAR 17-798.3-10(b)(11)), and the Hawaii TANF care deduction covers incapacitated adults only (HAR 17-676-54.1); and SSI stops counting food as in-kind support and maintenance from September 30, 2024, with the ISM chain and countable income computed monthly. diff --git a/policyengine_us/parameters/gov/ssa/ssi/income/ism/food_counts.yaml b/policyengine_us/parameters/gov/ssa/ssi/income/ism/food_counts.yaml index 1b71f32aebd..b52ce4968fe 100644 --- a/policyengine_us/parameters/gov/ssa/ssi/income/ism/food_counts.yaml +++ b/policyengine_us/parameters/gov/ssa/ssi/income/ism/food_counts.yaml @@ -1,13 +1,13 @@ description: SSA uses this indicator to determine whether food counts in SSI in-kind support and maintenance calculations. -# NOTE: This parameter flips on 2024-10-01, but the consuming variables -# (ssi_pmv_applies, ssi_in_kind_support_and_maintenance, etc.) are -# YEAR-defined, so parameters(period) resolves to January 1 of the year. -# In practice the change takes effect in 2025, not October 2024. -# Converting the ISM chain to MONTH would fix this. +# The final rule removing food from in-kind support and maintenance took +# effect September 30, 2024 (89 FR 21199, DATES). The consuming variables +# are MONTH-defined and read this value at the start of each month; +# ssi_pmv_applies also reads it at the end of the month to find the month in +# which food stops counting. values: 1975-01-01: true - 2024-10-01: false + 2024-09-30: false metadata: unit: bool @@ -16,5 +16,5 @@ metadata: reference: - title: 20 CFR § 416.1130 - Introduction to in-kind support and maintenance (as amended) href: https://www.law.cornell.edu/cfr/text/20/416.1130 - - title: 89 FR 21199 - Omitting Food from In-Kind Support and Maintenance Calculations - href: https://www.federalregister.gov/documents/2024/03/27/2024-06464/omitting-food-from-in-kind-support-and-maintenance-calculations + - title: "89 FR 21199, Omitting Food from In-Kind Support and Maintenance Calculations #page 1,11" + href: https://www.govinfo.gov/content/pkg/FR-2024-03-27/pdf/2024-06464.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/hi/bessd/ccap/income/countable_income/sources.yaml b/policyengine_us/parameters/gov/states/hi/bessd/ccap/income/countable_income/sources.yaml index 44869e1041a..0ceb73c5e5c 100644 --- a/policyengine_us/parameters/gov/states/hi/bessd/ccap/income/countable_income/sources.yaml +++ b/policyengine_us/parameters/gov/states/hi/bessd/ccap/income/countable_income/sources.yaml @@ -32,17 +32,41 @@ values: # - royalties (item (17)) # - free rent converted to cost compensation (item (19)); # we don't track in-kind rent-for-activity at the moment - # HAR 17-798.2-10(b)(11) counts Hawaii public assistance (TANF), but we do - # NOT add `tanf` here to avoid the CCAP<->TANF circular dependency (CCAP - # income -> tanf -> TANF dependent-care deduction -> childcare_expenses -> - # child_care_subsidies -> CCAP). TANF families fall well below the lowest - # copay band, so the omission does not change their subsidy in practice. + # Hawaii public assistance (item (11)) is counted from August 6, 2021, + # under the replacement HAR 17-798.3-10(b)(11) (see the entry below). + # The predecessor 17-798.2-10(b)(11) lists it too, but the edition in + # force from August 2017 was not established, so this period keeps the + # earlier list. # Items (10) out-of-state public assistance and (12) adoption assistance # have no clean PolicyEngine income input. # Excluded per HAR 17-798.2-11 (omitted from the list above): capital # gains, SNAP, WIC, USDA donated foods, EITC, Title IV HEA aid, lump sums, # and others. The half-time+ student-minor earnings exclusion (item (8)) is # applied as a formula filter in hi_ccap_countable_income. + 2021-08-06: + # Same sources as above, plus Hawaii TANF payments before any + # overpayment-recovery reduction (HAR 17-798.3-10(b)(11), eff. + # 2021-08-06). hi_ccap_tanf_income explains why it reads hi_tanf + # rather than tanf. + - employment_income + - self_employment_income + - sstb_self_employment_income + - social_security_retirement + - social_security_disability + - social_security_survivors + - ssi + - dividend_income + - interest_income + - rental_income + - pension_income + - veterans_benefits + - military_retirement_pay + - total_unemployment_compensation + - strike_benefits + - workers_compensation + - alimony_income + - child_support_received + - hi_ccap_tanf_income metadata: unit: list @@ -55,6 +79,8 @@ metadata: # and unearned income. - title: HAR 17-798.3-10(b) and 17-798.3-11 href: https://humanservices.hawaii.gov/bessd/files/2021/09/CHAPTER-17-798.3-Child-Care-Payments.pdf#page=24 + - title: HAR 17-798.3-10(b)(11), Hawaii public assistance payments + href: https://www.law.cornell.edu/regulations/hawaii/Haw-Code-R-SS-17-798-3-10 - title: HAR 17-798.2-10(b) href: https://humanservices.hawaii.gov/bessd/files/2013/01/HAR-17-798.2-Child-Care-Services-Rules.pdf#page=19 - title: HAR 17-798.2-11 diff --git a/policyengine_us/parameters/gov/states/hi/dhs/tanf/deductions/dependent_care/amount.yaml b/policyengine_us/parameters/gov/states/hi/dhs/tanf/deductions/dependent_care/amount.yaml index ea7849163c4..acaec185182 100644 --- a/policyengine_us/parameters/gov/states/hi/dhs/tanf/deductions/dependent_care/amount.yaml +++ b/policyengine_us/parameters/gov/states/hi/dhs/tanf/deductions/dependent_care/amount.yaml @@ -1,25 +1,25 @@ -description: Hawaii deducts up to this amount for dependent care expenses based on employment hours under the Temporary Assistance for Needy Families program. +description: Hawaii deducts up to this amount for the actual cost of care of each incapacitated adult in the household, based on the applicant's weekly hours of employment, under the Temporary Assistance for Needy Families program. metadata: type: single_amount threshold_unit: hour amount_unit: currency-USD period: month - label: Hawaii TANF dependent care deduction amount + label: Hawaii TANF incapacitated adult care deduction amount reference: + - title: "HAR 17-676-54.1(c)(4) and (d)(4); HAR 17-676-2 full-time employed #page 6,36-37" + href: https://humanservices.hawaii.gov/wp-content/uploads/2019/03/HAR-17-676-INCOME.pdf#page=6 - title: Hawaii TANF State Plan 10.2.2 (Effective October 1, 2023) href: https://humanservices.hawaii.gov/wp-content/uploads/2024/12/Hawaii_TANF_State_Plan_Signed_Certified-Eff_20231001.pdf#page=20 - - title: HAR 17-676-2 Earned income (1) - href: https://humanservices.hawaii.gov/wp-content/uploads/2019/03/HAR-17-676-INCOME.pdf#page=6 -# Full-time = 32+ hours/week per HAR 17-676 -# Part-time = less than 32 hours/week +# Full time = employed 32 or more hours a week (HAR 17-676-2). +# Less than full time = under 32 hours a week. brackets: - threshold: 2007-07-01: 0 amount: - 2007-07-01: 165 # Part-time + 2007-07-01: 165 # Less than full time - threshold: 2007-07-01: 32 amount: - 2007-07-01: 175 # Full-time + 2007-07-01: 175 # Full time diff --git a/policyengine_us/parameters/gov/states/mo/dss/tanf/minimum_payment.yaml b/policyengine_us/parameters/gov/states/mo/dss/tanf/minimum_payment.yaml index 546e356614e..629b468d621 100644 --- a/policyengine_us/parameters/gov/states/mo/dss/tanf/minimum_payment.yaml +++ b/policyengine_us/parameters/gov/states/mo/dss/tanf/minimum_payment.yaml @@ -9,5 +9,7 @@ metadata: period: month label: Missouri TANF minimum payment reference: + - title: 13 CSR 40-2.310(14) + href: https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-2.pdf#page=36 - title: Missouri DSS Manual 0210.010.15 - Payment Determination href: https://dssmanuals.mo.gov/temporary-assistance-case-management/0210-010-15/ diff --git a/policyengine_us/tests/code_health/test_source_conflicts.py b/policyengine_us/tests/code_health/test_source_conflicts.py index 8512cb59e88..3ba17002545 100644 --- a/policyengine_us/tests/code_health/test_source_conflicts.py +++ b/policyengine_us/tests/code_health/test_source_conflicts.py @@ -119,12 +119,10 @@ "policyengine_us/parameters/gov/irs/credits/residential_clean_energy/fuel_cell_cap_per_kw.yaml": 1, "policyengine_us/parameters/gov/irs/income/exemption/overtime/hce_salary_threshold.yaml": 1, "policyengine_us/parameters/gov/irs/income/exemption/overtime/salary_basis_threshold.yaml": 1, - "policyengine_us/parameters/gov/ssa/ssi/income/ism/food_counts.yaml": 1, "policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml": 1, "policyengine_us/parameters/gov/states/ca/cpuc/income_sources.yaml": 1, "policyengine_us/parameters/gov/states/co/doi/premium_assistance/amount/additional_member.yaml": 1, "policyengine_us/parameters/gov/states/co/doi/premium_assistance/amount/first_member.yaml": 1, - "policyengine_us/parameters/gov/states/hi/bessd/ccap/income/countable_income/sources.yaml": 1, "policyengine_us/parameters/gov/states/ma/hic/connector_care/fpl_floor.yaml": 1, "policyengine_us/parameters/gov/states/mo/tax/income/deductions/federal_income_tax/ignored_credits.yaml": 1, "policyengine_us/parameters/gov/states/mt/tax/income/subtractions/disability_income/cap.yaml": 1, diff --git a/policyengine_us/tests/core/test_mo_tanf_dependent_parent_properties.py b/policyengine_us/tests/core/test_mo_tanf_dependent_parent_properties.py index 5312218b384..b75ffb32e8b 100644 --- a/policyengine_us/tests/core/test_mo_tanf_dependent_parent_properties.py +++ b/policyengine_us/tests/core/test_mo_tanf_dependent_parent_properties.py @@ -60,7 +60,8 @@ PERIOD = "2026-01" YEAR = 2026 -# 13 CSR 40-2.310(13) standard of need and (12) payment percentage. +# 13 CSR 40-2.310(13) standard of need and (12) payment percentage; (14) +# lowers the payment to the whole dollar (see _payment). STANDARD_OF_NEED = {1: 393, 2: 678, 3: 846, 4: 990, 5: 1_123, 6: 1_247} PAYMENT_PERCENTAGE = 0.34526 @@ -210,7 +211,8 @@ def _calc(sim, variable): def _payment(size): - return STANDARD_OF_NEED.get(int(size), 0) * PAYMENT_PERCENTAGE + # 13 CSR 40-2.310(14) lowers the payment to the whole dollar. + return np.floor(STANDARD_OF_NEED.get(int(size), 0) * PAYMENT_PERCENTAGE) def _adult_is_dependent_child(h): diff --git a/policyengine_us/tests/core/test_mo_tanf_non_parent_caretaker_properties.py b/policyengine_us/tests/core/test_mo_tanf_non_parent_caretaker_properties.py index dc5ce09318e..d3570cdcb4f 100644 --- a/policyengine_us/tests/core/test_mo_tanf_non_parent_caretaker_properties.py +++ b/policyengine_us/tests/core/test_mo_tanf_non_parent_caretaker_properties.py @@ -44,7 +44,8 @@ YEAR = 2026 N = 480 SEED = 20260928 -# 13 CSR 40-2.310(13) standard of need and (12) payment percentage. +# 13 CSR 40-2.310(13) standard of need and (12) payment percentage; (14) +# lowers the payment to the whole dollar (see _payment). STANDARD_OF_NEED = {1: 393, 2: 678, 3: 846, 4: 990, 5: 1_123} PAYMENT_PERCENTAGE = 0.34526 WORK_EXPENSE = 90 @@ -179,7 +180,8 @@ def _person_index(): def _payment(size): - return STANDARD_OF_NEED.get(size, 0) * PAYMENT_PERCENTAGE + # 13 CSR 40-2.310(14) lowers the payment to the whole dollar. + return np.floor(STANDARD_OF_NEED.get(size, 0) * PAYMENT_PERCENTAGE) def test_unflagged_households_include_dependent_parents(unflagged_sim): diff --git a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/ism/ssi_in_kind_support_and_maintenance.yaml b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/ism/ssi_in_kind_support_and_maintenance.yaml index 195518591b6..48a393c495c 100644 --- a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/ism/ssi_in_kind_support_and_maintenance.yaml +++ b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/eligibility/income/ism/ssi_in_kind_support_and_maintenance.yaml @@ -69,3 +69,63 @@ ssi_medicaid_pays_majority_of_care: true output: ssi_in_kind_support_and_maintenance: 0 + +- name: Case 6, food-only support does not trigger PMV in October 2024. + period: 2024-10 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ssi_federal_living_arrangement: OWN_HOUSEHOLD + ssi_receives_food_from_others: true + ssi_receives_outside_shelter_support: false + ssi_receives_shelter_from_others_in_household: false + output: + # Food stopped counting as ISM on September 30, 2024 (89 FR 21199). + ssi_pmv_applies: false + ssi_in_kind_support_and_maintenance: 0 + +- name: Case 7, food-only support triggers PMV before the exclusion. + period: 2024-08 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ssi_federal_living_arrangement: OWN_HOUSEHOLD + ssi_receives_food_from_others: true + ssi_receives_outside_shelter_support: false + ssi_receives_shelter_from_others_in_household: false + ssi_pmv_amount: 334.33 + output: + # $943 / 3 + $20 = $334.33 monthly PMV (20 CFR 416.1140(a)(1)). + ssi_pmv_applies: true + ssi_in_kind_support_and_maintenance: 334.33 + +- name: Case 8, shelter support continues to trigger PMV after the exclusion. + period: 2024-10 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + ssi_federal_living_arrangement: OWN_HOUSEHOLD + ssi_receives_food_from_others: false + ssi_receives_outside_shelter_support: true + ssi_receives_shelter_from_others_in_household: false + ssi_pmv_amount: 334.33 + output: + ssi_pmv_applies: true + ssi_in_kind_support_and_maintenance: 334.33 + +- name: Case 9, monthly PMV amount for an individual in 2024. + period: 2024-10 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + output: + # $943 / 3 + $20, a monthly amount. + ssi_pmv_amount: 334.33 diff --git a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/ssi_living_arrangement_integration.yaml b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/ssi_living_arrangement_integration.yaml index ebf2ccf7c70..cda76a0eb43 100644 --- a/policyengine_us/tests/policy/baseline/gov/ssa/ssi/ssi_living_arrangement_integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/ssa/ssi/ssi_living_arrangement_integration.yaml @@ -196,8 +196,8 @@ is_disabled: true meets_ssi_disability_criteria: true ssi_receives_outside_shelter_support: true - # Actual annual shelter value $1,200 ($100/month electric bill) - ssi_shelter_support_value: 1_200 + # Actual monthly shelter value $100 (electric bill) + ssi_shelter_support_value: 100 spm_units: spm_unit: members: [person1] @@ -207,9 +207,8 @@ output: ssi_federal_living_arrangement: OWN_HOUSEHOLD ssi_pmv_applies: true - # PMV annual = 342.33 * 12 = 4,108 - # Actual = 1,200 < PMV → use actual - # ISM monthly = 1,200 / 12 = 100 + # PMV monthly = 342.33 + # Actual = 100 < PMV → use actual ssi_in_kind_support_and_maintenance: 100 # Countable = (100 - 20) = 80 (after $20 general exclusion) ssi_countable_income: 80 @@ -245,6 +244,146 @@ uncapped_ssi: 628.67 ssi: 628.67 +- name: Case 9b, food-only support in October 2024 no longer triggers PMV. + period: 2024-10 + absolute_error_margin: 0.01 + input: + people: + person1: + # Year-defined inputs are keyed to the calendar year so that a + # non-January test month still reads them. + age: + 2024: 40 + is_disabled: + 2024: true + meets_ssi_disability_criteria: + 2024: true + ssi_receives_food_from_others: true + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + output: + ssi_federal_living_arrangement: OWN_HOUSEHOLD + # Food stopped counting as ISM on September 30, 2024 (89 FR 21199). + # Before this change the 2024 exclusion waited until January 2025. + ssi_pmv_applies: false + ssi_in_kind_support_and_maintenance: 0 + ssi_countable_income: 0 + uncapped_ssi: 943 + ssi: 943 + +- name: Case 9c, food-only support in September 2024 still triggers PMV. + period: 2024-09 + absolute_error_margin: 0.01 + input: + people: + person1: + # Year-defined inputs are keyed to the calendar year so that a + # non-January test month still reads them. + age: + 2024: 40 + is_disabled: + 2024: true + meets_ssi_disability_criteria: + 2024: true + ssi_receives_food_from_others: true + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + output: + # Food received from September 1 to 29 still counts; the PMV is not + # prorated by day. + ssi_pmv_applies: true + ssi_in_kind_support_and_maintenance: 334.33 + ssi_countable_income: 314.33 + ssi: 628.67 + +- name: Case 9d, September 2024 food received only on or after September 30 does not trigger PMV. + period: 2024-09 + absolute_error_margin: 0.01 + input: + people: + person1: + # Year-defined inputs are keyed to the calendar year so that a + # non-January test month still reads them. + age: + 2024: 40 + is_disabled: + 2024: true + meets_ssi_disability_criteria: + 2024: true + ssi_receives_food_from_others: true + ssi_food_from_others_only_on_or_after_food_exclusion: true + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + output: + ssi_pmv_applies: false + ssi_in_kind_support_and_maintenance: 0 + ssi_countable_income: 0 + ssi: 943 + +- name: Case 9e, the September 30 flag does not affect a month after the exclusion starts. + period: 2024-08 + absolute_error_margin: 0.01 + input: + people: + person1: + # Year-defined inputs are keyed to the calendar year so that a + # non-January test month still reads them. + age: + 2024: 40 + is_disabled: + 2024: true + meets_ssi_disability_criteria: + 2024: true + ssi_receives_food_from_others: true + ssi_food_from_others_only_on_or_after_food_exclusion: true + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + output: + # August 2024 ends before September 30, so its food counts. + ssi_pmv_applies: true + ssi_in_kind_support_and_maintenance: 334.33 + +- name: Case 9f, a year of food-only support counts ISM for January through September 2024. + period: 2024 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 40 + is_disabled: true + meets_ssi_disability_criteria: true + ssi_receives_food_from_others: true + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + output: + # 9 x ($943 / 3 + $20) = 9 x 334.333 = 3,009; before this change the + # model counted all 12 months ($4,012). + ssi_in_kind_support_and_maintenance: 3_009 + # 9 x 314.333 = 2,829 + ssi_countable_income: 2_829 + # 9 x 628.667 + 3 x 943 = 5,658 + 2,829 = 8,487 + ssi: 8_487 + - name: Case 10, food-only support after 9/30/2024 does not trigger PMV. period: 2025-01 absolute_error_margin: 0.01 @@ -355,8 +494,8 @@ is_disabled: true meets_ssi_disability_criteria: true ssi_receives_outside_shelter_support: true - # Actual annual shelter value $6,000 exceeds PMV ($4,108) - ssi_shelter_support_value: 6_000 + # Actual monthly shelter value $500 exceeds PMV ($342.33) + ssi_shelter_support_value: 500 spm_units: spm_unit: members: [person1] @@ -366,8 +505,8 @@ output: ssi_federal_living_arrangement: OWN_HOUSEHOLD ssi_pmv_applies: true - # PMV annual = 342.33 * 12 = 4,108 - # Actual = 6,000 > PMV → capped at PMV + # PMV monthly = 342.33 + # Actual = 500 > PMV → capped at PMV # ISM monthly = 342.33 (PMV, not 500) ssi_in_kind_support_and_maintenance: 342.33 # Countable = 342.33 - 20 = 322.33 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/copay/hi_ccap_copay.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/copay/hi_ccap_copay.yaml index 65ff2be8a04..3f834da616a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/copay/hi_ccap_copay.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/copay/hi_ccap_copay.yaml @@ -12,7 +12,7 @@ people: person1: age: 30 - employment_income: 56_000 # 4,666.67/mo, FPG ratio 2.30+ -> 9% + employment_income_before_lsr: 56_000 # 4,666.67/mo, FPG ratio 2.30+ -> 9% immigration_status: CITIZEN person2: age: 4 @@ -41,7 +41,7 @@ people: person1: age: 30 - employment_income: 40_800 # 3,400/mo, FPG ratio 1.68 -> 5% + employment_income_before_lsr: 40_800 # 3,400/mo, FPG ratio 1.68 -> 5% immigration_status: CITIZEN person2: age: 1 # < 36 months -> INFANT_TODDLER rate @@ -70,7 +70,7 @@ people: person1: age: 30 - employment_income: 12_000 # 1,000/mo, FPG ratio 0.49 -> 0% + employment_income_before_lsr: 12_000 # 1,000/mo, FPG ratio 0.49 -> 0% immigration_status: CITIZEN person2: age: 4 @@ -101,7 +101,7 @@ people: person1: age: 25 - employment_income: 43_584 # 3,632/mo + employment_income_before_lsr: 43_584 # 3,632/mo immigration_status: CITIZEN tax_units: tax_unit: @@ -130,7 +130,7 @@ people: person1: age: 30 - employment_income: 56_000 # 4,666.67/mo, far above 230% FPG -> 9% + employment_income_before_lsr: 56_000 # 4,666.67/mo, far above 230% FPG -> 9% immigration_status: CITIZEN person2: age: 4 @@ -159,7 +159,7 @@ people: person1: age: 30 - employment_income: 56_000 # 4,666.67/mo, far above 230% FPG -> 9% + employment_income_before_lsr: 56_000 # 4,666.67/mo, far above 230% FPG -> 9% immigration_status: CITIZEN person2: age: 4 @@ -193,7 +193,7 @@ people: person1: age: 30 - employment_income: 56_000 # 4,666.67/mo, FPG ratio 2.79 -> 9% + employment_income_before_lsr: 56_000 # 4,666.67/mo, FPG ratio 2.79 -> 9% immigration_status: CITIZEN person2: age: 4 @@ -235,7 +235,7 @@ people: person1: age: 30 - employment_income: 66_000 # 5,500/mo, FPG ratio 2.61 -> 9% + employment_income_before_lsr: 66_000 # 5,500/mo, FPG ratio 2.61 -> 9% immigration_status: CITIZEN person2: age: 1 # < 36 months -> INFANT_TODDLER rate @@ -271,7 +271,7 @@ people: person1: age: 30 - employment_income: 66_000 # 5,500/mo, FPG ratio 2.49 -> 9% + employment_income_before_lsr: 66_000 # 5,500/mo, FPG ratio 2.49 -> 9% immigration_status: CITIZEN person2: age: 1 # < 36 months -> INFANT_TODDLER rate @@ -299,3 +299,39 @@ hi_ccap_maximum_monthly_rate: [0, 1_733, 795] hi_ccap_copay_rate: 0.09 hi_ccap_copay: 495 + +- name: Counted Hawaii TANF payments can move a family out of the zero co-payment band. + period: 2025-01 + absolute_error_margin: 0.001 + input: + people: + parent: + age: 30 + employment_income_before_lsr: 30_000 # 2,500/month + spouse: + age: 30 + is_disabled: true + child: + age: 5 + hi_ccap_maximum_monthly_rate: 1_000 + spm_units: + unit: + members: [parent, spouse, child] + hi_tanf: 153.64 # monthly + spm_unit_fpg: 30_650 + spm_unit_pre_subsidy_childcare_expenses: 6_000 + hi_ccap_eligible: true + households: + household: + members: [parent, spouse, child] + state_code: HI + output: + # Countable income = $2,500 + $153.64 Hawaii TANF = $2,653.64 + # (HAR 17-798.3-10(b)(11)). Monthly FPG = $30,650 / 12 = $2,554.17, so + # income is about 103.9% of FPG: the 1% band. Without the TANF income, + # $2,500 is under 100% of FPG and the co-payment is zero. + hi_ccap_countable_income: 2_653.64 + hi_ccap_copay_rate: 0.01 + hi_ccap_copay: 26.5364 + # min($6,000 / 12, $1,000) - $26.5364 = $473.4636 + hi_ccap: 473.4636 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/copay/hi_ccap_copay_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/copay/hi_ccap_copay_rate.yaml index 8906ff01a9c..d776ad2ac65 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/copay/hi_ccap_copay_rate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/copay/hi_ccap_copay_rate.yaml @@ -16,7 +16,7 @@ people: person1: age: 30 - employment_income: 12_000 # 1,000/mo, ratio 0.49 + employment_income_before_lsr: 12_000 # 1,000/mo, ratio 0.49 immigration_status: CITIZEN person2: age: 4 @@ -41,7 +41,7 @@ people: person1: age: 30 - employment_income: 24_320 # 2,026.67/mo, ratio exactly 1.00 + employment_income_before_lsr: 24_320 # 2,026.67/mo, ratio exactly 1.00 immigration_status: CITIZEN person2: age: 4 @@ -67,7 +67,7 @@ people: person1: age: 30 - employment_income: 26_280 # 2,190/mo, ratio 1.08 + employment_income_before_lsr: 26_280 # 2,190/mo, ratio 1.08 immigration_status: CITIZEN person2: age: 4 @@ -92,7 +92,7 @@ people: person1: age: 30 - employment_income: 30_000 # 2,500/mo, ratio 1.23 + employment_income_before_lsr: 30_000 # 2,500/mo, ratio 1.23 immigration_status: CITIZEN person2: age: 4 @@ -117,7 +117,7 @@ people: person1: age: 30 - employment_income: 34_080 # 2,840/mo, ratio 1.40 + employment_income_before_lsr: 34_080 # 2,840/mo, ratio 1.40 immigration_status: CITIZEN person2: age: 4 @@ -142,7 +142,7 @@ people: person1: age: 30 - employment_income: 37_200 # 3,100/mo, ratio 1.53 + employment_income_before_lsr: 37_200 # 3,100/mo, ratio 1.53 immigration_status: CITIZEN person2: age: 4 @@ -167,7 +167,7 @@ people: person1: age: 30 - employment_income: 40_800 # 3,400/mo, ratio 1.68 + employment_income_before_lsr: 40_800 # 3,400/mo, ratio 1.68 immigration_status: CITIZEN person2: age: 4 @@ -192,7 +192,7 @@ people: person1: age: 30 - employment_income: 44_400 # 3,700/mo, ratio 1.83 + employment_income_before_lsr: 44_400 # 3,700/mo, ratio 1.83 immigration_status: CITIZEN person2: age: 4 @@ -217,7 +217,7 @@ people: person1: age: 30 - employment_income: 48_000 # 4,000/mo, ratio 1.97 + employment_income_before_lsr: 48_000 # 4,000/mo, ratio 1.97 immigration_status: CITIZEN person2: age: 4 @@ -242,7 +242,7 @@ people: person1: age: 30 - employment_income: 53_040 # 4,420/mo, ratio 2.18 + employment_income_before_lsr: 53_040 # 4,420/mo, ratio 2.18 immigration_status: CITIZEN person2: age: 4 @@ -267,7 +267,7 @@ people: person1: age: 30 - employment_income: 56_000 # 4,666.67/mo, ratio 2.30 (just above) + employment_income_before_lsr: 56_000 # 4,666.67/mo, ratio 2.30 (just above) immigration_status: CITIZEN person2: age: 4 @@ -293,7 +293,7 @@ people: person1: age: 30 - employment_income: 58_320 # 4,860/mo, ratio 2.40 + employment_income_before_lsr: 58_320 # 4,860/mo, ratio 2.40 immigration_status: CITIZEN person2: age: 4 @@ -320,7 +320,7 @@ people: person1: age: 30 - employment_income: 0 # ratio 0.00 -> 0% band + employment_income_before_lsr: 0 # ratio 0.00 -> 0% band immigration_status: CITIZEN person2: age: 4 @@ -331,6 +331,9 @@ spm_units: spm_unit: members: [person1, person2] + # Without earnings the family would qualify for Hawaii TANF, which + # CCAP counts (HAR 17-798.3-10(b)(11)); this case has no TANF. + takes_up_tanf_if_eligible: false households: household: members: [person1, person2] diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/eligibility/hi_ccap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/eligibility/hi_ccap_income_eligible.yaml index bb332b42a48..822ec799ad0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/eligibility/hi_ccap_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/eligibility/hi_ccap_income_eligible.yaml @@ -12,7 +12,7 @@ people: person1: age: 30 - employment_income: 72_000 # 6,000/month + employment_income_before_lsr: 72_000 # 6,000/month immigration_status: CITIZEN person2: age: 4 @@ -37,7 +37,7 @@ people: person1: age: 30 - employment_income: 78_000 # 6,500/month + employment_income_before_lsr: 78_000 # 6,500/month immigration_status: CITIZEN person2: age: 4 @@ -62,7 +62,7 @@ people: person1: age: 35 - employment_income: 200_000 # 16,666.67/month, far above limit + employment_income_before_lsr: 200_000 # 16,666.67/month, far above limit immigration_status: CITIZEN person2: age: 6 @@ -88,7 +88,7 @@ people: person1: age: 35 - employment_income: 200_000 # 16,666.67/month + employment_income_before_lsr: 200_000 # 16,666.67/month immigration_status: CITIZEN person2: age: 6 @@ -138,7 +138,7 @@ person1: age: 30 # 74,624/yr = 6,218.667/mo (~3.5 cents under the 6,218.7017 ceiling) - employment_income: 74_624 + employment_income_before_lsr: 74_624 immigration_status: CITIZEN person2: age: 4 @@ -164,7 +164,7 @@ person1: age: 30 # 74,648.42/yr = 6,220.7017/mo (= ceiling + 2/mo, clearly over) - employment_income: 74_648.42 + employment_income_before_lsr: 74_648.42 immigration_status: CITIZEN person2: age: 4 @@ -191,7 +191,7 @@ age: 30 # Family-of-1 ceiling = 129,108 x 0.52 x 0.85 / 12 = 4,755.4780/mo. # 57,060/yr = 4,755.00/mo (just under the ceiling) -> eligible - employment_income: 57_060 + employment_income_before_lsr: 57_060 immigration_status: CITIZEN spm_units: spm_unit: @@ -212,7 +212,7 @@ # Family-of-8 ceiling = 129,108 x 1.38 x 0.85 / 12 = 12,620.3070/mo. # adj = 0.52 + 0.16x5 + 0.03x2 = 1.38 (the 7th/8th use 0.03 each). # 151,000/yr = 12,583.33/mo, just under the ceiling -> eligible. - employment_income: 151_000 + employment_income_before_lsr: 151_000 immigration_status: CITIZEN person2: age: 38 @@ -255,7 +255,7 @@ person1: age: 40 # 152,000/yr = 12,666.67/mo > 12,620.31 ceiling -> ineligible - employment_income: 152_000 + employment_income_before_lsr: 152_000 immigration_status: CITIZEN person2: age: 38 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/hi_ccap.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/hi_ccap.yaml index 6ed40870741..f879cdbb800 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/hi_ccap.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/hi_ccap.yaml @@ -10,7 +10,7 @@ people: person1: age: 30 - employment_income: 12_000 # low income -> 0% copay + employment_income_before_lsr: 12_000 # low income -> 0% copay weekly_hours_worked_before_lsr: 40 immigration_status: CITIZEN person2: @@ -42,7 +42,7 @@ people: person1: age: 30 - employment_income: 12_000 + employment_income_before_lsr: 12_000 weekly_hours_worked_before_lsr: 40 immigration_status: CITIZEN person2: @@ -73,7 +73,7 @@ people: person1: age: 30 - employment_income: 56_000 # 4,666.67/mo, FPG ratio 2.30+ -> 9% + employment_income_before_lsr: 56_000 # 4,666.67/mo, FPG ratio 2.30+ -> 9% weekly_hours_worked_before_lsr: 40 immigration_status: CITIZEN person2: @@ -105,7 +105,7 @@ people: person1: age: 30 - employment_income: 12_000 + employment_income_before_lsr: 12_000 weekly_hours_worked_before_lsr: 40 immigration_status: CITIZEN person2: @@ -173,7 +173,7 @@ people: person1: age: 30 - employment_income: 0 + employment_income_before_lsr: 0 weekly_hours_worked_before_lsr: 0 is_full_time_student: false is_disabled: false @@ -208,7 +208,7 @@ people: person1: age: 30 - employment_income: 56_000 # 4,666.67/mo, FPG ratio 2.30+ -> 9% + employment_income_before_lsr: 56_000 # 4,666.67/mo, FPG ratio 2.30+ -> 9% weekly_hours_worked_before_lsr: 40 immigration_status: CITIZEN person2: @@ -241,7 +241,7 @@ people: person1: age: 30 - employment_income: 56_000 # 4,666.67/mo, FPG ratio 2.30+ -> 9% + employment_income_before_lsr: 56_000 # 4,666.67/mo, FPG ratio 2.30+ -> 9% weekly_hours_worked_before_lsr: 40 immigration_status: CITIZEN person2: @@ -273,7 +273,7 @@ people: person1: age: 30 - employment_income: 12_000 + employment_income_before_lsr: 12_000 weekly_hours_worked_before_lsr: 40 immigration_status: CITIZEN spm_units: @@ -298,7 +298,7 @@ people: person1: age: 30 - employment_income: 12_000 # low income -> 0% copay + employment_income_before_lsr: 12_000 # low income -> 0% copay weekly_hours_worked_before_lsr: 40 immigration_status: CITIZEN person2: @@ -332,7 +332,7 @@ people: person1: age: 30 - employment_income: 12_000 # low income -> 0% copay + employment_income_before_lsr: 12_000 # low income -> 0% copay weekly_hours_worked_before_lsr: 10 # 10 x 52/12 = 43.33 monthly immigration_status: CITIZEN person2: @@ -371,7 +371,7 @@ people: person1: age: 30 - employment_income: 12_000 # low income -> 0% copay + employment_income_before_lsr: 12_000 # low income -> 0% copay weekly_hours_worked_before_lsr: 10 # 10 x 52/12 = 43.33 monthly immigration_status: CITIZEN person2: @@ -411,7 +411,7 @@ people: person1: age: 30 - employment_income: 56_000 # 4,666.67/mo + employment_income_before_lsr: 56_000 # 4,666.67/mo weekly_hours_worked_before_lsr: 40 immigration_status: CITIZEN person2: diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/hi_ccap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/hi_ccap_countable_income.yaml index 3737656552e..238588f2b22 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/hi_ccap_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/hi_ccap_countable_income.yaml @@ -6,6 +6,8 @@ # # hi_ccap_countable_income is MONTH-defined. YEAR-defined sources are entered # annually (auto-divided to monthly); SSI is MONTH-defined and entered monthly. +# Earnings are entered as employment_income_before_lsr, the input Hawaii TANF +# reads, so the TANF grant CCAP counts from 2021-08-06 sees the same earnings. - name: Case 1, employment income is counted. period: 2025-01 @@ -14,7 +16,7 @@ people: person1: age: 30 - employment_income: 24_000 # 2,000/month + employment_income_before_lsr: 24_000 # 2,000/month spm_units: spm_unit: members: [person1] @@ -68,7 +70,7 @@ people: person1: age: 40 - employment_income: 24_000 # 2,000/month + employment_income_before_lsr: 24_000 # 2,000/month ssi: 500 # 500/month social_security_retirement: 12_000 # 1,000/month spm_units: @@ -113,10 +115,10 @@ people: person1: age: 30 - employment_income: 24_000 # parent, 2,000/month (counted) + employment_income_before_lsr: 24_000 # parent, 2,000/month (counted) person2: age: 16 # minor (< 18) - employment_income: 12_000 # 1,000/month, excluded as minor student + employment_income_before_lsr: 12_000 # 1,000/month, excluded as minor student is_full_time_student: true spm_units: spm_unit: @@ -136,10 +138,10 @@ people: person1: age: 30 - employment_income: 24_000 # parent, 2,000/month + employment_income_before_lsr: 24_000 # parent, 2,000/month person2: age: 16 # minor but not a student -> earnings counted - employment_income: 12_000 # 1,000/month + employment_income_before_lsr: 12_000 # 1,000/month is_full_time_student: false spm_units: spm_unit: @@ -159,10 +161,10 @@ people: person1: age: 30 - employment_income: 24_000 # parent, 2,000/month + employment_income_before_lsr: 24_000 # parent, 2,000/month person2: age: 20 # adult (>= 18); exclusion is minors only - employment_income: 12_000 # 1,000/month, counted + employment_income_before_lsr: 12_000 # 1,000/month, counted is_full_time_student: true spm_units: spm_unit: @@ -174,3 +176,102 @@ output: # 2,000 + 1,000 = 3,000 (adult student not excluded) hi_ccap_countable_income: 3_000 + +- name: Case 9, Hawaii TANF payments are counted from August 6, 2021. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + parent: + age: 30 + employment_income_before_lsr: 12_000 # 1,000/month + child: + age: 5 + spm_units: + unit: + members: [parent, child] + hi_tanf: 100 # monthly + households: + household: + members: [parent, child] + state_code: HI + output: + # HAR 17-798.3-10(b)(11): $1,000 earnings + $100 Hawaii TANF. + hi_ccap_tanf_income: 100 + hi_ccap_countable_income: 1_100 + +- name: Case 10, TANF the family does not take up is not counted. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + parent: + age: 30 + employment_income_before_lsr: 12_000 + child: + age: 5 + spm_units: + unit: + members: [parent, child] + hi_tanf: 100 + takes_up_tanf_if_eligible: false + households: + household: + members: [parent, child] + state_code: HI + output: + hi_ccap_tanf_income: 0 + hi_ccap_countable_income: 1_000 + +- name: Case 11, Hawaii TANF is not added before the August 6, 2021 rules. + period: 2021-01 + absolute_error_margin: 0.01 + input: + people: + parent: + age: 30 + employment_income_before_lsr: 12_000 + child: + age: 5 + spm_units: + unit: + members: [parent, child] + hi_tanf: 100 + households: + household: + members: [parent, child] + state_code: HI + output: + # The predecessor HAR 17-798.2 edition in force before then was not + # established, so the earlier source list applies. + hi_ccap_countable_income: 1_000 + +- name: Case 12, a computed Hawaii TANF grant flows into CCAP income. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + parent: + age: 30 + employment_income_before_lsr: 18_000 # 1,500/month + weekly_hours_worked_before_lsr: 40 + child: + age: 5 + is_tax_unit_dependent: true + spm_units: + unit: + members: [parent, child] + tax_units: + tax_unit: + members: [parent, child] + households: + household: + members: [parent, child] + state_code: HI + output: + # Hawaii TANF: countable earnings (1,500 x 0.8 - 200) x 0.45 = 450, with + # no incapacitated adult care deduction; 485.76 - 450 = 35.76. The grant + # reaches CCAP income without a circular dependency. + hi_tanf_dependent_care_deduction: 0 + hi_tanf: 35.76 + hi_ccap_countable_income: 1_535.76 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/integration.yaml index 9445909227f..45bb22f4b55 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/bessd/ccap/integration.yaml @@ -18,7 +18,7 @@ people: person1: age: 30 - employment_income: 18_000 # 1,500/mo + employment_income_before_lsr: 18_000 # 1,500/mo weekly_hours_worked_before_lsr: 40 is_tax_unit_head_or_spouse: true immigration_status: CITIZEN @@ -66,7 +66,7 @@ people: person1: age: 32 - employment_income: 60_000 # 5,000/mo + employment_income_before_lsr: 60_000 # 5,000/mo weekly_hours_worked_before_lsr: 40 is_tax_unit_head_or_spouse: true immigration_status: CITIZEN @@ -108,7 +108,7 @@ people: person1: age: 35 - employment_income: 200_000 # far above income limit + employment_income_before_lsr: 200_000 # far above income limit weekly_hours_worked_before_lsr: 40 is_tax_unit_head_or_spouse: true immigration_status: CITIZEN @@ -152,7 +152,7 @@ people: person1: age: 45 - employment_income: 30_000 # 2,500/mo + employment_income_before_lsr: 30_000 # 2,500/mo weekly_hours_worked_before_lsr: 40 is_tax_unit_head_or_spouse: true immigration_status: CITIZEN @@ -197,7 +197,7 @@ people: person1: age: 33 - employment_income: 36_000 # 3,000/mo + employment_income_before_lsr: 36_000 # 3,000/mo weekly_hours_worked_before_lsr: 40 is_tax_unit_head_or_spouse: true immigration_status: CITIZEN @@ -249,13 +249,13 @@ people: person1: age: 35 - employment_income: 30_000 + employment_income_before_lsr: 30_000 weekly_hours_worked_before_lsr: 40 is_tax_unit_head_or_spouse: true immigration_status: CITIZEN person2: age: 33 - employment_income: 0 + employment_income_before_lsr: 0 weekly_hours_worked_before_lsr: 0 is_full_time_student: false is_disabled: false @@ -291,7 +291,7 @@ people: person1: age: 35 - employment_income: 78_000 # 6,500/mo > 6,218.70 limit + employment_income_before_lsr: 78_000 # 6,500/mo > 6,218.70 limit weekly_hours_worked_before_lsr: 40 is_tax_unit_head_or_spouse: true immigration_status: CITIZEN @@ -324,7 +324,7 @@ people: person1: age: 30 - employment_income: 18_000 + employment_income_before_lsr: 18_000 weekly_hours_worked_before_lsr: 40 immigration_status: CITIZEN person2: diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/tanf/hi_tanf_countable_earned_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/tanf/hi_tanf_countable_earned_income.yaml index 8a28757eca2..fb60e6e5a2c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/tanf/hi_tanf_countable_earned_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/tanf/hi_tanf_countable_earned_income.yaml @@ -37,7 +37,7 @@ # No childcare expenses, so no dependent care deduction hi_tanf_countable_earned_income: 540 -- name: Case 2, earned income with dependent care deduction. +- name: Case 2, earned income with an incapacitated adult care deduction. period: 2024-01 input: people: @@ -46,12 +46,12 @@ tanf_gross_earned_income: 1_000 weekly_hours_worked_before_lsr: 40 person2: - age: 5 + age: 60 + # $100/month cost of care for an incapacitated adult + hi_tanf_qualifying_incapacitated_adult_care_expenses: 100 spm_units: spm_unit: members: [person1, person2] - # $1,200/year = $100/month childcare - childcare_expenses: 1_200 tax_units: tax_unit: members: [person1, person2] @@ -61,11 +61,11 @@ state_code: HI output: # Person1 earned after deductions: 270 - # Dependent care: min(100, 1 child × $175) = 100 + # Adult care: min(100, $175) = 100 (HAR 17-676-54.1(d)(4)) # Final: max(270 - 100, 0) = 170 hi_tanf_countable_earned_income: 170 -- name: Case 3, dependent care deduction capped at per-child max. +- name: Case 3, incapacitated adult care deduction capped at the per-adult max. period: 2024-01 input: people: @@ -74,12 +74,12 @@ tanf_gross_earned_income: 1_500 weekly_hours_worked_before_lsr: 40 person2: - age: 5 + age: 60 + # $500/month adult care, exceeds the $175 cap + hi_tanf_qualifying_incapacitated_adult_care_expenses: 500 spm_units: spm_unit: members: [person1, person2] - # $6,000/year = $500/month childcare, exceeds $175 cap - childcare_expenses: 6_000 tax_units: tax_unit: members: [person1, person2] @@ -89,11 +89,11 @@ state_code: HI output: # Person1 earned after deductions: 450 - # Dependent care: min(500, 1 child × $175) = 175 + # Adult care: min(500, $175) = 175 # Final: max(450 - 175, 0) = 275 hi_tanf_countable_earned_income: 275 -- name: Case 4, dependent care deduction cannot reduce earned below zero. +- name: Case 4, adult care deduction cannot reduce earned below zero. period: 2024-01 input: people: @@ -103,11 +103,11 @@ tanf_gross_earned_income: 200 weekly_hours_worked_before_lsr: 40 person2: - age: 5 + age: 60 + hi_tanf_qualifying_incapacitated_adult_care_expenses: 200 spm_units: spm_unit: members: [person1, person2] - childcare_expenses: 2_400 tax_units: tax_unit: members: [person1, person2] @@ -117,6 +117,6 @@ state_code: HI output: # Person1 earned after deductions: 0 (income too low) - # Dependent care: min(200, 175) = 175 + # Adult care: min(200, 175) = 175 # Final: max(0 - 175, 0) = 0 (floored at zero) hi_tanf_countable_earned_income: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/tanf/income/hi_tanf_dependent_care_deduction.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/tanf/income/hi_tanf_dependent_care_deduction.yaml index 6df22fdedb2..cecdbf3a185 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/tanf/income/hi_tanf_dependent_care_deduction.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/tanf/income/hi_tanf_dependent_care_deduction.yaml @@ -1,10 +1,11 @@ -# Hawaii TANF dependent care deduction tests -# Deduction is actual childcare expenses, capped at rate per child per month -# Rate: $175 (full-time, 32+ hrs) or $165 (part-time, <32 hrs) -# Uses MAX of adult hours - if either parent is full-time, use full-time rate -# Per Hawaii TANF State Plan +# Hawaii TANF dependent care deduction: HAR 17-676-54.1(c)(4) and (d)(4) +# deduct the actual cost of care of each incapacitated adult living in the +# household and receiving financial assistance, up to $175 a month when the +# applicant is employed full time (32+ hours a week, HAR 17-676-2) and $165 +# otherwise. Each adult's cost is capped separately. Child care costs are not +# part of this deduction. -- name: Case 1, no childcare expenses. +- name: Case 1, no care expenses. period: 2024-01 input: people: @@ -16,9 +17,6 @@ spm_units: spm_unit: members: [person1, person2] - tax_units: - tax_unit: - members: [person1, person2] households: household: members: [person1, person2] @@ -26,33 +24,29 @@ output: hi_tanf_dependent_care_deduction: 0 -- name: Case 2, single parent full-time, expenses below cap. - period: 2024-01 +- name: Case 2, child care does not create an incapacitated-adult deduction. + period: 2025-04 input: people: - person1: + parent: age: 30 weekly_hours_worked_before_lsr: 40 - person2: + child: age: 5 spm_units: - spm_unit: - members: [person1, person2] - # $1,200/year = $100/month, below $175 cap - childcare_expenses: 1_200 - tax_units: - tax_unit: - members: [person1, person2] + unit: + members: [parent, child] + childcare_expenses: 12_000 households: household: - members: [person1, person2] + members: [parent, child] state_code: HI output: - # 40 hrs = full-time, $175 cap - # $100/month < $175 cap, so full amount deducted - hi_tanf_dependent_care_deduction: 100 + # No qualifying adult or adult-care cost, so no deduction. Before this + # change the model deducted min($12,000 / 12, $175) = $175 for the child. + hi_tanf_dependent_care_deduction: 0 -- name: Case 3, single parent full-time, expenses above cap. +- name: Case 3, an amount entered for a child is not deducted. period: 2024-01 input: people: @@ -61,50 +55,39 @@ weekly_hours_worked_before_lsr: 40 person2: age: 5 + hi_tanf_qualifying_incapacitated_adult_care_expenses: 100 spm_units: spm_unit: members: [person1, person2] - # $3,600/year = $300/month, above $175 cap - childcare_expenses: 3_600 - tax_units: - tax_unit: - members: [person1, person2] households: household: members: [person1, person2] state_code: HI output: - # 40 hrs = full-time, $175 cap - # $300/month > $175 cap, capped at 1 child × $175 = $175 - hi_tanf_dependent_care_deduction: 175 + hi_tanf_dependent_care_deduction: 0 -- name: Case 4, single parent part-time, expenses above cap. +- name: Case 4, full-time applicant, adult care cost below the cap. period: 2024-01 input: people: person1: age: 30 - weekly_hours_worked_before_lsr: 20 + weekly_hours_worked_before_lsr: 40 person2: - age: 5 + age: 60 + hi_tanf_qualifying_incapacitated_adult_care_expenses: 100 spm_units: spm_unit: members: [person1, person2] - # $3,600/year = $300/month, above $165 cap - childcare_expenses: 3_600 - tax_units: - tax_unit: - members: [person1, person2] households: household: members: [person1, person2] state_code: HI output: - # 20 hrs = part-time, $165 cap - # $300/month > $165 cap, capped at 1 child × $165 = $165 - hi_tanf_dependent_care_deduction: 165 + # 40 hours is full time; $100 is below the $175 cap. + hi_tanf_dependent_care_deduction: 100 -- name: Case 5, two parents both full-time, uses full-time rate. +- name: Case 5, full-time applicant, adult care cost above the cap. period: 2024-01 input: people: @@ -112,110 +95,40 @@ age: 30 weekly_hours_worked_before_lsr: 40 person2: - age: 28 - weekly_hours_worked_before_lsr: 35 - person3: - age: 5 + age: 60 + hi_tanf_qualifying_incapacitated_adult_care_expenses: 300 spm_units: spm_unit: - members: [person1, person2, person3] - # $3,600/year = $300/month - childcare_expenses: 3_600 - tax_units: - tax_unit: - members: [person1, person2, person3] + members: [person1, person2] households: household: - members: [person1, person2, person3] + members: [person1, person2] state_code: HI output: - # MAX(40, 35) = 40 hrs = full-time, $175 cap - # $300/month > $175 cap, capped at $175 hi_tanf_dependent_care_deduction: 175 -- name: Case 6, two parents one part-time, uses full-time rate (MAX). +- name: Case 6, part-time applicant, adult care cost above the cap. period: 2024-01 input: people: person1: age: 30 - weekly_hours_worked_before_lsr: 40 - person2: - age: 28 weekly_hours_worked_before_lsr: 20 - person3: - age: 5 - spm_units: - spm_unit: - members: [person1, person2, person3] - # $3,600/year = $300/month - childcare_expenses: 3_600 - tax_units: - tax_unit: - members: [person1, person2, person3] - households: - household: - members: [person1, person2, person3] - state_code: HI - output: - # MAX(40, 20) = 40 hrs = full-time, $175 cap - # $300/month > $175 cap, capped at $175 - hi_tanf_dependent_care_deduction: 175 - -- name: Case 7, two children, full-time parent. - period: 2024-01 - input: - people: - person1: - age: 30 - weekly_hours_worked_before_lsr: 40 person2: - age: 5 - person3: - age: 8 - spm_units: - spm_unit: - members: [person1, person2, person3] - # $6,000/year = $500/month, above 2 × $175 = $350 cap - childcare_expenses: 6_000 - tax_units: - tax_unit: - members: [person1, person2, person3] - households: - household: - members: [person1, person2, person3] - state_code: HI - output: - # 40 hrs = full-time, $175 per child - # $500/month > $350 cap, capped at 2 children × $175 = $350 - hi_tanf_dependent_care_deduction: 350 - -- name: Case 8, no children in household. - period: 2024-01 - input: - people: - person1: - age: 30 - weekly_hours_worked_before_lsr: 40 - person2: - age: 25 - weekly_hours_worked_before_lsr: 40 + age: 60 + hi_tanf_qualifying_incapacitated_adult_care_expenses: 300 spm_units: spm_unit: members: [person1, person2] - childcare_expenses: 2_400 - tax_units: - tax_unit: - members: [person1, person2] households: household: members: [person1, person2] state_code: HI output: - # No children means cap = 0 children × $175 = $0 - hi_tanf_dependent_care_deduction: 0 + # 20 hours is less than full time: $165 cap. + hi_tanf_dependent_care_deduction: 165 -- name: Case 9, exactly 32 hours (boundary between part-time and full-time). +- name: Case 7, exactly 32 hours is full time. period: 2024-01 input: people: @@ -223,50 +136,19 @@ age: 30 weekly_hours_worked_before_lsr: 32 person2: - age: 5 + age: 60 + hi_tanf_qualifying_incapacitated_adult_care_expenses: 300 spm_units: spm_unit: members: [person1, person2] - childcare_expenses: 3_600 - tax_units: - tax_unit: - members: [person1, person2] households: household: members: [person1, person2] state_code: HI output: - # 32 hrs = full-time (32+ threshold), $175 cap hi_tanf_dependent_care_deduction: 175 -- name: Case 10, two parents both part-time, uses part-time rate. - period: 2024-01 - input: - people: - person1: - age: 30 - weekly_hours_worked_before_lsr: 25 - person2: - age: 28 - weekly_hours_worked_before_lsr: 20 - person3: - age: 5 - spm_units: - spm_unit: - members: [person1, person2, person3] - childcare_expenses: 3_600 - tax_units: - tax_unit: - members: [person1, person2, person3] - households: - household: - members: [person1, person2, person3] - state_code: HI - output: - # MAX(25, 20) = 25 hrs = part-time, $165 cap - hi_tanf_dependent_care_deduction: 165 - -- name: Case 11, exactly 31 hours (just under full-time threshold). +- name: Case 8, 31 hours is less than full time. period: 2024-01 input: people: @@ -274,23 +156,19 @@ age: 30 weekly_hours_worked_before_lsr: 31 person2: - age: 5 + age: 60 + hi_tanf_qualifying_incapacitated_adult_care_expenses: 300 spm_units: spm_unit: members: [person1, person2] - childcare_expenses: 3_600 - tax_units: - tax_unit: - members: [person1, person2] households: household: members: [person1, person2] state_code: HI output: - # 31 hrs < 32 threshold = part-time, $165 cap hi_tanf_dependent_care_deduction: 165 -- name: Case 12, three children, full-time parent. +- name: Case 9, each incapacitated adult's cost is capped separately. period: 2024-01 input: people: @@ -298,54 +176,47 @@ age: 30 weekly_hours_worked_before_lsr: 40 person2: - age: 10 + age: 60 + hi_tanf_qualifying_incapacitated_adult_care_expenses: 300 person3: - age: 7 - person4: - age: 4 + age: 25 + hi_tanf_qualifying_incapacitated_adult_care_expenses: 50 spm_units: spm_unit: - members: [person1, person2, person3, person4] - # $8,400/year = $700/month, above 3 × $175 = $525 cap - childcare_expenses: 8_400 - tax_units: - tax_unit: - members: [person1, person2, person3, person4] + members: [person1, person2, person3] households: household: - members: [person1, person2, person3, person4] + members: [person1, person2, person3] state_code: HI output: - # 40 hrs = full-time, $175 per child - # $700/month > $525 cap, capped at 3 children × $175 = $525 - hi_tanf_dependent_care_deduction: 525 + # min($300, $175) + min($50, $175) = $225. Pooling the costs against a + # $350 two-adult cap would give $350. + hi_tanf_dependent_care_deduction: 225 -- name: Case 13, disabled adult household member care expenses. +- name: Case 10, a full-time worker sets the cap when another adult works part time. period: 2024-01 - absolute_error_margin: 0.01 input: people: person1: age: 30 weekly_hours_worked_before_lsr: 40 person2: - age: 25 - is_disabled: true - care_expenses: 1_200 + age: 28 + weekly_hours_worked_before_lsr: 20 + person3: + age: 60 + hi_tanf_qualifying_incapacitated_adult_care_expenses: 300 spm_units: spm_unit: - members: [person1, person2] + members: [person1, person2, person3] households: household: - members: [person1, person2] + members: [person1, person2, person3] state_code: HI output: - # Per State Plan 10.2.1(D): care of a disabled adult household member - # up to $175/month (full-time employment, 40 hours >= 32). - # Expenses = 1,200 / 12 = 100/month, below the cap. - hi_tanf_dependent_care_deduction: 100 + hi_tanf_dependent_care_deduction: 175 -- name: Case 14, adult care expenses without disability are not deducted. +- name: Case 11, generic care expenses are not mapped to the deduction. period: 2024-01 absolute_error_margin: 0.01 input: @@ -355,6 +226,7 @@ weekly_hours_worked_before_lsr: 40 person2: age: 25 + is_disabled: true care_expenses: 1_200 spm_units: spm_unit: @@ -364,6 +236,6 @@ members: [person1, person2] state_code: HI output: - # Person2 is neither a child nor a disabled adult, so no care - # recipients: min(100, 0) = 0. + # care_expenses does not establish that the adult is incapacitated and + # receives financial assistance, so it is not deducted. hi_tanf_dependent_care_deduction: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/tanf/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/tanf/integration.yaml index ddb1fcd3a82..e26e94d9bb0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/tanf/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/hi/dhs/tanf/integration.yaml @@ -251,7 +251,7 @@ # Benefit = 610.56 - 570 = 40.56 hi_tanf: 40.56 -- name: Case 7, family with dependent care deduction in full pipeline. +- name: Case 7, child care costs give no dependent care deduction in the full pipeline. period: 2024-01 input: people: @@ -280,20 +280,20 @@ output: hi_tanf_gross_income: 1_500 hi_tanf_gross_income_eligible: true - # Dependent care: min(150, 1 child × $175) = 150 - hi_tanf_dependent_care_deduction: 150 + # HAR 17-676-54.1(d)(4) deducts the care of incapacitated adults only, + # so the $150/month child care cost is not deducted. + hi_tanf_dependent_care_deduction: 0 # Earned deductions for $1,500: # Step 1: 20% = 300, After: 1,200 # Step 2: $200 flat, After: 1,000 # Step 3: 55% = 550, After: 450 - # After dependent care: max(450 - 150, 0) = 300 - hi_tanf_countable_earned_income: 300 - hi_tanf_countable_income: 300 + hi_tanf_countable_earned_income: 450 + hi_tanf_countable_income: 450 # SOA = 1265 × 0.48 × 0.80 = 485.76 (mandatory-work steady-state) hi_tanf_maximum_benefit: 485.76 hi_tanf_eligible: true - # Benefit = 485.76 - 300 = 185.76 - hi_tanf: 185.76 + # Benefit = 485.76 - 450 = 35.76 + hi_tanf: 35.76 - name: Case 8, single person with no income. period: 2024-01 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/integration.yaml index a0147f3f836..503d73c29ff 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/integration.yaml @@ -29,7 +29,7 @@ mo_tanf_income_eligible: true mo_tanf_resources_eligible: true mo_tanf_eligible: true - mo_tanf: 234.086 + mo_tanf: 234 - name: Family of 3 with earned income below maximum period: 2024 @@ -90,9 +90,9 @@ mo_tanf_income_eligible: true mo_tanf_eligible: true # Monthly: $250 earned - ($90 + $30 + $130 / 3) deductions leaves - # $86.67 countable; $292.09 - $86.67 = $205.42 benefit; * 12 = - # $2,465.08. - mo_tanf: 2_465.08 + # $86.67 countable; $292.09 - $86.67 = $205.42, lowered to $205 + # (13 CSR 40-2.310(14)); * 12 = $2,460. + mo_tanf: 2_460 - name: Family of 3 income at exact 185% limit period: 2024 @@ -145,7 +145,7 @@ output: mo_tanf_resources_eligible: true mo_tanf_eligible: true - mo_tanf: 2_809.035 + mo_tanf: 2_808 - name: Family with resources exceeding $1000 limit period: 2024 @@ -248,7 +248,7 @@ mo_tanf_percentage_of_need_test: true mo_tanf_income_eligible: true mo_tanf_eligible: true - mo_tanf: 1_052.724 + mo_tanf: 1_044 - name: Benefit calculation period: 2024 @@ -275,7 +275,7 @@ mo_tanf_standard_of_need: 8_136 mo_tanf_maximum_benefit: 2_809.035 mo_tanf_eligible: true - mo_tanf: 2_809.035 + mo_tanf: 2_808 - name: A 19-year-old non-student household member is excluded from the unit period: 2024-01 @@ -307,7 +307,7 @@ mo_tanf_assistance_unit_size: 2 mo_tanf_standard_of_need: 678 mo_tanf_maximum_benefit: 234.086 - mo_tanf: 234.086 + mo_tanf: 234 - name: Pregnancy alone does not create eligibility without a dependent child period: 2024-01 @@ -357,7 +357,7 @@ mo_tanf_gross_earned_income: 0 mo_tanf_gross_income_eligible: true mo_tanf_eligible: true - mo_tanf: 234.086 + mo_tanf: 234 - name: Student teen parent's earnings do not affect the grant period: 2024-01 @@ -386,7 +386,7 @@ # who is a full-time secondary-school student. mo_tanf_gross_earned_income: 0 mo_tanf_eligible: true - mo_tanf: 234.086 + mo_tanf: 234 - name: An SSI-recipient parent is excluded from needs and income period: 2024-01 @@ -420,7 +420,7 @@ mo_tanf_countable_income: 0 mo_tanf_maximum_benefit: 135.687 mo_tanf_eligible: true - mo_tanf: 135.687 + mo_tanf: 135 - name: A family whose only child receives SSI gets a caretaker-only grant period: 2024-01 @@ -451,7 +451,7 @@ # parent"). mo_tanf_assistance_unit_size: 1 mo_tanf_eligible: true - mo_tanf: 135.69 + mo_tanf: 135 - name: An SSI child's own savings do not disqualify the caretaker-only unit period: 2024-01 @@ -484,7 +484,7 @@ mo_tanf_resources_eligible: true mo_tanf_assistance_unit_size: 1 mo_tanf_eligible: true - mo_tanf: 135.69 + mo_tanf: 135 - name: A family whose child and caretaker both receive SSI has no payable unit period: 2024-01 @@ -543,7 +543,7 @@ # size-2 payment level while the SSI child is excluded. mo_tanf_assistance_unit_size: 2 mo_tanf_eligible: true - mo_tanf: 234.09 + mo_tanf: 234 - name: An SSI child with an eligible sibling stays out of the unit period: 2024-01 @@ -576,7 +576,7 @@ # (13 CSR 40-2.310(1)(F); DSS Manual 0210.005.10). mo_tanf_assistance_unit_size: 2 mo_tanf_eligible: true - mo_tanf: 234.09 + mo_tanf: 234 - name: A caretaker's own assets can still fail the resource test period: 2024-01 @@ -636,12 +636,13 @@ output: # Per earner: $90 + $30 + ($200 - $120) / 3 = $146.67; x2 = $293.33 # (13 CSR 40-2.310(9)(A) applies the disregards to each participant). - # Countable: $400 - $293.33 = $106.67; benefit: $292.09 - $106.67. + # Countable: $400 - $293.33 = $106.67; benefit: $292.09 - $106.67 + # = $185.42, lowered to $185. mo_tanf_gross_earned_income: 400 mo_tanf_earned_income_deductions: 293.33 mo_tanf_countable_income: 106.67 mo_tanf_eligible: true - mo_tanf: 185.42 + mo_tanf: 185 - name: Two enrolled earners end to end period: 2024-01 @@ -677,7 +678,7 @@ mo_tanf_earned_income_deductions: 400 mo_tanf_countable_income: 0 mo_tanf_eligible: true - mo_tanf: 292.09 + mo_tanf: 292 - name: A self-employment loss does not offset another earner's income period: 2024-01 @@ -708,11 +709,12 @@ # The loss earner's -$300 deduction cancels their -$300 gross, so # countable income equals the wage earner's own result: $480 - $240 # = $240 (13 CSR 40-2.310(9)(A) applies the disregards per - # participant; no cross-earner loss offset). Benefit: $292.09 - $240. + # participant; no cross-earner loss offset). Benefit: $292.09 - $240 + # = $52.09, lowered to $52. mo_tanf_gross_earned_income: 180 mo_tanf_earned_income_deductions: -60 mo_tanf_countable_income: 240 - mo_tanf: 52.09 + mo_tanf: 52 - name: A self-employment loss does not offset an enrolled earner's income period: 2024-01 @@ -745,4 +747,4 @@ # work exemption = $410; the loss earner's -$300 cancels their own # gross, leaving countable income $480 - $410 = $70. mo_tanf_countable_income: 70 - mo_tanf: 222.09 + mo_tanf: 222 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf.yaml index 3bf6eb8dbb4..ef45b7ba43c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf.yaml @@ -16,7 +16,9 @@ mo_tanf_standard_of_need: 846 mo_tanf_countable_income: 0 output: - mo_tanf: 292.09 + # 846 x 0.34526 = 292.08996, lowered to the whole dollar under + # 13 CSR 40-2.310(14). + mo_tanf: 292 - name: Eligible household with countable income receives reduced benefit period: 2024-01 @@ -26,7 +28,8 @@ mo_tanf_standard_of_need: 846 mo_tanf_countable_income: 100 output: - mo_tanf: 192.09 + # 292.08996 - 100 = 192.08996, lowered to 192. + mo_tanf: 192 - name: Benefit below $10 minimum threshold is not paid period: 2024-01 @@ -36,7 +39,7 @@ mo_tanf_standard_of_need: 846 mo_tanf_countable_income: 285 output: - # $292.09 - $285 = $7.09, but minimum payment is $10 + # $292.08996 - $285 = $7.08996, lowered to $7, below the $10 minimum. mo_tanf: 0 - name: Benefit of $10 @@ -47,7 +50,8 @@ mo_tanf_standard_of_need: 846 mo_tanf_countable_income: 282 output: - mo_tanf: 10.09 + # $292.08996 - $282 = $10.08996, lowered to $10. + mo_tanf: 10 - name: Countable income exceeds maximum benefit results in zero period: 2024-01 @@ -58,3 +62,47 @@ mo_tanf_countable_income: 300 output: mo_tanf: 0 + +- name: A size-two zero-income grant is lowered to whole dollars. + period: 2026-01 + input: + state_code: MO + mo_tanf_eligible: true + mo_tanf_standard_of_need: 678 + mo_tanf_countable_income: 0 + output: + # 678 x 0.34526 = 234.08628; 13 CSR 40-2.310(14) lowers it to 234. + mo_tanf: 234 + +- name: A payable grant just above ten dollars is lowered to ten. + period: 2026-01 + input: + state_code: MO + mo_tanf_eligible: true + mo_tanf_standard_of_need: 678 + mo_tanf_countable_income: 223.25 + output: + # 234.08628 - 223.25 = 10.83628, lowered to 10. + mo_tanf: 10 + +- name: A grant below ten dollars remains unpaid. + period: 2026-01 + input: + state_code: MO + mo_tanf_eligible: true + mo_tanf_standard_of_need: 678 + mo_tanf_countable_income: 224.10 + output: + # 234.08628 - 224.10 = 9.98628, lowered to 9, below the $10 minimum. + mo_tanf: 0 + +- name: A grant of exactly ten dollars is paid. + period: 2026-01 + input: + state_code: MO + mo_tanf_eligible: true + mo_tanf_maximum_benefit: 234 + mo_tanf_countable_income: 224 + output: + # 234 - 224 = 10, not less than the $10 minimum. + mo_tanf: 10 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_countable_resources.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_countable_resources.yaml index 2188605a31f..e2b632fe128 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_countable_resources.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_countable_resources.yaml @@ -215,7 +215,7 @@ # The needy grandparent is included. mo_tanf_non_parent_caretaker_included: true mo_tanf_countable_resources: 0 - mo_tanf: 234.086 + mo_tanf: 234 - name: An included non-parent caretaker's resources count period: 2026-01 @@ -243,4 +243,4 @@ # included in the assistance group, count the NPCR's resources." mo_tanf_non_parent_caretaker_included: true mo_tanf_countable_resources: 800 - mo_tanf: 234.086 + mo_tanf: 234 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_gross_unearned_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_gross_unearned_income.yaml index 2c9f0329b60..a7d890b6188 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_gross_unearned_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_gross_unearned_income.yaml @@ -82,7 +82,7 @@ mo_tanf_gross_unearned_income: 200.0 mo_tanf_assistance_unit_size: 2 mo_tanf_eligible: true - mo_tanf: 34.08628 + mo_tanf: 34 - name: Unemployment remains countable period: 2026-01 @@ -112,7 +112,7 @@ mo_tanf_gross_unearned_income: 200.0 mo_tanf_assistance_unit_size: 2 mo_tanf_eligible: true - mo_tanf: 34.08628 + mo_tanf: 34 - name: Mixed workers compensation and unemployment are counted once period: 2026-01 @@ -142,7 +142,7 @@ mo_tanf_gross_unearned_income: 200.0 mo_tanf_assistance_unit_size: 2 mo_tanf_eligible: true - mo_tanf: 34.08628 + mo_tanf: 34 - name: No income receives the maximum grant period: 2026-01 @@ -172,7 +172,7 @@ mo_tanf_gross_unearned_income: 0.0 mo_tanf_assistance_unit_size: 2 mo_tanf_eligible: true - mo_tanf: 234.08628 + mo_tanf: 234 - name: Workers compensation above the payment standard makes the unit ineligible period: 2026-01 @@ -235,7 +235,7 @@ mo_tanf_is_assistance_unit_member: [true, true, false] mo_tanf_gross_unearned_income: 50 mo_tanf_assistance_unit_size: 2 - mo_tanf: 184.08628 + mo_tanf: 184 - name: Workers compensation of an SSI recipient does not count period: 2026-01 @@ -264,7 +264,7 @@ mo_tanf_is_assistance_unit_member: [false, true] mo_tanf_gross_unearned_income: 0 mo_tanf_assistance_unit_size: 1 - mo_tanf: 135.68718 + mo_tanf: 135 - name: Taxable and tax-exempt interest are excluded from Missouri TANF income period: 2026-01 @@ -295,7 +295,7 @@ mo_tanf_gross_unearned_income: 0 mo_tanf_countable_income: 0 mo_tanf_eligible: true - mo_tanf: 234.08628 + mo_tanf: 234 - name: Interest is excluded while dividends and workers compensation count period: 2026-01 @@ -329,7 +329,7 @@ mo_tanf_gross_unearned_income: 200 mo_tanf_countable_income: 200 mo_tanf_eligible: true - mo_tanf: 34.08628 + mo_tanf: 34 - name: Disability payments and strike benefits count alongside workers compensation period: 2026-01 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_is_assistance_unit_member.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_is_assistance_unit_member.yaml index c723459a5e5..0d760a76cb9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_is_assistance_unit_member.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/mo_tanf_is_assistance_unit_member.yaml @@ -1,8 +1,10 @@ # Parents in the Missouri TANF assistance unit when someone else claims them # as a tax dependent: 13 CSR 40-2.300(5)(C), 13 CSR 40-2.310(1)(F) and # DSS Manual 0210.005.05, 0210.005.10 and 0210.005.30. -# Standard of need: size 1 $393, size 2 $678, size 3 $846. Payment is 34.526% -# of the standard: size 1 $135.687, size 2 $234.086, size 3 $292.090. +# Standard of need: size 1 $393, size 2 $678, size 3 $846. The maximum is +# 34.526% of the standard (size 1 $135.687, size 2 $234.086, size 3 +# $292.090), and 13 CSR 40-2.310(14) lowers the payment to the whole +# dollar: size 1 $135, size 2 $234, size 3 $292. - name: A mother claimed as her own mother's tax dependent is the caretaker for her child period: 2026-01 @@ -35,7 +37,7 @@ mo_tanf_non_parent_caretaker: [false, false, false] mo_tanf_is_assistance_unit_member: [false, true, true] mo_tanf_assistance_unit_size: 2 - mo_tanf: 234.086 + mo_tanf: 234 - name: The dependent mother's earnings count and the excluded grandparent's do not period: 2026-01 @@ -67,12 +69,12 @@ # 0210.005.05: "Include the needs and income of the following persons". # The mother's $300 less the $90 work expense, $30 and one-third of the # remaining $180 leaves $120 (13 CSR 40-2.310(9)(A)2-3): - # 234.086 - 120 = 114.086. The mother is 20, so no minor-parent deeming + # 234.086 - 120 = 114.086, lowered to 114. The mother is 20, so no minor-parent deeming # of the grandparent's income applies (13 CSR 40-2.310(8)(B)1.F). mo_tanf_is_assistance_unit_member: [false, true, true] mo_tanf_gross_earned_income: 300 mo_tanf_countable_income: 120 - mo_tanf: 114.086 + mo_tanf: 114 - name: An 18-year-old mother out of school is the caretaker, not a child period: 2026-01 @@ -105,7 +107,7 @@ mo_tanf_dependent_child: [false, false, true] mo_tanf_is_assistance_unit_member: [false, true, true] mo_tanf_assistance_unit_size: 2 - mo_tanf: 234.086 + mo_tanf: 234 - name: An 18-year-old mother in high school is a cash-eligible child, grouped with her own mother under one reading period: 2026-01 @@ -148,7 +150,7 @@ mo_tanf_is_assistance_unit_member: [true, true, true] mo_tanf_gross_earned_income: 0 mo_tanf_assistance_unit_size: 3 - mo_tanf: 292.090 + mo_tanf: 292 - name: A 16-year-old mother, her baby and her mother form one three-generation group period: 2026-01 @@ -179,7 +181,7 @@ # assistance group". The minor mother is a member as an eligible child. mo_tanf_is_assistance_unit_member: [true, true, true] mo_tanf_assistance_unit_size: 3 - mo_tanf: 292.090 + mo_tanf: 292 - name: An unmarried father claimed as the mother's dependent is a member with their child period: 2026-01 @@ -210,7 +212,7 @@ # household with everyone included." mo_tanf_is_assistance_unit_member: [true, true, true] mo_tanf_assistance_unit_size: 3 - mo_tanf: 292.090 + mo_tanf: 292 - name: Two dependent parents living with the child's grandparents are both members period: 2026-01 @@ -247,7 +249,7 @@ mo_tanf_non_parent_caretaker: [false, false, false, false, false] mo_tanf_is_assistance_unit_member: [false, false, true, true, true] mo_tanf_assistance_unit_size: 3 - mo_tanf: 292.090 + mo_tanf: 292 - name: A dependent adult who is a parent, but not of an eligible child, is not a member period: 2026-01 @@ -282,7 +284,7 @@ mo_tanf_is_assistance_unit_member: [false, true, true] mo_tanf_assistance_unit_size: 2 mo_tanf_gross_unearned_income: 0 - mo_tanf: 234.086 + mo_tanf: 234 - name: Without the input, a grandmother young enough to be the child's parent is counted as one period: 2026-01 @@ -347,7 +349,7 @@ # parent and child, so her own child in the home must be someone else. mo_tanf_is_parent_of_dependent_child: [false, false, false] mo_tanf_is_assistance_unit_member: [false, true, true] - mo_tanf: 234.086 + mo_tanf: 234 - name: The default rules out a dependent too young to be the child's parent period: 2026-01 @@ -377,7 +379,7 @@ # 19 - 9 = 10 years, fewer than the 12 the default requires. mo_tanf_is_parent_of_dependent_child: [false, false, false] mo_tanf_is_assistance_unit_member: [true, false, true] - mo_tanf: 234.086 + mo_tanf: 234 - name: A dependent parent on SSI is not a member but still excludes the non-parent caretaker period: 2026-01 @@ -411,7 +413,7 @@ mo_tanf_non_parent_caretaker: [false, false, false] mo_tanf_is_assistance_unit_member: [false, false, true] mo_tanf_assistance_unit_size: 1 - mo_tanf: 135.687 + mo_tanf: 135 - name: A grandparent marked as a non-parent stays out even when their own adult child is counted period: 2026-01 @@ -446,7 +448,7 @@ mo_tanf_is_parent_of_dependent_child: [true, true, false] mo_tanf_is_assistance_unit_member: [false, true, true] mo_tanf_assistance_unit_size: 2 - mo_tanf: 234.086 + mo_tanf: 234 - name: A mandatory dependent parent's income can eliminate the children's grant period: 2026-01 @@ -524,15 +526,15 @@ members: [grandparent, mother, child1, child2, child3] state_code: MO output: - # 990 * 0.34526 = 341.8074, $49.71744 more than the three children's - # $292.08996 without their mother. + # 990 * 0.34526 = 341.8074, lowered to $341, $49 more than the three + # children's $292 without their mother. mo_tanf_is_assistance_unit_member: [false, true, true, true, true] mo_tanf_assistance_unit_size: 4 mo_tanf_gross_earned_income: 0 mo_tanf_gross_unearned_income: 0 mo_tanf_countable_income: 0 mo_tanf_standard_of_need_test: true - mo_tanf: 341.8074 + mo_tanf: 341 - name: An explicit parent flag requires a dependent child in that person's tax unit period: 2026-01 @@ -567,7 +569,7 @@ # size 3 and 846 * 0.34526 = 292.08996. mo_tanf_is_assistance_unit_member: [true, true, false] mo_tanf_assistance_unit_size: 2 - mo_tanf: 234.08628 + mo_tanf: 234 - name: A real second parent filing separately stays excluded despite an explicit true parent flag period: 2026-01 @@ -607,4 +609,4 @@ mo_tanf_is_parent_of_dependent_child: [false, false, true] mo_tanf_is_assistance_unit_member: [true, true, false] mo_tanf_assistance_unit_size: 2 - mo_tanf: 234.08628 + mo_tanf: 234 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/non_parent_caretaker/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/non_parent_caretaker/integration.yaml index fc30561c8db..0e922dc1ea2 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/non_parent_caretaker/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/non_parent_caretaker/integration.yaml @@ -1,8 +1,10 @@ # Missouri TANF non-parent caretaker relative (NPCR) rules: 13 CSR 40-2.300(5)(D), # 13 CSR 40-2.310(3) and (8)(B)1.C, and DSS Manual 0210.005.05, 0210.005.10, # 0210.005.15, 0210.005.35, 0210.005.40 and 0210.010.10. -# Standard of need: size 1 $393, size 2 $678, size 3 $846. Payment is 34.526% -# of the standard: size 1 $135.687, size 2 $234.086, size 3 $292.090. +# Standard of need: size 1 $393, size 2 $678, size 3 $846. The maximum is +# 34.526% of the standard (size 1 $135.687, size 2 $234.086, size 3 +# $292.090), and 13 CSR 40-2.310(14) lowers the payment to the whole +# dollar: size 1 $135, size 2 $234, size 3 $292. - name: Grandparent with no spouse and $100 unemployment is left out because inclusion lowers the grant period: 2026-01 @@ -30,18 +32,18 @@ state_code: MO output: # No spouse in the home, so the NPCR is needy without a budget - # (DSS Manual 0210.005.35). Included: 292.090 - 100 = 192.090. - # Excluded: the two children alone get 234.086. DSS Manual 0210.005.15 + # (DSS Manual 0210.005.35). Included: 292.090 - 100 = 192.090, paid as 192. + # Excluded: the two children alone get 234. DSS Manual 0210.005.15 # forbids an optional inclusion that reduces the grant. mo_tanf_non_parent_caretaker: [true, false, false] mo_tanf_non_parent_caretaker_needy: true - mo_tanf_if_non_parent_caretaker_included: 192.090 - mo_tanf_if_non_parent_caretaker_excluded: 234.086 + mo_tanf_if_non_parent_caretaker_included: 192 + mo_tanf_if_non_parent_caretaker_excluded: 234 mo_tanf_non_parent_caretaker_included: false mo_tanf_is_assistance_unit_member: [false, true, true] mo_tanf_assistance_unit_size: 2 mo_tanf_gross_unearned_income: 0 - mo_tanf: 234.086 + mo_tanf: 234 - name: The same household without the non-parent input keeps the grandparent as a caretaker period: 2026-01 @@ -70,7 +72,7 @@ mo_tanf_non_parent_caretaker: [false, false, false] mo_tanf_non_parent_caretaker_needy: false mo_tanf_assistance_unit_size: 3 - mo_tanf: 192.090 + mo_tanf: 192 - name: Grandparent with $700 unemployment and a $0 spouse is not needy and is excluded period: 2026-01 @@ -112,7 +114,7 @@ mo_tanf_is_assistance_unit_member: [false, false, true, true] mo_tanf_assistance_unit_size: 2 mo_tanf_eligible: true - mo_tanf: 234.086 + mo_tanf: 234 - name: The same household without the non-parent input stays ineligible at size four period: 2026-01 @@ -169,12 +171,12 @@ state_code: MO output: mo_tanf_non_parent_caretaker_needy: true - mo_tanf_if_non_parent_caretaker_included: 292.090 - mo_tanf_if_non_parent_caretaker_excluded: 234.086 + mo_tanf_if_non_parent_caretaker_included: 292 + mo_tanf_if_non_parent_caretaker_excluded: 234 mo_tanf_non_parent_caretaker_included: true mo_tanf_is_assistance_unit_member: [true, true, true] mo_tanf_assistance_unit_size: 3 - mo_tanf: 292.090 + mo_tanf: 292 - name: A needy grandparent who opts out is excluded even though inclusion would raise the grant period: 2026-01 @@ -206,7 +208,7 @@ mo_tanf_non_parent_caretaker_needy: true mo_tanf_non_parent_caretaker_included: false mo_tanf_assistance_unit_size: 2 - mo_tanf: 234.086 + mo_tanf: 234 - name: Grandparent with a $0 spouse is needy through the budget and is included period: 2026-01 @@ -241,7 +243,7 @@ mo_tanf_non_parent_caretaker_included: true mo_tanf_is_assistance_unit_member: [true, false, true, true] mo_tanf_assistance_unit_size: 3 - mo_tanf: 292.090 + mo_tanf: 292 - name: A spouse with $700 of income makes the grandparent not needy period: 2026-01 @@ -274,7 +276,7 @@ mo_tanf_non_parent_caretaker_countable_income: 700 mo_tanf_non_parent_caretaker_needy: false mo_tanf_assistance_unit_size: 2 - mo_tanf: 234.086 + mo_tanf: 234 - name: The same spouse on SSI makes the grandparent needy without a budget period: 2026-01 @@ -312,7 +314,7 @@ mo_tanf_non_parent_caretaker_included: true mo_tanf_is_assistance_unit_member: [true, false, true, true] mo_tanf_assistance_unit_size: 3 - mo_tanf: 292.090 + mo_tanf: 292 - name: When the head receives SSI the spouse is the caretaker relative and is needy period: 2026-01 @@ -347,7 +349,7 @@ mo_tanf_non_parent_caretaker_included: true mo_tanf_is_assistance_unit_member: [false, true, true] mo_tanf_assistance_unit_size: 2 - mo_tanf: 234.086 + mo_tanf: 234 - name: A grandparent with $800 and no spouse is needy but excluded because inclusion makes the unit ineligible period: 2026-01 @@ -381,7 +383,7 @@ mo_tanf_if_non_parent_caretaker_included: 0 mo_tanf_non_parent_caretaker_included: false mo_tanf_assistance_unit_size: 2 - mo_tanf: 234.086 + mo_tanf: 234 - name: A needy grandparent whose only grandchild receives SSI receives a caretaker-only grant period: 2026-01 @@ -411,7 +413,7 @@ mo_tanf_non_parent_caretaker_included: true mo_tanf_is_assistance_unit_member: [true, false] mo_tanf_assistance_unit_size: 1 - mo_tanf: 135.687 + mo_tanf: 135 - name: A grandparent is not a non-parent caretaker when the grandchild's adult mother lives in the home period: 2026-01 @@ -448,7 +450,7 @@ mo_tanf_non_parent_caretaker_needy: false mo_tanf_is_assistance_unit_member: [false, true, true] mo_tanf_assistance_unit_size: 2 - mo_tanf: 234.086 + mo_tanf: 234 - name: A mother who is herself a dependent child does not block her aunt as caretaker relative period: 2026-01 @@ -481,7 +483,7 @@ mo_tanf_non_parent_caretaker: [true, false, false] mo_tanf_non_parent_caretaker_included: true mo_tanf_assistance_unit_size: 3 - mo_tanf: 292.090 + mo_tanf: 292 - name: A stepparent marked by mistake as a non-parent is still excluded when the parent is in the home period: 2026-01 @@ -538,8 +540,8 @@ members: [grandparent, grandchild1, grandchild2] state_code: MO output: - # 12 months of the children-only grant: 12 x 234.086. - mo_tanf: 2_809.04 + # 12 months of the children-only grant: 12 x 234. + mo_tanf: 2_808 - name: An excluded caretaker's resources do not count period: 2026-01 @@ -573,4 +575,4 @@ mo_tanf_non_parent_caretaker_included: false mo_tanf_countable_resources: 0 mo_tanf_resources_eligible: true - mo_tanf: 234.086 + mo_tanf: 234 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/non_parent_caretaker/mo_tanf_non_parent_caretaker.yaml b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/non_parent_caretaker/mo_tanf_non_parent_caretaker.yaml index aeb93628404..f37e1f625fc 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/non_parent_caretaker/mo_tanf_non_parent_caretaker.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/mo/dss/tanf/non_parent_caretaker/mo_tanf_non_parent_caretaker.yaml @@ -74,7 +74,7 @@ mo_tanf_non_parent_caretaker_needy: true mo_tanf_non_parent_caretaker_included: true mo_tanf_assistance_unit_size: 2 - mo_tanf: 234.086 + mo_tanf: 234 - name: A non-parent caretaker who receives SSI is never the caretaker relative period: 2026-01 @@ -101,7 +101,7 @@ mo_tanf_non_parent_caretaker: [false, false] mo_tanf_non_parent_caretaker_needy: false mo_tanf_is_assistance_unit_member: [false, true] - mo_tanf: 135.687 + mo_tanf: 135 - name: A parent on SSI in the home still excludes a non-parent caretaker period: 2026-01 @@ -198,7 +198,7 @@ mo_tanf_non_parent_caretaker: [true, false, false] mo_tanf_non_parent_caretaker_included: true mo_tanf_assistance_unit_size: 2 - mo_tanf: 234.086 + mo_tanf: 234 - name: Without the override the default rules out a great-grandparent too old to be the child's parent period: 2026-01 @@ -233,5 +233,5 @@ mo_tanf_non_parent_caretaker: [true, false, false] mo_tanf_non_parent_caretaker_included: true mo_tanf_assistance_unit_size: 2 - mo_tanf: 234.086 + mo_tanf: 234 diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/meets_snap_gross_income_test.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/meets_snap_gross_income_test.yaml index 1aa82f7f1c2..c2e7577590d 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/meets_snap_gross_income_test.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/meets_snap_gross_income_test.yaml @@ -222,3 +222,87 @@ state_code: PA output: meets_snap_gross_income_test: true + +- name: Guam two-person household passes the FY 2027 gross income test + period: 2026-10 + input: + people: + person1: {} + person2: {} + spm_units: + spm_unit: + members: [person1, person2] + snap_unit_size: 2 + has_snap_elderly_disabled_member: false + # 7 CFR 273.9(a)(1)(i): Guam uses 130% of the poverty guidelines + # for the 48 contiguous States. FY 2027 uses the 2026 guidelines + # ($15,960 + $5,680 = $21,640 for two people); 130% x $21,640 / 12 + # = $2,344.33, rounded up to $2,345. + snap_gross_test_income: 1_000 + households: + household: + members: [person1, person2] + state_code: GU + output: + meets_snap_gross_income_test: true + +- name: Virgin Islands two-person household at the FY 2027 gross limit passes + period: 2026-10 + input: + people: + person1: {} + person2: {} + spm_units: + spm_unit: + members: [person1, person2] + snap_unit_size: 2 + has_snap_elderly_disabled_member: false + # $2,345 is the two-person contiguous-state gross limit, which the + # Virgin Islands also use (7 CFR 273.9(a)(1)(i)). + snap_gross_test_income: 2_345 + households: + household: + members: [person1, person2] + state_code: VI + output: + meets_snap_gross_income_test: true + +- name: Virgin Islands two-person household just above the FY 2027 gross limit fails + period: 2026-10 + input: + people: + person1: {} + person2: {} + spm_units: + spm_unit: + members: [person1, person2] + snap_unit_size: 2 + has_snap_elderly_disabled_member: false + snap_gross_test_income: 2_346 + households: + household: + members: [person1, person2] + state_code: VI + output: + meets_snap_gross_income_test: false + +- name: Ten-person Guam household at the FY 2027 gross limit passes + period: 2026-10 + input: + people: + person1: {} + spm_units: + spm_unit: + members: [person1] + snap_unit_size: 10 + has_snap_elderly_disabled_member: false + # Guam uses the contiguous-state standard and its separately rounded + # increment: $6,037 for eight people plus 2 x $616 gives $7,269 + # (7 CFR 273.9(a)(1)(i), (a)(3)(i)). + snap_gross_test_income: 7_269 + households: + household: + members: [person1] + state_code: GU + output: + meets_snap_gross_income_test: true diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/meets_snap_net_income_test.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/meets_snap_net_income_test.yaml index 85238ffc712..2ccef2565eb 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/meets_snap_net_income_test.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/meets_snap_net_income_test.yaml @@ -272,3 +272,81 @@ state_code: HI output: meets_snap_net_income_test: true + +- name: Guam two-person household passes the FY 2027 net income test + period: 2026-10 + input: + people: + person1: {} + person2: {} + spm_units: + spm_unit: + members: [person1, person2] + snap_unit_size: 2 + # 7 CFR 273.9(a)(2)(i): Guam uses the poverty guidelines for the 48 + # contiguous States. FY 2027 uses the 2026 guidelines ($15,960 + + # $5,680 = $21,640 for two people); $21,640 / 12 = $1,803.33, + # rounded up to $1,804. + snap_net_income: 365 + households: + household: + members: [person1, person2] + state_code: GU + output: + meets_snap_net_income_test: true + +- name: Virgin Islands two-person household at the FY 2027 net limit passes + period: 2026-10 + input: + people: + person1: {} + person2: {} + spm_units: + spm_unit: + members: [person1, person2] + snap_unit_size: 2 + snap_net_income: 1_804 + households: + household: + members: [person1, person2] + state_code: VI + output: + meets_snap_net_income_test: true + +- name: Virgin Islands two-person household just above the FY 2027 net limit fails + period: 2026-10 + input: + people: + person1: {} + person2: {} + spm_units: + spm_unit: + members: [person1, person2] + snap_unit_size: 2 + snap_net_income: 1_805 + households: + household: + members: [person1, person2] + state_code: VI + output: + meets_snap_net_income_test: false + +- name: Nine-person Virgin Islands household at the FY 2027 net limit passes + period: 2026-10 + input: + people: + person1: {} + spm_units: + spm_unit: + members: [person1] + snap_unit_size: 9 + # The contiguous-state eight-person standard of $4,644 plus the + # separately rounded $474 increment gives $5,118 + # (7 CFR 273.9(a)(2)(i), (a)(3)(ii)). + snap_net_income: 5_118 + households: + household: + members: [person1] + state_code: VI + output: + meets_snap_net_income_test: true diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/income/snap_fpg.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/income/snap_fpg.yaml index c924c743ae7..2d8daeed80d 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/income/snap_fpg.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/income/snap_fpg.yaml @@ -19,3 +19,42 @@ output: spm_unit_fpg: 13590 + 4720 * 2 snap_fpg: (12880 + 4540 * 2) / 12 * 9 + (13590 + 4720 * 2) / 12 * 3 + +- name: Guam uses the contiguous-state SNAP poverty guideline in FY 2027 + period: 2026-10 + absolute_error_margin: 0.01 + input: + people: + person1: {} + person2: {} + spm_units: + spm_unit: + members: [person1, person2] + snap_unit_size: 2 + households: + household: + members: [person1, person2] + state_code: GU + output: + # 7 CFR 273.9(a)(1)(i), (a)(2)(i): ($15,960 + $5,680) / 12. + snap_fpg: 1_803.33 + +- name: The Virgin Islands use the contiguous-state SNAP poverty guideline in FY 2027 + period: 2026-10 + absolute_error_margin: 0.01 + input: + people: + person1: {} + person2: {} + person3: {} + spm_units: + spm_unit: + members: [person1, person2, person3] + snap_unit_size: 3 + households: + household: + members: [person1, person2, person3] + state_code: VI + output: + # ($15,960 + 2 x $5,680) / 12. + snap_fpg: 2_276.67 diff --git a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/_apply_ssi_exclusions.py b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/_apply_ssi_exclusions.py index 0b5de7a0f16..c60a0f8965f 100644 --- a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/_apply_ssi_exclusions.py +++ b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/_apply_ssi_exclusions.py @@ -1,7 +1,7 @@ from policyengine_us.model_api import * -def _apply_ssi_exclusions( +def _apply_ssi_exclusions_monthly( earned_income: ArrayLike, unearned_income: ArrayLike, parameters: ParameterNode, @@ -9,35 +9,51 @@ def _apply_ssi_exclusions( general_exclusion: ArrayLike = None, ) -> ArrayLike: """ - Applies standard SSI income exclusions to convert total earned/unearned income - into countable income. This follows 20 CFR §§ 416.1112 and 416.1124: + Applies standard SSI income exclusions to one month's earned and unearned + income, returning that month's countable income. This follows + 20 CFR §§ 416.1112 and 416.1124: 1) Subtract $20 'general' exclusion from unearned (or from earned if unearned < 20). 2) Subtract $65 'earned' exclusion from any remaining earned income. 3) Exclude 50% of the remainder of earned income. - - All amounts are stored as annual but exclusions are monthly amounts, so we convert - from annual -> monthly, apply monthly exclusions, then go back to annual. """ - # Convert from annual to monthly - earned_monthly = earned_income / MONTHS_IN_YEAR - unearned_monthly = unearned_income / MONTHS_IN_YEAR - p = parameters(period).gov.ssa.ssi.income.exclusions general_exclusion = p.general if general_exclusion is None else general_exclusion # Step 1: Subtract general exclusion from unearned first - applied_general = min_(general_exclusion, unearned_monthly) - countable_unearned = unearned_monthly - applied_general + applied_general = min_(general_exclusion, unearned_income) + countable_unearned = unearned_income - applied_general # The remainder of the general exclusion (if unearned < 20) applies to earned leftover_general = general_exclusion - applied_general total_earned_excl = p.earned + leftover_general # Step 2 & 3: Apply the total earned exclusion, then exclude 50% of the rest - earned_after_flat = max_(earned_monthly - total_earned_excl, 0) + earned_after_flat = max_(earned_income - total_earned_excl, 0) # The 'earned_share' parameter is the fraction excluded above the flat. Typically 0.5 => 50% excluded. # So the fraction that remains is (1 - earned_share). countable_earned = earned_after_flat * (1.0 - p.earned_share) - # Convert back to annual - return (countable_unearned + countable_earned) * MONTHS_IN_YEAR + return countable_unearned + countable_earned + + +def _apply_ssi_exclusions( + earned_income: ArrayLike, + unearned_income: ArrayLike, + parameters: ParameterNode, + period: Period, + general_exclusion: ArrayLike = None, +) -> ArrayLike: + """ + Applies the standard SSI income exclusions to annual earned and unearned + income, treating each month as one-twelfth of the year, and returns + annual countable income. The exclusions are monthly amounts, so this + converts annual -> monthly, applies them, then goes back to annual. + """ + monthly = _apply_ssi_exclusions_monthly( + earned_income / MONTHS_IN_YEAR, + unearned_income / MONTHS_IN_YEAR, + parameters, + period, + general_exclusion, + ) + return monthly * MONTHS_IN_YEAR diff --git a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_in_kind_support_and_maintenance.py b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_in_kind_support_and_maintenance.py index 993b20fe33b..7e87a1d5e5b 100644 --- a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_in_kind_support_and_maintenance.py +++ b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_in_kind_support_and_maintenance.py @@ -6,7 +6,7 @@ class ssi_in_kind_support_and_maintenance(Variable): entity = Person label = "SSI in-kind support and maintenance" unit = USD - definition_period = YEAR + definition_period = MONTH reference = ( "https://www.law.cornell.edu/cfr/text/20/416.1130", "https://www.law.cornell.edu/cfr/text/20/416.1140", @@ -14,7 +14,7 @@ class ssi_in_kind_support_and_maintenance(Variable): def formula(person, period, parameters): # ISM is counted as unearned income for own-household recipients - # who receive shelter (or food, pre-10/2024) support. + # who receive shelter support (or food, before September 30, 2024). # The PMV rule caps ISM at the presumed maximum value. # If the recipient provides an actual shelter value (rebuttal), # ISM is the lesser of the actual value and the PMV. diff --git a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_pmv_amount.py b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_pmv_amount.py index 18c70e2a9be..101b7aa6b11 100644 --- a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_pmv_amount.py +++ b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_pmv_amount.py @@ -6,7 +6,7 @@ class ssi_pmv_amount(Variable): entity = Person label = "SSI presumed maximum value amount" unit = USD - definition_period = YEAR + definition_period = MONTH reference = ( "https://www.law.cornell.edu/cfr/text/20/416.1140", "https://secure.ssa.gov/poms.nsf/lnx/0500835300", @@ -34,5 +34,4 @@ def formula(person, period, parameters): pmv_monthly = ( applicable_fbr * p.income.ism.pmv_fbr_fraction + p.income.exclusions.general ) - pmv_monthly = where(deeming_applies, pmv_monthly / 2, pmv_monthly) - return pmv_monthly * MONTHS_IN_YEAR + return where(deeming_applies, pmv_monthly / 2, pmv_monthly) diff --git a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_pmv_applies.py b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_pmv_applies.py index afad7780207..be38891ec2e 100644 --- a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_pmv_applies.py +++ b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_pmv_applies.py @@ -8,10 +8,11 @@ class ssi_pmv_applies(Variable): value_type = bool entity = Person label = "SSI presumed maximum value rule applies" - definition_period = YEAR + definition_period = MONTH reference = ( "https://www.law.cornell.edu/cfr/text/20/416.1140", "https://www.law.cornell.edu/cfr/text/20/416.1141", + "https://www.govinfo.gov/content/pkg/FR-2024-03-27/pdf/2024-06464.pdf#page=1", ) def formula(person, period, parameters): @@ -20,9 +21,19 @@ def formula(person, period, parameters): receives_shelter = person( "ssi_receives_outside_shelter_support", period ) | person("ssi_receives_shelter_from_others_in_household", period) - # Before 9/30/2024, food also counted as ISM under the PMV rule. - # After 9/30/2024, only shelter triggers PMV (89 FR 21210). - food_counts = parameters(period).gov.ssa.ssi.income.ism.food_counts + # Food stopped counting as ISM on September 30, 2024 (89 FR 21199). + # Food still counts in a month that starts before that date, except + # when all of the month's food from others was received or paid for + # on or after it. The PMV is not prorated by day. + food_counts = bool(parameters(period).gov.ssa.ssi.income.ism.food_counts) + food_counts_at_month_end = bool( + parameters(period.stop).gov.ssa.ssi.income.ism.food_counts + ) + exclusion_starts_this_month = food_counts and not food_counts_at_month_end + food_only_after_exclusion = person( + "ssi_food_from_others_only_on_or_after_food_exclusion", period + ) + late_food_excluded = exclusion_starts_this_month & food_only_after_exclusion receives_food = person("ssi_receives_food_from_others", period) - receives_ism_support = receives_shelter | (receives_food & food_counts) - return is_own_household & receives_ism_support + receives_counted_food = receives_food & food_counts & ~late_food_excluded + return is_own_household & (receives_shelter | receives_counted_food) diff --git a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_shelter_support_value.py b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_shelter_support_value.py index d7d9ca3d72e..e8c73bef159 100644 --- a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_shelter_support_value.py +++ b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ism/ssi_shelter_support_value.py @@ -4,9 +4,9 @@ class ssi_shelter_support_value(Variable): value_type = float entity = Person - label = "Actual annual value of shelter support received for SSI ISM purposes" + label = "Actual monthly value of shelter support received for SSI ISM purposes" unit = USD - definition_period = YEAR + definition_period = MONTH reference = ( "https://www.law.cornell.edu/cfr/text/20/416.1140", "https://secure.ssa.gov/poms.nsf/lnx/0500835300", diff --git a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ssi_countable_income.py b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ssi_countable_income.py index 1d268ec5b6c..f946a4da8c9 100644 --- a/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ssi_countable_income.py +++ b/policyengine_us/variables/gov/ssa/ssi/eligibility/income/ssi_countable_income.py @@ -1,6 +1,6 @@ from policyengine_us.model_api import * from policyengine_us.variables.gov.ssa.ssi.eligibility.income._apply_ssi_exclusions import ( - _apply_ssi_exclusions, + _apply_ssi_exclusions_monthly, ) @@ -9,7 +9,7 @@ class ssi_countable_income(Variable): entity = Person label = "SSI countable income" unit = USD - definition_period = YEAR + definition_period = MONTH reference = "https://www.law.cornell.edu/uscode/text/42/1382a#b" documentation = """ Calculates total countable income for SSI: @@ -23,9 +23,15 @@ class ssi_countable_income(Variable): ISM is added to unearned income BEFORE exclusions per 20 CFR § 416.1140. The PMV formula includes $20 so that after the general exclusion applies, the net countable ISM equals 1/3 FBR (matching POMS SI 00835.901 values). + + Countable income is computed for each month, so a change in ISM within a + year (such as food ceasing to count on September 30, 2024) reaches the + months it applies to. Annual queries sum the months. """ def formula(person, period, parameters): + # YEAR-defined income amounts read for a month are one-twelfth of the + # annual amount; ISM is MONTH-defined and read for the month itself. # The individual's earned income, after the blind/disabled student exclusion pre_reduction_earned_income = person("ssi_marital_earned_income", period) blind_disabled_working_student_income = person( @@ -56,7 +62,7 @@ def formula(person, period, parameters): total_unearned = unearned_income + parent_deemed + ism # Apply standard SSI exclusions to the individual's own income - personal_countable = _apply_ssi_exclusions( + personal_countable = _apply_ssi_exclusions_monthly( earned_income, total_unearned, parameters, diff --git a/policyengine_us/variables/gov/ssa/ssi/eligibility/status/ssi_food_from_others_only_on_or_after_food_exclusion.py b/policyengine_us/variables/gov/ssa/ssi/eligibility/status/ssi_food_from_others_only_on_or_after_food_exclusion.py new file mode 100644 index 00000000000..24d61dde203 --- /dev/null +++ b/policyengine_us/variables/gov/ssa/ssi/eligibility/status/ssi_food_from_others_only_on_or_after_food_exclusion.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class ssi_food_from_others_only_on_or_after_food_exclusion(Variable): + value_type = bool + entity = Person + label = ( + "All food from others this month came on or after the SSI food exclusion date" + ) + documentation = ( + "Whether all of the food this person received from others in the " + "month was received or paid for on or after the date food stopped " + "counting as in-kind support and maintenance (September 30, 2024). " + "Only matters in the month that date falls in." + ) + definition_period = MONTH + default_value = False + reference = ( + "https://www.govinfo.gov/content/pkg/FR-2024-03-27/pdf/2024-06464.pdf#page=1", + "https://secure.ssa.gov/apps10/referencearchive.nsf/links/09202024102751AM", + ) diff --git a/policyengine_us/variables/gov/states/hi/bessd/ccap/hi_ccap_tanf_income.py b/policyengine_us/variables/gov/states/hi/bessd/ccap/hi_ccap_tanf_income.py new file mode 100644 index 00000000000..fcc8726efc0 --- /dev/null +++ b/policyengine_us/variables/gov/states/hi/bessd/ccap/hi_ccap_tanf_income.py @@ -0,0 +1,28 @@ +from policyengine_us.model_api import * + + +class hi_ccap_tanf_income(Variable): + value_type = float + entity = SPMUnit + label = "Hawaii TANF payments counted as Hawaii CCAP income" + unit = USD + definition_period = MONTH + defined_for = StateCode.HI + reference = ( + # HAR 17-798.3-10(b)(11), eff. 2021-08-06. + "https://www.law.cornell.edu/regulations/hawaii/Haw-Code-R-SS-17-798-3-10", + ) + + def formula(spm_unit, period, parameters): + # HAR 17-798.3-10(b)(11) counts "Hawaii public assistance payments + # prior to any reduction of the monthly assistance payment due to + # overpayment recovery". The model has no overpayment recovery, so + # the payment is the Hawaii TANF grant the family takes up. + # Reading tanf here would be circular: tanf sums every state's TANF + # program, several of which deduct childcare_expenses, which nets + # out child_care_subsidies, which includes Hawaii CCAP. hi_tanf under + # the TANF take-up gate equals tanf for Hawaii households. + if parameters(period).gov.hhs.tanf.abolish_tanf: + return 0 + takes_up = spm_unit("takes_up_tanf_if_eligible", period.this_year) + return spm_unit("hi_tanf", period) * takes_up diff --git a/policyengine_us/variables/gov/states/hi/dhs/tanf/income/hi_tanf_dependent_care_deduction.py b/policyengine_us/variables/gov/states/hi/dhs/tanf/income/hi_tanf_dependent_care_deduction.py index a07aa2f7839..96391afe022 100644 --- a/policyengine_us/variables/gov/states/hi/dhs/tanf/income/hi_tanf_dependent_care_deduction.py +++ b/policyengine_us/variables/gov/states/hi/dhs/tanf/income/hi_tanf_dependent_care_deduction.py @@ -8,37 +8,30 @@ class hi_tanf_dependent_care_deduction(Variable): unit = USD definition_period = MONTH reference = ( + # HAR 17-676-54.1(c)(4) and (d)(4), PDF pages 36-37 + "https://humanservices.hawaii.gov/wp-content/uploads/2019/03/HAR-17-676-INCOME.pdf#page=36", "https://humanservices.hawaii.gov/wp-content/uploads/2024/12/Hawaii_TANF_State_Plan_Signed_Certified-Eff_20231001.pdf#page=20", ) defined_for = StateCode.HI def formula(spm_unit, period, parameters): p = parameters(period).gov.states.hi.dhs.tanf.deductions.dependent_care - - # Per State Plan section 10.2.1(D), the deduction covers the cost - # of care for a disabled adult household member; care of children - # also flows through the same per-person caps. - childcare_expenses = spm_unit("childcare_expenses", period) - adult_care_expenses = add(spm_unit, period, ["care_expenses"]) - - # Count children and disabled adults in the unit for the per-person cap + # HAR 17-676-54.1(c)(4) and (d)(4) deduct "the actual cost for the + # care of each incapacitated adult living in the same household and + # receiving financial assistance", up to $175 a month if the + # applicant is employed full time or $165 if less than full time. + # The rule covers incapacitated adults only; child care costs are + # not deducted here. person = spm_unit.members - is_child = person("is_child", period.this_year) is_adult = ~person("is_child", period.this_year) - is_disabled_adult = is_adult & person("is_disabled", period.this_year) - num_care_recipients = spm_unit.sum(is_child | is_disabled_adult) - - # Determine rate based on MAX of adult hours - # If either parent works full-time, use full-time rate + care_cost = is_adult * person( + "hi_tanf_qualifying_incapacitated_adult_care_expenses", period + ) + # The cap follows the working applicant's employment: full time is + # 32 or more hours a week (HAR 17-676-2). When several adults work, + # the applicant is treated as full time if any of them is. hours = person("weekly_hours_worked_before_lsr", period.this_year) - # Only consider adult hours (children get 0) - adult_hours = where(is_adult, hours, 0) - max_adult_hours = spm_unit.max(adult_hours) - - # Full-time = 32+ hours/week - # Rate is $175 (full-time) or $165 (part-time) per person - rate = p.amount.calc(max_adult_hours) - max_deduction = num_care_recipients * rate - - # Deduct actual cost up to max per care recipient - return min_(childcare_expenses + adult_care_expenses, max_deduction) + max_adult_hours = spm_unit.max(where(is_adult, hours, 0)) + cap = spm_unit.project(p.amount.calc(max_adult_hours)) + # Each adult's cost is capped separately. + return spm_unit.sum(min_(care_cost, cap)) diff --git a/policyengine_us/variables/gov/states/hi/dhs/tanf/income/hi_tanf_qualifying_incapacitated_adult_care_expenses.py b/policyengine_us/variables/gov/states/hi/dhs/tanf/income/hi_tanf_qualifying_incapacitated_adult_care_expenses.py new file mode 100644 index 00000000000..4ab73f28774 --- /dev/null +++ b/policyengine_us/variables/gov/states/hi/dhs/tanf/income/hi_tanf_qualifying_incapacitated_adult_care_expenses.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class hi_tanf_qualifying_incapacitated_adult_care_expenses(Variable): + value_type = float + entity = Person + label = "Hawaii TANF qualifying incapacitated adult care expenses" + documentation = ( + "Actual monthly cost of care for this person, when the person is an " + "incapacitated adult who lives in the household and receives Hawaii " + "TANF financial assistance (HAR 17-676-54.1(c)(4) and (d)(4)). Leave " + "at zero for anyone who does not meet those conditions." + ) + unit = USD + definition_period = MONTH + default_value = 0 + reference = ( + # PDF pages 36-37 + "https://humanservices.hawaii.gov/wp-content/uploads/2019/03/HAR-17-676-INCOME.pdf#page=36", + ) diff --git a/policyengine_us/variables/gov/states/mo/dss/tanf/mo_tanf.py b/policyengine_us/variables/gov/states/mo/dss/tanf/mo_tanf.py index e80e86666d5..8357c2522ee 100644 --- a/policyengine_us/variables/gov/states/mo/dss/tanf/mo_tanf.py +++ b/policyengine_us/variables/gov/states/mo/dss/tanf/mo_tanf.py @@ -9,6 +9,9 @@ class mo_tanf(Variable): definition_period = MONTH reference = ( "https://www.law.cornell.edu/regulations/missouri/13-CSR-40-2-310", + # 13 CSR 40-2.310(14): payments lowered to the whole dollar; no + # payment below $10. + "https://www.sos.mo.gov/cmsimages/adrules/csr/current/13csr/13c40-2.pdf#page=36", "https://dssmanuals.mo.gov/temporary-assistance-case-management/0210-010-15/", ) defined_for = "mo_tanf_eligible" @@ -19,4 +22,8 @@ def formula(spm_unit, period, parameters): benefit = max_(maximum_benefit - countable_income, 0) capped_benefit = min_(benefit, maximum_benefit) p = parameters(period).gov.states.mo.dss.tanf - return where(capped_benefit >= p.minimum_payment, capped_benefit, 0) + # 13 CSR 40-2.310(14): "In the payment of TA benefits, the amount + # shall always be lowered to the nearest dollar interval", and a + # grant below $10 is not paid. + payment = np.floor(capped_benefit) + return where(payment >= p.minimum_payment, payment, 0) diff --git a/policyengine_us/variables/gov/usda/snap/income/snap_income_standard_helpers.py b/policyengine_us/variables/gov/usda/snap/income/snap_income_standard_helpers.py index 3f51fc266e3..17eca74ecff 100644 --- a/policyengine_us/variables/gov/usda/snap/income/snap_income_standard_helpers.py +++ b/policyengine_us/variables/gov/usda/snap/income/snap_income_standard_helpers.py @@ -1,11 +1,26 @@ from policyengine_us.model_api import * +# 7 CFR 273.9(a)(1)(i), (a)(2)(i): +# https://www.govinfo.gov/content/pkg/CFR-2025-title7-vol4/pdf/CFR-2025-title7-vol4-sec273-9.pdf#page=1 +SNAP_CONTIGUOUS_US_GUIDELINE_AREAS = ["GU", "VI"] + def snap_monthly_fpg_amounts(spm_unit, period, parameters): """Monthly poverty guideline for the first person and for each additional person, from the guidelines SNAP adopts each October 1 (7 CFR 273.9(a)(3)). + + Guam and the Virgin Islands use the guidelines for the 48 contiguous + States and the District of Columbia (7 CFR 273.9(a)(1)(i) and (a)(2)(i)), + so they read the contiguous-US guideline rather than their own zero + placeholders. This mapping is specific to SNAP income standards; the + households keep their own state group elsewhere. """ state_group = spm_unit.household("state_group_str", period.this_year) + state_group = np.where( + np.isin(state_group, SNAP_CONTIGUOUS_US_GUIDELINE_AREAS), + "CONTIGUOUS_US", + state_group, + ) year = period.start.year month = period.start.month if month >= 10: