diff --git a/changelog.d/wi-ssp-2026.added.md b/changelog.d/wi-ssp-2026.added.md new file mode 100644 index 00000000000..8285a0a2057 --- /dev/null +++ b/changelog.d/wi-ssp-2026.added.md @@ -0,0 +1 @@ +Add Wisconsin Caretaker Supplement eligibility, income tests and child benefit payments. Add Wisconsin State SSI Supplement and certified exceptional-expense payments, including the May 2026 rate increase. diff --git a/changelog.d/wi-ssp-2026.fixed.md b/changelog.d/wi-ssp-2026.fixed.md new file mode 100644 index 00000000000..2797f23e6da --- /dev/null +++ b/changelog.d/wi-ssp-2026.fixed.md @@ -0,0 +1 @@ +Make Wisconsin Works (W-2) units ineligible when every custodial parent receives SSI, under Wis. Stat. 49.145(2)(i); a custodial parent not on SSI can still qualify. diff --git a/policyengine_us/parameters/gov/household/household_state_benefits.yaml b/policyengine_us/parameters/gov/household/household_state_benefits.yaml index d2cbd6ba2d4..a784dd18915 100644 --- a/policyengine_us/parameters/gov/household/household_state_benefits.yaml +++ b/policyengine_us/parameters/gov/household/household_state_benefits.yaml @@ -73,6 +73,8 @@ values: - tx_ssi_state_supplement # Virginia benefits - va_child_care_subsidies + # Wisconsin benefits + - wi_ssp # Massachusetts benefits - ma_eaedc # DC benefits @@ -167,6 +169,8 @@ values: - va_child_care_subsidies # West Virginia benefits - wv_child_care_subsidies + # Wisconsin benefits + - wi_ssp # North Carolina benefits - nc_child_care_subsidies # South Carolina benefits @@ -269,6 +273,8 @@ values: - va_child_care_subsidies # West Virginia benefits - wv_child_care_subsidies + # Wisconsin benefits + - wi_ssp # North Carolina benefits - nc_child_care_subsidies # South Carolina benefits @@ -372,6 +378,8 @@ values: - va_child_care_subsidies # West Virginia benefits - wv_child_care_subsidies + # Wisconsin benefits + - wi_ssp # North Carolina benefits - nc_child_care_subsidies # South Carolina benefits @@ -401,6 +409,7 @@ values: - nj_property_tax_relief # New York benefits - ny_child_care_subsidies + metadata: unit: list period: year diff --git a/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml b/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml index 0df11213631..2df4648c02b 100644 --- a/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/hud/annual_income/sources/unearned.yaml @@ -19,6 +19,8 @@ values: - strike_benefits - social_security - ssi + # Exclude only SSI-E meeting the assisted-home care conditions. + - wi_ssp_countable_for_hud - general_assistance - total_unemployment_compensation - child_support_received @@ -29,6 +31,7 @@ values: - disability_benefits - survivor_benefits - financial_assistance + metadata: unit: list period: year diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/amount/couple.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/amount/couple.yaml new file mode 100644 index 00000000000..4e4fbe96728 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/amount/couple.yaml @@ -0,0 +1,12 @@ +description: Wisconsin provides this amount as the payment per couple under the State Supplementary Payment program. +values: + 2026-01-01: 132.05 + 2026-05-01: 145.26 + +metadata: + unit: currency-USD + period: month + label: Wisconsin SSP payment amount per couple + reference: + - title: Wisconsin DMS Operations Memo 26-12, Increase to SSI State Supplementary Payments + href: https://www.dhs.wisconsin.gov/dms/memos/ops/dms-ops-2026-12.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/amount/individual.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/amount/individual.yaml new file mode 100644 index 00000000000..ba8e1a65333 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/amount/individual.yaml @@ -0,0 +1,12 @@ +description: Wisconsin provides this amount as the individual payment under the State Supplementary Payment program. +values: + 2026-01-01: 83.78 + 2026-05-01: 92.16 + +metadata: + unit: currency-USD + period: month + label: Wisconsin SSP individual payment amount + reference: + - title: Wisconsin DMS Operations Memo 26-12, Increase to SSI State Supplementary Payments + href: https://www.dhs.wisconsin.gov/dms/memos/ops/dms-ops-2026-12.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/amount/ineligible_spouse_independent.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/amount/ineligible_spouse_independent.yaml new file mode 100644 index 00000000000..aff674c9ae4 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/amount/ineligible_spouse_independent.yaml @@ -0,0 +1,12 @@ +description: Wisconsin provides this amount to a recipient living independently with an ineligible spouse under the State Supplementary Payment program. +values: + 2026-01-01: 130.43 + 2026-05-01: 143.47 + +metadata: + unit: currency-USD + period: month + label: Wisconsin SSP payment amount with an ineligible spouse living independently + reference: + - title: Wisconsin DMS Operations Memo 26-12, Increase to SSI State Supplementary Payments + href: https://www.dhs.wisconsin.gov/dms/memos/ops/dms-ops-2026-12.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/amount/ineligible_spouse_other_household.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/amount/ineligible_spouse_other_household.yaml new file mode 100644 index 00000000000..1605e5e5d6a --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/amount/ineligible_spouse_other_household.yaml @@ -0,0 +1,12 @@ +description: Wisconsin provides this amount to a recipient with an ineligible spouse in another household under the State Supplementary Payment program. +values: + 2026-01-01: 135.05 + 2026-05-01: 148.56 + +metadata: + unit: currency-USD + period: month + label: Wisconsin SSP payment amount with an ineligible spouse in another person's household + reference: + - title: Wisconsin DMS Operations Memo 26-12, Increase to SSI State Supplementary Payments + href: https://www.dhs.wisconsin.gov/dms/memos/ops/dms-ops-2026-12.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/additional_child.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/additional_child.yaml new file mode 100644 index 00000000000..9f9d42d0bd7 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/additional_child.yaml @@ -0,0 +1,13 @@ +description: Wisconsin provides this amount as the monthly payment for each additional eligible child under the Caretaker Supplement program. +values: + 2026-01-01: 165 + +metadata: + unit: currency-USD + period: month + label: Wisconsin CTS additional eligible child benefit + reference: + - title: Wis. Stat. 49.775(4) + href: https://docs.legis.wisconsin.gov/document/statutes/49.775 + - title: Caretaker Supplement Handbook 5.2.6 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=65 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/area_i_counties.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/area_i_counties.yaml new file mode 100644 index 00000000000..a252539a97c --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/area_i_counties.yaml @@ -0,0 +1,30 @@ +description: Wisconsin applies the Area I income limits in these counties under the Caretaker Supplement program. +values: + 2026-01-01: + - BROWN_COUNTY_WI + - DANE_COUNTY_WI + - DODGE_COUNTY_WI + - DUNN_COUNTY_WI + - EAU_CLAIRE_COUNTY_WI + - FOND_DU_LAC_COUNTY_WI + - KENOSHA_COUNTY_WI + - LA_CROSSE_COUNTY_WI + - MARATHON_COUNTY_WI + - MANITOWOC_COUNTY_WI + - MILWAUKEE_COUNTY_WI + - OUTAGAMIE_COUNTY_WI + - OZAUKEE_COUNTY_WI + - RACINE_COUNTY_WI + - ROCK_COUNTY_WI + - ST_CROIX_COUNTY_WI + - SHEBOYGAN_COUNTY_WI + - WASHINGTON_COUNTY_WI + - WAUKESHA_COUNTY_WI + - WINNEBAGO_COUNTY_WI + +metadata: + unit: list + label: Wisconsin CTS Area I counties + reference: + - title: Caretaker Supplement Handbook 5.2.3 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=63 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/care_other_limit.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/care_other_limit.yaml new file mode 100644 index 00000000000..b43dd2974fd --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/care_other_limit.yaml @@ -0,0 +1,11 @@ +description: Wisconsin limits the dependent care deduction to this monthly amount for each older child and each incapacitated adult under the Caretaker Supplement program. +values: + 2026-01-01: 175 + +metadata: + unit: currency-USD + period: month + label: Wisconsin CTS older child care deduction limit + reference: + - title: Caretaker Supplement Handbook 3.2.1.2.3 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/care_young_age.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/care_young_age.yaml new file mode 100644 index 00000000000..799f27f4f1a --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/care_young_age.yaml @@ -0,0 +1,10 @@ +description: Wisconsin applies the higher dependent care deduction to children below this age under the Caretaker Supplement program. +values: + 2026-01-01: 2 + +metadata: + unit: year + label: Wisconsin CTS young child care age limit + reference: + - title: Caretaker Supplement Handbook 3.2.1.2.3 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/care_young_limit.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/care_young_limit.yaml new file mode 100644 index 00000000000..f5fa63dfb27 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/care_young_limit.yaml @@ -0,0 +1,11 @@ +description: Wisconsin limits the dependent care deduction to this monthly amount for each young child under the Caretaker Supplement program. +values: + 2026-01-01: 200 + +metadata: + unit: currency-USD + period: month + label: Wisconsin CTS young child care deduction limit + reference: + - title: Caretaker Supplement Handbook 3.2.1.2.3 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/earned_flat.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/earned_flat.yaml new file mode 100644 index 00000000000..629d34646b2 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/earned_flat.yaml @@ -0,0 +1,11 @@ +description: Wisconsin disregards this amount of monthly earned income, after the work expense deduction, under the Caretaker Supplement program. +values: + 2026-01-01: 30 + +metadata: + unit: currency-USD + period: month + label: Wisconsin CTS additional flat earned income disregard + reference: + - title: Caretaker Supplement Handbook 3.2.1.2.3 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/earned_fraction.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/earned_fraction.yaml new file mode 100644 index 00000000000..17417d37cf9 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/earned_fraction.yaml @@ -0,0 +1,10 @@ +description: Wisconsin disregards this share of remaining earned income under the Caretaker Supplement program. +values: + 2026-01-01: 0.3333333333333333 + +metadata: + unit: /1 + label: Wisconsin CTS additional earned income disregard fraction + reference: + - title: Caretaker Supplement Handbook 3.2.1.2.3 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/eligible_immigration_statuses.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/eligible_immigration_statuses.yaml new file mode 100644 index 00000000000..4aee497a995 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/eligible_immigration_statuses.yaml @@ -0,0 +1,21 @@ +description: Wisconsin limits eligibility to these immigration statuses under the Caretaker Supplement program. +values: + # PAROLED_ONE_YEAR is parole under 8 USC 1182(d)(5), one of the lawful + # presence grounds that Handbook 3.1.4 item 2 lists. + 2026-01-01: + - CITIZEN + - LEGAL_PERMANENT_RESIDENT + - REFUGEE + - ASYLEE + - CUBAN_HAITIAN_ENTRANT + - DEPORTATION_WITHHELD + - CONDITIONAL_ENTRANT + - PAROLED_ONE_YEAR + +metadata: + unit: list + period: year + label: Wisconsin CTS eligible immigration statuses + reference: + - title: "Caretaker Supplement Handbook 3.1.4 #page 19-20" + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=19 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/first_child.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/first_child.yaml new file mode 100644 index 00000000000..32ea86d3a84 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/first_child.yaml @@ -0,0 +1,13 @@ +description: Wisconsin provides this amount as the monthly payment for the first eligible child under the Caretaker Supplement program. +values: + 2026-01-01: 275 + +metadata: + unit: currency-USD + period: month + label: Wisconsin CTS first eligible child benefit + reference: + - title: Wis. Stat. 49.775(4) + href: https://docs.legis.wisconsin.gov/document/statutes/49.775 + - title: Caretaker Supplement Handbook 5.2.6 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=65 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross/area_1.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross/area_1.yaml new file mode 100644 index 00000000000..b777800e0bf --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross/area_1.yaml @@ -0,0 +1,62 @@ +description: Wisconsin limits monthly gross income to these amounts by assistance group size in Area I counties under the Caretaker Supplement program. + +metadata: + unit: currency-USD + period: month + label: Wisconsin CTS Area I gross income limits + type: single_amount + threshold_unit: person + amount_unit: currency-USD + reference: + - title: Caretaker Supplement Handbook 5.2.1 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=62 + +brackets: + - threshold: + 2026-01-01: 1 + amount: + 2026-01-01: 576 + - threshold: + 2026-01-01: 2 + amount: + 2026-01-01: 1_018 + - threshold: + 2026-01-01: 3 + amount: + 2026-01-01: 1_197 + - threshold: + 2026-01-01: 4 + amount: + 2026-01-01: 1_429 + - threshold: + 2026-01-01: 5 + amount: + 2026-01-01: 1_640 + - threshold: + 2026-01-01: 6 + amount: + 2026-01-01: 1_773 + - threshold: + 2026-01-01: 7 + amount: + 2026-01-01: 1_919 + - threshold: + 2026-01-01: 8 + amount: + 2026-01-01: 2_034 + - threshold: + 2026-01-01: 9 + amount: + 2026-01-01: 2_130 + - threshold: + 2026-01-01: 10 + amount: + 2026-01-01: 2_182 + - threshold: + 2026-01-01: 11 + amount: + 2026-01-01: 2_228 + - threshold: + 2026-01-01: 12 + amount: + 2026-01-01: 2_274 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross/area_2.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross/area_2.yaml new file mode 100644 index 00000000000..09d041e2151 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross/area_2.yaml @@ -0,0 +1,62 @@ +description: Wisconsin limits monthly gross income to these amounts by assistance group size in Area II counties under the Caretaker Supplement program. + +metadata: + unit: currency-USD + period: month + label: Wisconsin CTS Area II gross income limits + type: single_amount + threshold_unit: person + amount_unit: currency-USD + reference: + - title: Caretaker Supplement Handbook 5.2.1 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=62 + +brackets: + - threshold: + 2026-01-01: 1 + amount: + 2026-01-01: 557 + - threshold: + 2026-01-01: 2 + amount: + 2026-01-01: 987 + - threshold: + 2026-01-01: 3 + amount: + 2026-01-01: 1_159 + - threshold: + 2026-01-01: 4 + amount: + 2026-01-01: 1_386 + - threshold: + 2026-01-01: 5 + amount: + 2026-01-01: 1_593 + - threshold: + 2026-01-01: 6 + amount: + 2026-01-01: 1_719 + - threshold: + 2026-01-01: 7 + amount: + 2026-01-01: 1_863 + - threshold: + 2026-01-01: 8 + amount: + 2026-01-01: 1_976 + - threshold: + 2026-01-01: 9 + amount: + 2026-01-01: 2_067 + - threshold: + 2026-01-01: 10 + amount: + 2026-01-01: 2_115 + - threshold: + 2026-01-01: 11 + amount: + 2026-01-01: 2_161 + - threshold: + 2026-01-01: 12 + amount: + 2026-01-01: 2_208 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross_additional.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross_additional.yaml new file mode 100644 index 00000000000..2ec92ae4b77 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross_additional.yaml @@ -0,0 +1,11 @@ +description: Wisconsin raises the gross income limit by this amount for each person beyond the largest group size in the income tables under the Caretaker Supplement program. +values: + 2026-01-01: 25 + +metadata: + unit: currency-USD + period: month + label: Wisconsin CTS gross income limit increase beyond the table + reference: + - title: "Caretaker Supplement Handbook 5.2.1 and 5.2.2 #page 62-63" + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=62 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross_pregnant/area_1.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross_pregnant/area_1.yaml new file mode 100644 index 00000000000..0192aff269e --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross_pregnant/area_1.yaml @@ -0,0 +1,62 @@ +description: Wisconsin limits the monthly gross income of an assistance group with a pregnant woman to these amounts, which include one pregnancy allowance, by group size in Area I counties under the Caretaker Supplement program. + +metadata: + unit: currency-USD + period: month + label: Wisconsin CTS Area I gross income limits with pregnancy allowance + type: single_amount + threshold_unit: person + amount_unit: currency-USD + reference: + - title: "Caretaker Supplement Handbook 5.2.2 #page 62-63" + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=62 + +brackets: + - threshold: + 2026-01-01: 1 + amount: + 2026-01-01: 707 + - threshold: + 2026-01-01: 2 + amount: + 2026-01-01: 1_149 + - threshold: + 2026-01-01: 3 + amount: + 2026-01-01: 1_329 + - threshold: + 2026-01-01: 4 + amount: + 2026-01-01: 1_560 + - threshold: + 2026-01-01: 5 + amount: + 2026-01-01: 1_771 + - threshold: + 2026-01-01: 6 + amount: + 2026-01-01: 1_904 + - threshold: + 2026-01-01: 7 + amount: + 2026-01-01: 2_050 + - threshold: + 2026-01-01: 8 + amount: + 2026-01-01: 2_165 + - threshold: + 2026-01-01: 9 + amount: + 2026-01-01: 2_261 + - threshold: + 2026-01-01: 10 + amount: + 2026-01-01: 2_313 + - threshold: + 2026-01-01: 11 + amount: + 2026-01-01: 2_359 + - threshold: + 2026-01-01: 12 + amount: + 2026-01-01: 2_405 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross_pregnant/area_2.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross_pregnant/area_2.yaml new file mode 100644 index 00000000000..34f7761d913 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/gross_pregnant/area_2.yaml @@ -0,0 +1,62 @@ +description: Wisconsin limits the monthly gross income of an assistance group with a pregnant woman to these amounts, which include one pregnancy allowance, by group size in Area II counties under the Caretaker Supplement program. + +metadata: + unit: currency-USD + period: month + label: Wisconsin CTS Area II gross income limits with pregnancy allowance + type: single_amount + threshold_unit: person + amount_unit: currency-USD + reference: + - title: "Caretaker Supplement Handbook 5.2.2 #page 62-63" + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=62 + +brackets: + - threshold: + 2026-01-01: 1 + amount: + 2026-01-01: 689 + - threshold: + 2026-01-01: 2 + amount: + 2026-01-01: 1_118 + - threshold: + 2026-01-01: 3 + amount: + 2026-01-01: 1_290 + - threshold: + 2026-01-01: 4 + amount: + 2026-01-01: 1_517 + - threshold: + 2026-01-01: 5 + amount: + 2026-01-01: 1_725 + - threshold: + 2026-01-01: 6 + amount: + 2026-01-01: 1_850 + - threshold: + 2026-01-01: 7 + amount: + 2026-01-01: 1_995 + - threshold: + 2026-01-01: 8 + amount: + 2026-01-01: 2_108 + - threshold: + 2026-01-01: 9 + amount: + 2026-01-01: 2_198 + - threshold: + 2026-01-01: 10 + amount: + 2026-01-01: 2_246 + - threshold: + 2026-01-01: 11 + amount: + 2026-01-01: 2_293 + - threshold: + 2026-01-01: 12 + amount: + 2026-01-01: 2_339 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/minor_age_limit.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/minor_age_limit.yaml new file mode 100644 index 00000000000..f824b99c3a5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/minor_age_limit.yaml @@ -0,0 +1,10 @@ +description: Wisconsin treats children younger than this age as minors under the Caretaker Supplement program. +values: + 2026-01-01: 18 + +metadata: + unit: year + label: Wisconsin CTS minor age limit + reference: + - title: Caretaker Supplement Handbook 3.1.10 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=21 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/net/area_1.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/net/area_1.yaml new file mode 100644 index 00000000000..a8c0579e1d6 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/net/area_1.yaml @@ -0,0 +1,62 @@ +description: Wisconsin limits monthly net income (the assistance standard) to these amounts by assistance group size in Area I counties under the Caretaker Supplement program. + +metadata: + unit: currency-USD + period: month + label: Wisconsin CTS Area I net income limits + type: single_amount + threshold_unit: person + amount_unit: currency-USD + reference: + - title: Caretaker Supplement Handbook 5.2.4 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=64 + +brackets: + - threshold: + 2026-01-01: 1 + amount: + 2026-01-01: 311 + - threshold: + 2026-01-01: 2 + amount: + 2026-01-01: 550 + - threshold: + 2026-01-01: 3 + amount: + 2026-01-01: 647 + - threshold: + 2026-01-01: 4 + amount: + 2026-01-01: 772 + - threshold: + 2026-01-01: 5 + amount: + 2026-01-01: 886 + - threshold: + 2026-01-01: 6 + amount: + 2026-01-01: 958 + - threshold: + 2026-01-01: 7 + amount: + 2026-01-01: 1_037 + - threshold: + 2026-01-01: 8 + amount: + 2026-01-01: 1_099 + - threshold: + 2026-01-01: 9 + amount: + 2026-01-01: 1_151 + - threshold: + 2026-01-01: 10 + amount: + 2026-01-01: 1_179 + - threshold: + 2026-01-01: 11 + amount: + 2026-01-01: 1_204 + - threshold: + 2026-01-01: 12 + amount: + 2026-01-01: 1_229 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/net/area_2.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/net/area_2.yaml new file mode 100644 index 00000000000..e866b52fe9a --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/net/area_2.yaml @@ -0,0 +1,62 @@ +description: Wisconsin limits monthly net income (the assistance standard) to these amounts by assistance group size in Area II counties under the Caretaker Supplement program. + +metadata: + unit: currency-USD + period: month + label: Wisconsin CTS Area II net income limits + type: single_amount + threshold_unit: person + amount_unit: currency-USD + reference: + - title: Caretaker Supplement Handbook 5.2.4 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=64 + +brackets: + - threshold: + 2026-01-01: 1 + amount: + 2026-01-01: 301 + - threshold: + 2026-01-01: 2 + amount: + 2026-01-01: 533 + - threshold: + 2026-01-01: 3 + amount: + 2026-01-01: 626 + - threshold: + 2026-01-01: 4 + amount: + 2026-01-01: 749 + - threshold: + 2026-01-01: 5 + amount: + 2026-01-01: 861 + - threshold: + 2026-01-01: 6 + amount: + 2026-01-01: 929 + - threshold: + 2026-01-01: 7 + amount: + 2026-01-01: 1_007 + - threshold: + 2026-01-01: 8 + amount: + 2026-01-01: 1_068 + - threshold: + 2026-01-01: 9 + amount: + 2026-01-01: 1_117 + - threshold: + 2026-01-01: 10 + amount: + 2026-01-01: 1_143 + - threshold: + 2026-01-01: 11 + amount: + 2026-01-01: 1_168 + - threshold: + 2026-01-01: 12 + amount: + 2026-01-01: 1_193 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/pregnancy_allowance.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/pregnancy_allowance.yaml new file mode 100644 index 00000000000..3a1fbcf1b77 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/pregnancy_allowance.yaml @@ -0,0 +1,11 @@ +description: Wisconsin raises the net income limit by this amount for each pregnant woman, and the gross income limit for each pregnant woman after the first, under the Caretaker Supplement program. +values: + 2026-01-01: 71 + +metadata: + unit: currency-USD + period: month + label: Wisconsin CTS pregnancy allowance + reference: + - title: "Caretaker Supplement Handbook 5.2.2 and 5.2.5 #page 63-65" + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=63 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/resource_limit.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/resource_limit.yaml new file mode 100644 index 00000000000..fd10803782c --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/resource_limit.yaml @@ -0,0 +1,10 @@ +description: Wisconsin limits the countable assets of the assistance group to this amount under the Caretaker Supplement program. +values: + 2026-01-01: 1_000 + +metadata: + unit: currency-USD + label: Wisconsin CTS resource limit + reference: + - title: Caretaker Supplement Handbook 3.2.2 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/student_age_limit.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/student_age_limit.yaml new file mode 100644 index 00000000000..ea75ea2daee --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/student_age_limit.yaml @@ -0,0 +1,10 @@ +description: Wisconsin counts a high school student who is expected to graduate before this age as a dependent child under the Caretaker Supplement program. +values: + 2026-01-01: 19 + +metadata: + unit: year + label: Wisconsin CTS dependent student age limit + reference: + - title: Caretaker Supplement Handbook 3.1.10 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=21 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/student_hours_limit.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/student_hours_limit.yaml new file mode 100644 index 00000000000..1f09a6d006c --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/student_hours_limit.yaml @@ -0,0 +1,10 @@ +description: Wisconsin exempts a continuing part-time student's earnings when weekly work hours are below this number under the Caretaker Supplement program. +values: + 2026-01-01: 30 + +metadata: + unit: hour + label: Wisconsin CTS part-time student weekly work limit + reference: + - title: Caretaker Supplement Handbook 3.2.1.2.3 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/work_expense.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/work_expense.yaml new file mode 100644 index 00000000000..ca884ad4540 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/cts/work_expense.yaml @@ -0,0 +1,11 @@ +description: Wisconsin deducts this amount from the monthly earned income of each employed or self-employed person under the Caretaker Supplement program. +values: + 2026-01-01: 90 + +metadata: + unit: currency-USD + period: month + label: Wisconsin CTS work expense deduction + reference: + - title: Caretaker Supplement Handbook 3.2.1.2.3 + href: https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/exceptional_expense/couple.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/exceptional_expense/couple.yaml new file mode 100644 index 00000000000..bbc7cd8637d --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/exceptional_expense/couple.yaml @@ -0,0 +1,12 @@ +description: Wisconsin provides this amount as the exceptional expense supplement per couple under the State Supplementary Payment program. +values: + 2026-01-01: 345.36 + 2026-05-01: 379.9 + +metadata: + unit: currency-USD + period: month + label: Wisconsin SSP exceptional expense supplement amount per couple + reference: + - title: Wisconsin DMS Operations Memo 26-12, Increase to SSI State Supplementary Payments + href: https://www.dhs.wisconsin.gov/dms/memos/ops/dms-ops-2026-12.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/wi/dhs/ssp/exceptional_expense/individual.yaml b/policyengine_us/parameters/gov/states/wi/dhs/ssp/exceptional_expense/individual.yaml new file mode 100644 index 00000000000..45d7b4bd535 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wi/dhs/ssp/exceptional_expense/individual.yaml @@ -0,0 +1,12 @@ +description: Wisconsin provides this amount as the individual exceptional expense supplement under the State Supplementary Payment program. +values: + 2026-01-01: 95.99 + 2026-05-01: 105.59 + +metadata: + unit: currency-USD + period: month + label: Wisconsin SSP individual exceptional expense supplement amount + reference: + - title: Wisconsin DMS Operations Memo 26-12, Increase to SSI State Supplementary Payments + href: https://www.dhs.wisconsin.gov/dms/memos/ops/dms-ops-2026-12.pdf#page=2 diff --git a/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml b/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml index e9baee603e8..e53116f04bb 100644 --- a/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml +++ b/policyengine_us/parameters/gov/usda/snap/income/sources/unearned.yaml @@ -50,6 +50,7 @@ values: - sc_ssi_state_supplement - tx_ssi_state_supplement - wa_ssp + - wi_ssp_countable_for_snap # Listed elsewhere: ca_state_supplement is an SPM unit variable with no # person-level counterpart. policyengine-core projects a group value onto # every member, so listing it here would count it once per person in the @@ -95,9 +96,7 @@ values: metadata: reference: - - title: 7 CFR 273.9(b)(2) - href: https://www.law.cornell.edu/cfr/text/7/273.9#b_2 - - title: 7 CFR 273.9(c)(1) - href: https://www.law.cornell.edu/cfr/text/7/273.9#c_1 + - title: 7 CFR 273.9(b)(2) and (c)(1) + href: https://www.law.cornell.edu/cfr/text/7/273.9 - title: POMS SI 01401.001 General Information about State Supplementation href: https://secure.ssa.gov/poms.nsf/lnx/0501401001 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 5250ab3aa89..73b3e56edfc 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1093,6 +1093,19 @@ programs: tracks. Unmodeled paths: grandfathered medically-needy-in-medical- institution recipients per WAC 388-478-0055(2)(b); DDA-determined / PVL track per (2)(f); and foster child in BRS per (2)(g). + - state: WI + status: partial + name: Wisconsin SSP + full_name: Wisconsin State SSI Supplement + variable: wi_ssp + parameter_prefix: gov.states.wi.dhs.ssp + verified_years: "2026" + notes: >- + Models 2026 regular State SSI Supplement, certified Exceptional + Expense (SSI-E) and Caretaker Supplement payments, including the May + 2026 regular and SSI-E rate increase. Grandfathered state-only SSI recipients are not modeled; + without parent IDs the Caretaker Supplement pays one SSI parent per + family, and groups over 12 need a supplied net income limit. - id: social_security name: Social Security diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/dcf/works/wi_works_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/dcf/works/wi_works_eligible.yaml index 79e77ff7c3b..9c07a3758da 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/wi/dcf/works/wi_works_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/dcf/works/wi_works_eligible.yaml @@ -59,3 +59,233 @@ state_code: CA output: wi_works_eligible: false + +- name: Case 7, SSI parent cannot receive W-2 for the same month. + period: 2026-01 + input: + people: + person1: + age: 35 + ssi: 994 + person_id: 1 + person2: + age: 8 + ssi: 0 + person_id: 2 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child: + members: [person2] + spm_units: + unit: + members: [person1, person2] + wi_works_income_eligible: true + wi_works_resources_eligible: true + households: + household: + members: [person1, person2] + state_code: WI + output: + wi_works_eligible: false + +- name: Case 8, Child SSI does not exclude a non-SSI W-2 parent. + period: 2026-01 + input: + people: + person1: + age: 35 + ssi: 0 + person_id: 1 + person2: + age: 8 + ssi: 994 + person_id: 2 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child: + members: [person2] + spm_units: + unit: + members: [person1, person2] + wi_works_income_eligible: true + wi_works_resources_eligible: true + households: + household: + members: [person1, person2] + state_code: WI + output: + wi_works_eligible: true + +- name: Case 9, SSI parent does not exclude a non-SSI co-parent from W-2. + period: 2026-01 + input: + people: + person1: + age: 35 + ssi: 994 + person_id: 1 + person2: + age: 8 + ssi: 0 + person_id: 2 + parent_1_id: 1 + parent_2_id: 3 + person3: + person_id: 3 + age: 35 + ssi: 0 + marital_units: + parent: + members: [person1] + child: + members: [person2] + coparent: + members: [person3] + spm_units: + unit: + members: [person1, person2, person3] + wi_works_income_eligible: true + wi_works_resources_eligible: true + households: + household: + members: [person1, person2, person3] + state_code: WI + output: + wi_works_eligible: true + +- name: Case 10, Parent reported to receive SSI cannot receive W-2 even when modeled SSI is zero. + period: 2026-01 + input: + people: + person1: + age: 35 + ssi: 0 + receives_ssi: true + person_id: 1 + person2: + age: 8 + ssi: 0 + person_id: 2 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child: + members: [person2] + spm_units: + unit: + members: [person1, person2] + wi_works_income_eligible: true + wi_works_resources_eligible: true + households: + household: + members: [person1, person2] + state_code: WI + output: + # The only custodial parent receives SSI through receives_ssi. + wi_works_eligible: false + +- name: Case 11, Non-SSI grandparent is not a custodial parent of the SSI mother's child. + period: 2026-01 + input: + people: + person1: + age: 30 + ssi: 994 + person_id: 1 + parent_1_id: 3 + person2: + age: 8 + ssi: 0 + person_id: 2 + parent_1_id: 1 + person3: + age: 58 + ssi: 0 + person_id: 3 + marital_units: + parent: + members: [person1] + child: + members: [person2] + grandparent: + members: [person3] + spm_units: + unit: + members: [person1, person2, person3] + wi_works_income_eligible: true + wi_works_resources_eligible: true + households: + household: + members: [person1, person2, person3] + state_code: WI + output: + # The grandmother is the parent of an adult, not a custodial parent of + # a dependent child; the only custodial parent receives SSI. + wi_works_eligible: false + +- name: Case 12, Without parent IDs a parent on SSI cannot receive W-2. + period: 2026-01 + input: + people: + person1: + age: 30 + is_disabled: true + ssi: 994 + own_children_in_household: 1 + person2: + age: 3 + ssi: 0 + marital_units: + parent: + members: [person1] + child: + members: [person2] + spm_units: + unit: + members: [person1, person2] + wi_works_income_eligible: true + wi_works_resources_eligible: true + households: + household: + members: [person1, person2] + state_code: WI + output: + # No member has a parent ID, as in microsimulation, so every parent + # (own_children_in_household > 0) counts as custodial. The only + # custodial parent receives SSI (Wis. Stat. 49.145(2)(i)). + wi_works_eligible: false + +- name: Case 13, Without parent IDs a parent not on SSI remains W-2 eligible. + period: 2026-01 + input: + people: + person1: + age: 30 + ssi: 0 + own_children_in_household: 1 + person2: + age: 3 + ssi: 0 + marital_units: + parent: + members: [person1] + child: + members: [person2] + spm_units: + unit: + members: [person1, person2] + wi_works_income_eligible: true + wi_works_resources_eligible: true + households: + household: + members: [person1, person2] + state_code: WI + output: + # The same fallback parent does not receive SSI, so the exclusion + # does not apply. + wi_works_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/dhs/ssp/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/dhs/ssp/integration.yaml new file mode 100644 index 00000000000..1ac871013c2 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/dhs/ssp/integration.yaml @@ -0,0 +1,270 @@ +- name: Case 1, eligible couple. + period: 2026-05 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 65 + wi_ssi_e_certified: false + person2: + age: + 2026: 65 + wi_ssi_e_certified: false + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: WI + output: + wi_ssp: [72.63, 72.63] + +- name: Case 2, one eligible spouse. + period: 2026-05 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 65 + wi_ssi_e_certified: false + person2: + age: + 2026: 40 + wi_ssi_e_certified: false + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: WI + output: + wi_ssp: [143.47, 0] + +- name: Case 3, one eligible spouse in another household. + period: 2026-05 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 65 + wi_ssi_e_certified: false + ssi_lives_in_another_persons_household: true + ssi_receives_shelter_from_others_in_household: true + ssi_others_pay_all_meals: true + person2: + age: + 2026: 40 + wi_ssi_e_certified: false + ssi_lives_in_another_persons_household: true + ssi_receives_shelter_from_others_in_household: true + ssi_others_pay_all_meals: true + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: WI + output: + wi_ssp: [148.56, 0] + +- name: Case 4, both spouses certified. + period: 2026-05 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 65 + wi_ssi_e_certified: true + person2: + age: + 2026: 65 + wi_ssi_e_certified: true + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: WI + output: + wi_ssp: [262.58, 262.58] + +- name: Case 5, one spouse certified. + period: 2026-05 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 65 + wi_ssi_e_certified: true + person2: + age: + 2026: 65 + wi_ssi_e_certified: false + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: WI + output: + wi_ssp: [178.22, 72.63] + +- name: Case 6, annual benefits and SNAP income include both rates. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + output: + wi_ssp: 1_072.4 + household_state_benefits: 1_072.4 + snap_unearned_income: 13_000.4 + +- name: Case 7, Caretaker Supplement is included once in annual state and SNAP income. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + meets_ssi_disability_criteria: true + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child: + members: [person2] + families: + unit: + members: [person1, person2] + spm_units: + spm: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [3_300, 0] + wi_ssp: [4_372.4, 0] + snap_unearned_income: 16_300.4 + +- name: Case 8, Wisconsin excludes SSI-E from FoodShare but counts it for HUD. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: WI + age: 65 + wi_ssi_e_certified: true + output: + wi_ssp: 2_301.08 + wi_ssi_e: 1_228.68 + snap_unearned_income: 13_000.4 + hud_unearned_income: 14_229.08 + +- name: Case 9, spouse in a Medicaid nursing home past 90 days leaves the other spouse on the individual rate. + period: 2026-05 + absolute_error_margin: 0.01 + input: + people: + person1: + age: + 2026: 70 + person2: + age: + 2026: 70 + # Medicaid-paid nursing home stay without an authorized continuation. + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + marital_units: + couple: + members: [person1, person2] + tax_units: + unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: + 2026: WI + output: + # One spouse in a medical facility: benefits are computed separately + # (20 CFR 416.414(b)(3)). + ssi_couple_computation_applies: [false, false] + # person1 gets the individual FBR, 994; person2 gets the facility rate, 30. + ssi: [994, 30] + # person2's facility stay excludes them from the state payment. + wi_ssp_eligible: [true, false] + # Both spouses are aged, so neither is an SSI-ineligible spouse; one + # state-eligible spouse without an ineligible spouse gets the individual + # rate, 92.16, not the 143.47 ineligible-spouse rate. + wi_ssp_regular: [92.16, 0] + wi_ssi_e: [0, 0] + wi_cts: [0, 0] + wi_ssp: [92.16, 0] + +- name: Case 10, SPM-unit benefits include SSI, the regular supplement and SSI-E. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: WI + age: 70 + wi_ssi_e_certified: true + # The household does not take up FoodShare, so the benefit total holds + # SSI and the state supplement only. + takes_up_snap_if_eligible: false + output: + # 994 * 12 = 11,928. + ssi: 11_928 + # 4 * 83.78 + 8 * 92.16 = 335.12 + 737.28 = 1,072.40. + wi_ssp_regular: 1_072.4 + # 4 * 95.99 + 8 * 105.59 = 383.96 + 844.72 = 1,228.68. + wi_ssi_e: 1_228.68 + # No children, so no Caretaker Supplement. + wi_cts: 0 + # 1,072.40 + 1,228.68 = 2,301.08. + wi_ssp: 2_301.08 + household_state_benefits: 2_301.08 + # FoodShare counts the regular supplement but not SSI-E: + # 11,928 + 1,072.40 = 13,000.40. + snap_unearned_income: 13_000.4 + snap: 0 + # 11,928 SSI + 2,301.08 state supplement = 14,229.08. + spm_unit_benefits: 14_229.08 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/dhs/ssp/wi_cts.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/dhs/ssp/wi_cts.yaml new file mode 100644 index 00000000000..79ba6e6d362 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/dhs/ssp/wi_cts.yaml @@ -0,0 +1,2189 @@ +- name: Case 1, One non-SSI child receives the first-child amount. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [275, 0] + +- name: Case 2, Three eligible children use first and subsequent rates. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + person3: + age: 9 + person_id: 3 + parent_1_id: 1 + person4: + age: 10 + person_id: 4 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + child1: + members: [person3] + child2: + members: [person4] + families: + unit: + members: [person1, person2, person3, person4] + households: + home: + members: [person1, person2, person3, person4] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [605, 0, 0, 0] + +- name: Case 3, A child receiving SSI is excluded. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + ssi: 100 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [0, 0] + +- name: Case 4, SSDI alone does not make the parent eligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 0 + social_security_disability: 12_000 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [0, 0] + +- name: Case 5, Parent reported to receive SSI with modeled SSI of zero can qualify. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + is_disabled: true + ssi: 0 + receives_ssi: true + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + # receives_ssi makes the parent wi_ssp_eligible; alone in the + # marital unit, the parent gets the January 2026 individual rate of $83.78. + wi_ssp_regular: [83.78, 0] + # wi_ssp_regular > 0, so the parent is a CTS parent: one child = $275. + wi_cts: [275, 0] + +- name: Case 6, Age 18 needs graduation certification. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 18 + person_id: 2 + parent_1_id: 1 + is_in_secondary_school: true + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [0, 0] + +- name: Case 7, Age 18 enrolled and graduating before 19. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 18 + person_id: 2 + parent_1_id: 1 + is_in_secondary_school: true + wi_cts_graduates_before_19: true + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [275, 0] + +- name: Case 8, Age 19 is ineligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 19 + person_id: 2 + parent_1_id: 1 + is_in_secondary_school: true + wi_cts_graduates_before_19: true + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [0, 0] + +- name: Case 9, Child support is excluded from both tests. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + child_support_received: 24_000 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [275, 0] + +- name: Case 10, Income at the Area I net limit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + social_security_survivors: 3_732 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [275, 0] + +- name: Case 11, Income above the Area I net limit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + social_security_survivors: 3_744 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [0, 0] + +- name: Case 12, Income between the Area II and Area I net limits fails in Area II. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + social_security_survivors: 3_660 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: ADAMS_COUNTY_WI + output: + wi_cts: [0, 0] + +- name: Case 13, Income and resources belonging to SSI people are excluded. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + # 20 hours a week at the $7.25 minimum wage: 7.25 * 20 * 52 = 7,540, + # or 628.33 a month. SSI countable earnings = (628.33 - 20 - 65) / 2 + # = 271.67, so SSI = 994 - 271.67 = 722.33. + ssi: 722.33 + employment_income: 7_540 + # Below the $2,000 SSI resource limit, above the $1,000 CTS limit. + ssi_countable_resources: 1_500 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + # The SSI parent is outside the group, so the $628.33 of monthly wages + # (above the $311 size-1 net limit) and $1,500 of resources (above the + # $1,000 limit) are not counted: the child alone has $0, so $275. + wi_cts: [275, 0] + +- name: Case 14, Non-SSI resources at the limit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + bank_account_assets: 1_000 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [275, 0] + +- name: Case 15, Non-SSI resources above the limit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + bank_account_assets: 1_001 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [0, 0] + +- name: Case 16, New applicant earnings receive the 90 dollar work deduction. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 16 + person_id: 2 + parent_1_id: 1 + employment_income: 4_812 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + # 4,812 / 12 = 401 a month; gross 401 <= 576 (size 1, Area I); + # net 401 - 90 = 311 <= 311 net limit (threshold edge), so $275. + wi_cts: [275, 0] + +- name: Case 17, New applicant just above net earnings limit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 16 + person_id: 2 + parent_1_id: 1 + employment_income: 4_824 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + # 4,824 / 12 = 402 a month; net 402 - 90 = 312 > 311 (threshold edge). + wi_cts: [0, 0] + +- name: Case 18, Continuing minor full-time student earnings are exempt only in net test. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 16 + person_id: 2 + parent_1_id: 1 + employment_income: 6_912 + is_full_time_student: true + wi_cts_received_recently: true + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + # 6,912 / 12 = 576 a month; gross 576 <= 576 (threshold edge); a + # continuing full-time student's earnings are exempt in the net + # test, so net 0 <= 311 and the benefit is $275. + wi_cts: [275, 0] + +- name: Case 19, Continuing student fails gross test despite net exemption. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 16 + person_id: 2 + parent_1_id: 1 + employment_income: 6_924 + is_full_time_student: true + wi_cts_received_recently: true + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + # 6,924 / 12 = 577 a month > 576 gross limit (threshold edge). + wi_cts: [0, 0] + +- name: Case 20, Continuing nonschool minor receives 30 and one-third deduction. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 17 + person_id: 2 + parent_1_id: 1 + employment_income: 6_840 + wi_cts_received_recently: true + is_full_time_student: false + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + # 6,840 / 12 = 570 a month; gross 570 <= 576; a continuing minor + # not in school gets $90, $30 and one-third: + # (570 - 90 - 30) * 2 / 3 = 300 <= 311, so $275. + wi_cts: [275, 0] + +- name: Case 21, Two co-resident parents must both receive state SSI. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + parent_2_id: 20 + person3: + age: 40 + person_id: 20 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + other: + members: [person3] + families: + unit: + members: [person1, person2, person3] + households: + home: + members: [person1, person2, person3] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [0, 0, 0] + +- name: Case 22, Two unmarried SSI parents tie on one child, so the lower person_id parent is the caretaker. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + parent_2_id: 20 + person3: + age: 40 + person_id: 20 + ssi: 994 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + other: + members: [person3] + families: + unit: + members: [person1, person2, person3] + households: + home: + members: [person1, person2, person3] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [275, 0, 0] + +- name: Case 23, Outside Wisconsin. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: IL + county: DANE_COUNTY_WI + output: + wi_cts: [0, 0] + +- name: Case 24, Undocumented child. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + immigration_status: UNDOCUMENTED + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [0, 0] + +- name: Case 25, Permanent resident child is not subject to SSI five-year rules. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + immigration_status: LEGAL_PERMANENT_RESIDENT + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [275, 0] + +- name: Case 26, Handbook Buening example with co-parent income 700. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 10 + person_id: 2 + parent_1_id: 1 + social_security_survivors: 0 + person3: + age: 8 + person_id: 3 + parent_1_id: 1 + parent_2_id: 20 + person4: + age: 40 + person_id: 20 + unemployment_compensation: 8_400 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + child1: + members: [person3] + other: + members: [person4] + families: + unit: + members: [person1, person2, person3, person4] + households: + home: + members: [person1, person2, person3, person4] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [275, 0, 0, 0] + +- name: Case 27, Handbook Buening example with co-parent income 500. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 10 + person_id: 2 + parent_1_id: 1 + social_security_survivors: 2_400 + person3: + age: 8 + person_id: 3 + parent_1_id: 1 + parent_2_id: 20 + person4: + age: 40 + person_id: 20 + unemployment_compensation: 6_000 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + child1: + members: [person3] + other: + members: [person4] + families: + unit: + members: [person1, person2, person3, person4] + households: + home: + members: [person1, person2, person3, person4] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [0, 0, 0, 0] + +- name: Case 28, Dependent care paid for a sibling reduces the whole group net income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 16 + person_id: 2 + parent_1_id: 1 + employment_income: 8_400 + person3: + age: 9 + person_id: 3 + parent_1_id: 1 + pre_subsidy_childcare_expenses: 2_400 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + child1: + members: [person3] + families: + unit: + members: [person1, person2, person3] + households: + home: + members: [person1, person2, person3] + state_code: WI + county: DANE_COUNTY_WI + output: + # Teen earns 8,400 / 12 = 700 a month: gross 700 <= 1,018 (size 2). + # Net 700 - 90 = 610; the 9-year-old's care 2,400 / 12 = 200 is capped + # at $175, so 610 - 175 = 435 <= 550 and two children get 275 + 165. + wi_cts: [440, 0, 0] + +- name: Case 29, Child-support noncooperation excludes the entire family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + wi_cts_nonfinancially_ineligible: true + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [0, 0] + +- name: Case 30, Annual CTS resource balance above the limit remains ineligible. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + bank_account_assets: 1_001 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [0, 0] + +- name: Case 31, Large CTS group requires a verified net income limit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + person3: + age: 9 + person_id: 3 + parent_1_id: 1 + person4: + age: 10 + person_id: 4 + parent_1_id: 1 + person5: + age: 11 + person_id: 5 + parent_1_id: 1 + person6: + age: 12 + person_id: 6 + parent_1_id: 1 + person7: + age: 13 + person_id: 7 + parent_1_id: 1 + person8: + age: 14 + person_id: 8 + parent_1_id: 1 + person9: + age: 15 + person_id: 9 + parent_1_id: 1 + person10: + age: 8 + person_id: 10 + parent_1_id: 1 + person11: + age: 9 + person_id: 11 + parent_1_id: 1 + person12: + age: 10 + person_id: 12 + parent_1_id: 1 + person13: + age: 11 + person_id: 13 + parent_1_id: 1 + person14: + age: 12 + person_id: 14 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + child1: + members: [person3] + child2: + members: [person4] + child3: + members: [person5] + child4: + members: [person6] + child5: + members: [person7] + child6: + members: [person8] + child7: + members: [person9] + child8: + members: [person10] + child9: + members: [person11] + child10: + members: [person12] + child11: + members: [person13] + child12: + members: [person14] + families: + unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] + households: + home: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + +- name: Case 32, Agency-verified CTS limit supports a thirteen-child group. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + person3: + age: 9 + person_id: 3 + parent_1_id: 1 + person4: + age: 10 + person_id: 4 + parent_1_id: 1 + person5: + age: 11 + person_id: 5 + parent_1_id: 1 + person6: + age: 12 + person_id: 6 + parent_1_id: 1 + person7: + age: 13 + person_id: 7 + parent_1_id: 1 + person8: + age: 14 + person_id: 8 + parent_1_id: 1 + person9: + age: 15 + person_id: 9 + parent_1_id: 1 + person10: + age: 8 + person_id: 10 + parent_1_id: 1 + person11: + age: 9 + person_id: 11 + parent_1_id: 1 + person12: + age: 10 + person_id: 12 + parent_1_id: 1 + person13: + age: 11 + person_id: 13 + parent_1_id: 1 + person14: + age: 12 + person_id: 14 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + child1: + members: [person3] + child2: + members: [person4] + child3: + members: [person5] + child4: + members: [person6] + child5: + members: [person7] + child6: + members: [person8] + child7: + members: [person9] + child8: + members: [person10] + child9: + members: [person11] + child10: + members: [person12] + child11: + members: [person13] + child12: + members: [person14] + families: + unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] + wi_cts_large_group_net_income_limit: 1_254 + households: + home: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11, person12, person13, person14] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts: [2_255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + +- name: Case 33, Handbook Scenario 4 unmarried SSI caretakers with own children and a child in common. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + person_id: 1 + ssi: 994 + person2: + age: 36 + person_id: 2 + ssi: 994 + person3: + age: 12 + person_id: 3 + parent_1_id: 1 + person4: + age: 6 + person_id: 4 + parent_1_id: 1 + parent_2_id: 2 + person5: + age: 10 + person_id: 5 + parent_1_id: 2 + marital_units: + parent: + members: [person1] + other: + members: [person2] + child0: + members: [person3] + child1: + members: [person4] + child2: + members: [person5] + families: + unit: + members: [person1, person2, person3, person4, person5] + households: + home: + members: [person1, person2, person3, person4, person5] + state_code: WI + county: DANE_COUNTY_WI + output: + # The child in common links all three children into one filing unit + # (size 3, no income). Each caretaker has two eligible children, so the + # child in common goes to the lower person_id: person1 cares for + # persons 3 and 4, person2 for person 5. + wi_cts_caretaker_children: [2, 1, 0, 0, 0] + # Handbook Scenario 4: 275 + 165 = 440 to person1 and 275 to person2, + # 715 in total. + wi_cts: [440, 275, 0, 0, 0] + +- name: Case 34, Handbook Scenario 5 married SSI caretakers with own children and a child in common. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + person_id: 1 + # SSI couple: 1,491 / 2 = 745.50 each. + ssi: 745.5 + person2: + age: 36 + person_id: 2 + ssi: 745.5 + person3: + age: 12 + person_id: 3 + parent_1_id: 1 + person4: + age: 6 + person_id: 4 + parent_1_id: 1 + parent_2_id: 2 + person5: + age: 10 + person_id: 5 + parent_1_id: 2 + marital_units: + parents: + members: [person1, person2] + child0: + members: [person3] + child1: + members: [person4] + child2: + members: [person5] + families: + unit: + members: [person1, person2, person3, person4, person5] + households: + home: + members: [person1, person2, person3, person4, person5] + state_code: WI + county: DANE_COUNTY_WI + output: + # Marriage does not change the groups: two children each, the tie goes + # to the lower person_id. + wi_cts_caretaker_children: [2, 1, 0, 0, 0] + # Handbook Scenario 5: 275 + 165 = 440 and 275, 715 in total. + wi_cts: [440, 275, 0, 0, 0] + +- name: Case 35, Tie for a child in common goes to the lower person ID whatever the member order. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 36 + person_id: 2 + ssi: 994 + person2: + age: 38 + person_id: 1 + ssi: 994 + person3: + age: 6 + person_id: 4 + parent_1_id: 2 + parent_2_id: 1 + person4: + age: 10 + person_id: 5 + parent_1_id: 2 + person5: + age: 12 + person_id: 3 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + other: + members: [person2] + child0: + members: [person3] + child1: + members: [person4] + child2: + members: [person5] + families: + unit: + members: [person1, person2, person3, person4, person5] + households: + home: + members: [person1, person2, person3, person4, person5] + state_code: WI + county: DANE_COUNTY_WI + output: + # Case 33 with the rows and parent slots reversed: each caretaker has + # two eligible children, and person2 (person_id 1) is listed second and + # in the child's second parent slot, yet still takes the child in common. + wi_cts_caretaker_children: [1, 2, 0, 0, 0] + # 275 to person1; 275 + 165 = 440 to person2. + wi_cts: [275, 440, 0, 0, 0] + +- name: Case 36, Handbook Scenario 7 married parents whose only child in common receives SSI. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + person_id: 1 + ssi: 745.5 + person2: + age: 36 + person_id: 2 + ssi: 745.5 + person3: + age: 12 + person_id: 3 + parent_1_id: 1 + person4: + age: 6 + person_id: 4 + parent_1_id: 1 + parent_2_id: 2 + is_disabled: true + ssi: 994 + person5: + age: 10 + person_id: 5 + parent_1_id: 2 + marital_units: + parents: + members: [person1, person2] + child0: + members: [person3] + child1: + members: [person4] + child2: + members: [person5] + families: + unit: + members: [person1, person2, person3, person4, person5] + households: + home: + members: [person1, person2, person3, person4, person5] + state_code: WI + county: DANE_COUNTY_WI + output: + # The SSI child breaks the link, so persons 3 and 5 form two separate + # one-child filing units and the SSI child is in neither. + wi_cts_sfu_member: [false, false, true, false, true] + wi_cts_caretaker_children: [1, 1, 0, 0, 0] + # Handbook Scenario 7: two payments of $275. + wi_cts: [275, 275, 0, 0, 0] + +- name: Case 37, Handbook Scenario 8 unmarried parents whose only child in common receives SSI. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + person_id: 1 + ssi: 994 + person2: + age: 36 + person_id: 2 + ssi: 994 + person3: + age: 12 + person_id: 3 + parent_1_id: 1 + person4: + age: 6 + person_id: 4 + parent_1_id: 1 + parent_2_id: 2 + is_disabled: true + ssi: 994 + person5: + age: 10 + person_id: 5 + parent_1_id: 2 + marital_units: + parent: + members: [person1] + other: + members: [person2] + child0: + members: [person3] + child1: + members: [person4] + child2: + members: [person5] + families: + unit: + members: [person1, person2, person3, person4, person5] + households: + home: + members: [person1, person2, person3, person4, person5] + state_code: WI + county: DANE_COUNTY_WI + output: + # Two separate one-child units, one per SSI parent. + wi_cts_caretaker_children: [1, 1, 0, 0, 0] + # Handbook Scenario 8: one $275 payment in each case. + wi_cts: [275, 275, 0, 0, 0] + +- name: Case 38, SSI child in common does not pull the non-SSI co-parent into the filing unit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 16 + person_id: 2 + parent_1_id: 1 + # 16 hours a week at the $7.25 minimum wage: 7.25 * 16 * 52 = 6,032. + employment_income: 6_032 + person3: + age: 42 + person_id: 3 + person4: + age: 4 + person_id: 4 + parent_1_id: 1 + parent_2_id: 3 + is_disabled: true + ssi: 994 + marital_units: + parent: + members: [person1] + other: + members: [person3] + child0: + members: [person2] + child1: + members: [person4] + families: + unit: + members: [person1, person2, person3, person4] + households: + home: + members: [person1, person2, person3, person4] + state_code: WI + county: DANE_COUNTY_WI + output: + # The partner is linked to the teen only through the SSI child, who + # breaks the link (Handbook 3.3.1), so the teen is tested alone. + wi_cts_sfu_member: [false, true, false, false] + # 6,032 / 12 = 502.67 a month: gross 502.67 <= 576, but net + # 502.67 - 90 = 412.67 > 311 (size 1, Area I), so $0. + wi_cts: [0, 0, 0, 0] + +- name: Case 39, Paroled child of an SSI parent is eligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + immigration_status: PAROLED_ONE_YEAR + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + # Parole under 8 USC 1182(d)(5) is lawful presence under Handbook + # 3.1.4, so the child counts: one child = $275. + wi_cts: [275, 0] + +- name: Case 40, Omitting marital units does not exclude the child. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + # Both people fall into one default marital unit; only + # wi_cts_child_excluded marks a married minor, so one child = $275. + wi_cts: [275, 0] + +- name: Case 41, Pregnancy allowance raises the gross income limit for a pregnant teen. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 17 + person_id: 2 + parent_1_id: 1 + is_pregnant: true + is_full_time_student: true + wi_cts_received_recently: true + # 20 hours a week at the $7.25 minimum wage: 7.25 * 20 * 52 = 7,540. + employment_income: 7_540 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + # 7,540 / 12 = 628.33 a month counts in the gross test. + wi_cts_gross_income: [0, 628.33] + # A continuing full-time student's earnings are exempt in the net test. + wi_cts_net_income: [0, 0] + # Gross 628.33 exceeds the 576 regular limit but not the 707 pregnancy + # limit (size 1, Area I); net 0 <= 311 + 71 = 382, so $275. + wi_cts: [275, 0] + +- name: Case 42, Without parent IDs the family SSI parent receives the award for its children. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 34 + ssi: 994 + own_children_in_household: 2 + person2: + age: 9 + person3: + age: 5 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + child1: + members: [person3] + families: + unit: + members: [person1, person2, person3] + households: + home: + members: [person1, person2, person3] + state_code: WI + county: MILWAUKEE_COUNTY_WI + output: + # No parent links, as in microsimulation: the family is one filing unit, + # its only parent (own_children_in_household) receives SSP, and the + # parent receives the award for both children. + wi_cts_sfu_member: [false, true, true] + wi_cts_caretaker_children: [2, 0, 0] + # 275 + 165 = 440. + wi_cts: [440, 0, 0] + +- name: Case 43, Additional flat disregard alone subtracts 30 dollars after the work expense. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + person_id: 1 + ssi: 994 + person2: + age: 18 + person_id: 2 + parent_1_id: 1 + is_in_secondary_school: true + wi_cts_graduates_before_19: true + wi_cts_additional_flat_disregard: true + # 20 hours a week at the $7.25 minimum wage: 7.25 * 20 * 52 = 7,540. + employment_income: 7_540 + person3: + age: 14 + person_id: 3 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + child1: + members: [person3] + families: + unit: + members: [person1, person2, person3] + households: + home: + members: [person1, person2, person3] + state_code: WI + county: DANE_COUNTY_WI + output: + # The 18-year-old senior is past the one-third months but still gets + # $30: 7,540 / 12 = 628.33; 628.33 - 90 - 30 = 508.33. + wi_cts_net_income: [0, 508.33, 0] + # Size 2: gross 628.33 <= 1,018 and net 508.33 <= 550, so 275 + 165. + wi_cts: [440, 0, 0] + +- name: Case 44, Continuing part-time student working under 30 hours has exempt earnings. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 42 + person_id: 1 + ssi: 994 + person2: + age: 16 + person_id: 2 + parent_1_id: 1 + is_full_time_student: false + wi_cts_part_time_student: true + wi_cts_received_recently: true + weekly_hours_worked: 20 + # 20 hours a week at the $7.25 minimum wage: 7.25 * 20 * 52 = 7,540. + employment_income: 7_540 + person3: + age: 11 + person_id: 3 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + child1: + members: [person3] + families: + unit: + members: [person1, person2, person3] + households: + home: + members: [person1, person2, person3] + state_code: WI + county: DANE_COUNTY_WI + output: + # 7,540 / 12 = 628.33 a month counts in the gross test. + wi_cts_gross_income: [0, 628.33, 0] + # 20 hours < 30, so a continuing part-time student's earnings are exempt. + wi_cts_net_income: [0, 0, 0] + # Size 2: gross 628.33 <= 1,018 and net 0 <= 550, so 275 + 165. + wi_cts: [440, 0, 0] + +- name: Case 45, Infant care deduction is capped at 200 dollars in an Area II county. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 38 + person_id: 1 + ssi: 994 + person2: + age: 17 + person_id: 2 + parent_1_id: 1 + # 20 hours a week at the $7.25 minimum wage: 7.25 * 20 * 52 = 7,540. + employment_income: 7_540 + person3: + age: 1 + person_id: 3 + parent_1_id: 1 + # Part-time infant care at $600 a month. + pre_subsidy_childcare_expenses: 7_200 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + child1: + members: [person3] + families: + unit: + members: [person1, person2, person3] + households: + home: + members: [person1, person2, person3] + state_code: WI + county: WOOD_COUNTY_WI + output: + # 7,200 / 12 = 600 a month, capped at $200 for a child under 2. + wi_cts_dependent_care_deduction: [0, 0, 200] + # New applicant teen: 7,540 / 12 = 628.33; 628.33 - 90 = 538.33. + wi_cts_net_income: [0, 538.33, 0] + # Area II size 2: gross 628.33 <= 987; net 538.33 - 200 = 338.33 <= 533, + # so 275 + 165 = 440. + wi_cts: [440, 0, 0] + +- name: Case 46, Child support the co-parent pays outside the home lowers the Buening group net income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 10 + person_id: 2 + parent_1_id: 1 + social_security_survivors: 2_400 + person3: + age: 8 + person_id: 3 + parent_1_id: 1 + parent_2_id: 20 + person4: + age: 40 + person_id: 20 + unemployment_compensation: 6_000 + # $85 a month for a child living elsewhere: 17% of his $500, the + # Wisconsin one-child percentage standard. + child_support_expense: 1_020 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + child1: + members: [person3] + other: + members: [person4] + families: + unit: + members: [person1, person2, person3, person4] + households: + home: + members: [person1, person2, person3, person4] + state_code: WI + county: DANE_COUNTY_WI + output: + # Handbook 3.3.1 Example 2 (Case 27) plus the support Dan pays. + # Tim and Dan: gross 500 <= 1,018; net 500 - 85 = 415 <= 550, so they + # stay in the group. Group of 3: gross 200 + 500 = 700 <= 1,197; net + # 700 - 85 = 615 <= 647, so Mary gets $275 for Jill. + wi_cts: [275, 0, 0, 0] + +- name: Case 47, Incarcerated child of an SSI parent is not eligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 16 + person_id: 2 + parent_1_id: 1 + is_incarcerated: true + marital_units: + parent: + members: [person1] + child0: + members: [person2] + families: + unit: + members: [person1, person2] + households: + home: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + output: + # Handbook 3.1.6: a person incarcerated in jail or prison is not in a + # CTS qualified living arrangement. Without is_incarcerated the parent + # would receive $275 for this child, as in Case 1. + wi_cts_child_eligible: [false, false] + wi_cts: [0, 0] + # The parent keeps the January 2026 individual rate only. + wi_ssp: [83.78, 0] + +- name: Case 48, Additional one-third disregard input gives an 18-year-old senior 30 dollars and one-third. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + person_id: 1 + ssi: 994 + person2: + age: 18 + person_id: 2 + parent_1_id: 1 + is_in_secondary_school: true + wi_cts_graduates_before_19: true + wi_cts_additional_fraction_disregard: true + # 20 hours a week at the $7.25 minimum wage: 7.25 * 20 * 52 = 7,540. + employment_income: 7_540 + person3: + age: 14 + person_id: 3 + parent_1_id: 1 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + child1: + members: [person3] + families: + unit: + members: [person1, person2, person3] + households: + home: + members: [person1, person2, person3] + state_code: WI + county: DANE_COUNTY_WI + output: + # An 18-year-old is not a continuing minor, so only the input applies + # $30 and one-third: 7,540 / 12 = 628.33; + # (628.33 - 90 - 30) * (1 - 1/3) = 508.33 * 2 / 3 = 338.89. + wi_cts_net_income: [0, 338.89, 0] + # Size 2: gross 628.33 <= 1,018 and net 338.89 <= 550, so 275 + 165. + wi_cts: [440, 0, 0] + # 83.78 + 440 = 523.78. + wi_ssp: [523.78, 0, 0] + +- name: Case 49, Dependent care deduction cannot reduce unearned income when no one in the group works. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 10 + person_id: 2 + parent_1_id: 1 + # 600 a month. + social_security_survivors: 7_200 + person3: + age: 1 + person_id: 3 + parent_1_id: 1 + # 600 a month. + pre_subsidy_childcare_expenses: 7_200 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + child1: + members: [person3] + families: + unit: + members: [person1, person2, person3] + households: + home: + members: [person1, person2, person3] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts_dependent_care_deduction: [0, 0, 200] + wi_cts_net_income: [0, 600, 0] + # Size 2, Area I: gross 600 <= 1,018. No earned income absorbs the care + # deduction (45 CFR 233.20(a)(11)(i)(D)), so net 600 > 550. + wi_cts: [0, 0, 0] + +- name: Case 50, Tribal Area I input for one household leaves the other household's area unchanged. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 16 + person_id: 2 + parent_1_id: 1 + person3: + age: 40 + person_id: 3 + ssi: 994 + person4: + age: 16 + person_id: 4 + parent_1_id: 3 + marital_units: + parent1: + members: [person1] + child1: + members: [person2] + parent2: + members: [person3] + child2: + members: [person4] + families: + family1: + members: [person1, person2] + family2: + members: [person3, person4] + spm_units: + unit1: + members: [person1, person2] + unit2: + members: [person3, person4] + tax_units: + tax_unit1: + members: [person1, person2] + tax_unit2: + members: [person3, person4] + households: + home1: + members: [person1, person2] + state_code: WI + county: PORTAGE_COUNTY_WI + wi_cts_tribal_area_i: true + home2: + members: [person3, person4] + state_code: WI + county: MILWAUKEE_COUNTY_WI + output: + # Portage is Area II, so home1 needs the tribal input; Milwaukee is an + # Area I county by formula. + wi_cts_area_i: [true, true, true, true] + wi_cts: [275, 0, 275, 0] + +- name: Case 51, Other qualifying status for one child does not reset a citizen sibling or another family. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 10 + person_id: 2 + parent_1_id: 1 + immigration_status: UNDOCUMENTED + wi_cts_other_qualifying_immigration_status: true + person3: + age: 6 + person_id: 3 + parent_1_id: 1 + person4: + age: 40 + person_id: 4 + ssi: 994 + person5: + age: 8 + person_id: 5 + parent_1_id: 4 + marital_units: + parent1: + members: [person1] + child1: + members: [person2] + child2: + members: [person3] + parent2: + members: [person4] + child3: + members: [person5] + families: + family1: + members: [person1, person2, person3] + family2: + members: [person4, person5] + spm_units: + unit1: + members: [person1, person2, person3] + unit2: + members: [person4, person5] + tax_units: + tax_unit1: + members: [person1, person2, person3] + tax_unit2: + members: [person4, person5] + households: + home1: + members: [person1, person2, person3] + state_code: WI + county: DANE_COUNTY_WI + home2: + members: [person4, person5] + state_code: WI + county: DANE_COUNTY_WI + output: + # The enum has no PRUCOL value. This child has approved PRUCOL evidence + # (Handbook 3.1.4 item 4), for example an indefinite stay of + # deportation, so the input makes the child eligible; the citizen + # sibling and the second family keep the formula. + wi_cts_child_eligible: [false, true, true, false, true] + # 275 + 165 = 440 for the first family; 275 for the second. + wi_cts: [440, 0, 0, 275, 0] + +- name: Case 52, Other countable resources for one child do not reset another family's bank balance. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 8 + person_id: 2 + parent_1_id: 1 + wi_cts_other_countable_resources: 500 + person3: + age: 40 + person_id: 3 + ssi: 994 + person4: + age: 8 + person_id: 4 + parent_1_id: 3 + bank_account_assets: 1_500 + marital_units: + parent1: + members: [person1] + child1: + members: [person2] + parent2: + members: [person3] + child2: + members: [person4] + families: + family1: + members: [person1, person2] + family2: + members: [person3, person4] + spm_units: + unit1: + members: [person1, person2] + unit2: + members: [person3, person4] + tax_units: + tax_unit1: + members: [person1, person2] + tax_unit2: + members: [person3, person4] + households: + home1: + members: [person1, person2] + state_code: WI + county: DANE_COUNTY_WI + home2: + members: [person3, person4] + state_code: WI + county: DANE_COUNTY_WI + output: + # 500 <= 1,000 for the first family; the second family's 1,500 bank + # balance still exceeds the 1,000 limit (Handbook 3.2.2). + wi_cts_countable_resources: [0, 500, 0, 1_500] + wi_cts: [275, 0, 0, 0] + +- name: Case 53, Dependent care deduction is limited to the earned income left after the 90 dollar disregard. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + person_id: 1 + ssi: 994 + person2: + age: 17 + person_id: 2 + parent_1_id: 1 + # 5 hours a week at the $7.25 minimum wage: 7.25 * 5 * 52 = 1,885. + employment_income: 1_885 + person3: + age: 1 + person_id: 3 + parent_1_id: 1 + # 600 a month each. + social_security_survivors: 7_200 + pre_subsidy_childcare_expenses: 7_200 + marital_units: + parent: + members: [person1] + child0: + members: [person2] + child1: + members: [person3] + families: + unit: + members: [person1, person2, person3] + households: + home: + members: [person1, person2, person3] + state_code: WI + county: DANE_COUNTY_WI + output: + wi_cts_dependent_care_deduction: [0, 0, 200] + wi_cts_net_income: [0, 67.08, 600] + # 157.08 - 90 = 67.08 earned income is left, so care is capped at 67.08: + # net 67.08 + 600 - 67.08 = 600 > 550. An uncapped $200 would give + # 467.08 and pay 440. + wi_cts: [0, 0, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/dhs/ssp/wi_ssp.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/dhs/ssp/wi_ssp.yaml new file mode 100644 index 00000000000..0cf5e95ac13 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/dhs/ssp/wi_ssp.yaml @@ -0,0 +1,227 @@ +- name: Case 1, January rate. + period: 2026-01 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + output: + wi_ssp: 83.78 + +- name: Case 2, April retains old rate. + period: 2026-04 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + output: + wi_ssp: 83.78 + +- name: Case 3, May new rate. + period: 2026-05 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + output: + wi_ssp: 92.16 + +- name: Case 4, December new rate. + period: 2026-12 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + output: + wi_ssp: 92.16 + +- name: Case 5, annual amount spans rate change. + period: 2026 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + output: + wi_ssp: 1_072.4 + +- name: Case 6, other household retains flat individual rate. + period: 2026-05 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + ssi_lives_in_another_persons_household: true + ssi_receives_shelter_from_others_in_household: true + ssi_others_pay_all_meals: true + output: + wi_ssp: 92.16 + +- name: Case 7, small SSI payment gets full state amount. + period: 2026-05 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + # Divorced-spouse benefit at SSA's August 2026 average for spouses of retired + # workers, $986.70 a month (Monthly Statistical Snapshot, Table 2): + # 986.70 * 12 = 11,840.40. + social_security_dependents: + 2026: 11_840.4 + output: + # SSI = 994 - (986.70 - 20) = 27.30. + ssi: 27.3 + # Any federal SSI payment brings the full individual rate. + wi_ssp: 92.16 + +- name: Case 8, no federal payment no new state eligibility. + period: 2026-05 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + # SSA's August 2026 average retired-worker benefit, $2,087.52 a month + # (Monthly Statistical Snapshot, Table 2): 2,087.52 * 12 = 25,050.24. + social_security_retirement: + 2026: 25_050.24 + output: + # Countable 2,087.52 - 20 = 2,067.52 exceeds the 994 FBR, so SSI is 0. + ssi: 0 + wi_ssp: 0 + +- name: Case 9, certified exceptional expense supplement before increase. + period: 2026-04 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + wi_ssi_e_certified: true + output: + wi_ssp: 179.77 + +- name: Case 10, certified exceptional expense supplement after increase. + period: 2026-05 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + wi_ssi_e_certified: true + output: + wi_ssp: 197.75 + +- name: Case 11, long term medical institution excluded. + period: 2026-05 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + output: + wi_ssp: 0 + +- name: Case 12, authorized institutional continuation. + period: 2026-05 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + wi_ssp_institutional_continuation: true + output: + wi_ssp: 92.16 + +- name: Case 13, incarceration excludes payment. + period: 2026-05 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + is_incarcerated: true + output: + wi_ssp: 0 + +- name: Case 14, outside Wisconsin. + period: 2026-05 + absolute_error_margin: 0.01 + input: + state_code: + 2026: MN + age: + 2026: 65 + output: + wi_ssp: 0 + +- name: Case 15, excess resources. + period: 2026-05 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + ssi_countable_resources: + 2026: 2_001 + output: + wi_ssp: 0 + +- name: Case 16, reported SSI receipt qualifies when modeled SSI is zero. + period: 2026-05 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + # No aged, blind or disability input, so the model computes no SSI. + age: + 2026: 45 + receives_ssi: true + output: + ssi: 0 + wi_ssp_eligible: true + # Individual rate from May 2026. + wi_ssp: 92.16 + +- name: Case 17, certified SSI-E recipient in the household of another gets no SSI-E. + period: 2026-05 + absolute_error_margin: 0.01 + input: + state_code: + 2026: WI + age: + 2026: 65 + ssi_lives_in_another_persons_household: true + ssi_receives_shelter_from_others_in_household: true + ssi_others_pay_all_meals: true + wi_ssi_e_certified: true + output: + # One-third reduction: 994 * (1 - 1/3) = 662.67. + ssi: 662.67 + # P-20679 3.1.1: the household-of-another arrangement bars SSI-E. + wi_ssi_e: 0 + # Regular individual rate only. + wi_ssp: 92.16 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wi/dhs/ssp/wi_ssp_countable_for_hud.yaml b/policyengine_us/tests/policy/baseline/gov/states/wi/dhs/ssp/wi_ssp_countable_for_hud.yaml new file mode 100644 index 00000000000..93fab22cf17 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wi/dhs/ssp/wi_ssp_countable_for_hud.yaml @@ -0,0 +1,693 @@ +# HUD PIH 2023-27 G.11 and PIH 2024-38 IV.B.1 exclude qualifying assisted-home care. +# wi_ssi_e_for_home_care is true when the SSI-E pays an assisted-family member's care that enables continued residence. +# Annual SSI-E = 4*95.99 + 8*105.59 = 1228.68; regular SSI remains counted. +# https://www.hud.gov/sites/dfiles/OCHCO/documents/2023-27pihn.pdf#page=81 +- name: Case 1, SSI-E paying an adult child in the assisted unit for home care is excluded. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + person_id: 1 + is_disabled: true + meets_ssi_disability_criteria: true + is_household_head: true + pre_subsidy_rent: 12_000 + wi_ssi_e_certified: true + wi_ssi_e_for_home_care: true + person2: + age: 30 + person_id: 2 + parent_1_id: 1 + is_household_head: false + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + families: + family1: + members: [person1] + family2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + spm_units: + unit: + members: [person1, person2] + receives_housing_assistance: true + households: + home: + members: [person1, person2] + state_code: WI + county_fips: '55079' + bedrooms: 2 + tenant_pays_utilities: false + output: + wi_ssi_e: [1_228.68, 0] + wi_ssp_countable_for_hud: [1_072.4, 0] + hud_annual_income: 13_000.4 + housing_assistance: 8_264.88 + +- name: Case 2, default unverified home-care qualification keeps SSI-E countable. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + person_id: 1 + is_disabled: true + meets_ssi_disability_criteria: true + is_household_head: true + pre_subsidy_rent: 12_000 + wi_ssi_e_certified: true + wi_ssi_e_for_home_care: false + person2: + age: 30 + person_id: 2 + parent_1_id: 1 + is_household_head: false + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + families: + family1: + members: [person1] + family2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + spm_units: + unit: + members: [person1, person2] + receives_housing_assistance: true + households: + home: + members: [person1, person2] + state_code: WI + county_fips: '55079' + bedrooms: 2 + tenant_pays_utilities: false + output: + wi_ssp_countable_for_hud: [2_301.08, 0] + hud_annual_income: 14_229.08 + housing_assistance: 7_896.28 + +- name: Case 3, blindness establishes the HUD disability for the home-care exclusion. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + person_id: 1 + is_blind: true + is_household_head: true + pre_subsidy_rent: 12_000 + wi_ssi_e_certified: true + wi_ssi_e_for_home_care: true + person2: + age: 30 + person_id: 2 + parent_1_id: 1 + is_household_head: false + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + families: + family1: + members: [person1] + family2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + spm_units: + unit: + members: [person1, person2] + receives_housing_assistance: true + households: + home: + members: [person1, person2] + state_code: WI + county_fips: '55079' + bedrooms: 2 + tenant_pays_utilities: false + output: + # Blindness passes the HUD disability test: 2,301.08 - 1,228.68 SSI-E = 1,072.40. + wi_ssp_countable_for_hud: [1_072.4, 0] + +- name: Case 4, Social Security disability benefits establish the HUD disability for an aged recipient. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + # Aged SSI recipient still on SSDI before full retirement age. + age: 66 + person_id: 1 + is_household_head: true + pre_subsidy_rent: 12_000 + # Wisconsin average Social Security benefit of disabled workers who also + # receive SSI, $698.90 a month (SSA SSI Annual Statistical Report 2024, + # Table 16): 698.90 * 12 = 8,386.80. + social_security_disability: 8_386.8 + wi_ssi_e_certified: true + wi_ssi_e_for_home_care: true + person2: + age: 30 + person_id: 2 + parent_1_id: 1 + is_household_head: false + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + families: + family1: + members: [person1] + family2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + spm_units: + unit: + members: [person1, person2] + receives_housing_assistance: true + households: + home: + members: [person1, person2] + state_code: WI + county_fips: '55079' + bedrooms: 2 + tenant_pays_utilities: false + output: + # SSI = 994 - (698.90 - 20) = 315.10 a month; 315.10 * 12 = 3,781.20. + ssi: [3_781.2, 0] + # SSDI receipt passes the HUD disability test: 2,301.08 - 1,228.68 = 1,072.40. + wi_ssp_countable_for_hud: [1_072.4, 0] + +- name: Case 5, age-only eligibility does not establish the HUD disability exclusion. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 65 + person_id: 1 + is_disabled: false + meets_ssi_disability_criteria: false + is_household_head: true + pre_subsidy_rent: 12_000 + wi_ssi_e_certified: true + wi_ssi_e_for_home_care: true + person2: + age: 30 + person_id: 2 + parent_1_id: 1 + is_household_head: false + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + families: + family1: + members: [person1] + family2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + spm_units: + unit: + members: [person1, person2] + receives_housing_assistance: true + households: + home: + members: [person1, person2] + state_code: WI + county_fips: '55079' + bedrooms: 2 + tenant_pays_utilities: false + output: + wi_ssp_countable_for_hud: [2_301.08, 0] + +- name: Case 6, care by a co-resident outside the assisted SPM unit keeps SSI-E countable. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + person_id: 1 + is_disabled: true + meets_ssi_disability_criteria: true + is_household_head: true + pre_subsidy_rent: 12_000 + wi_ssi_e_certified: true + # The caregiver is not a member of the assisted family. + wi_ssi_e_for_home_care: false + person2: + age: 30 + person_id: 2 + parent_1_id: 1 + is_household_head: false + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + families: + family1: + members: [person1] + family2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + spm_units: + unit1: + members: [person1] + receives_housing_assistance: true + unit2: + members: [person2] + households: + home: + members: [person1, person2] + state_code: WI + county_fips: '55079' + bedrooms: 2 + tenant_pays_utilities: false + output: + wi_ssp_countable_for_hud: [2_301.08, 0] + +- name: Case 7, care by an adult child living in another household keeps SSI-E countable. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + person_id: 1 + is_disabled: true + meets_ssi_disability_criteria: true + is_household_head: true + pre_subsidy_rent: 12_000 + wi_ssi_e_certified: true + # The caregiver lives outside the assisted unit. + wi_ssi_e_for_home_care: false + person2: + age: 30 + person_id: 2 + parent_1_id: 1 + is_household_head: false + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + families: + family1: + members: [person1] + family2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + spm_units: + unit: + members: [person1] + receives_housing_assistance: true + other: + members: [person2] + households: + home: + members: [person1] + state_code: WI + county_fips: '55079' + bedrooms: 2 + tenant_pays_utilities: false + other: + members: [person2] + state_code: WI + county_fips: '55079' + output: + wi_ssp_countable_for_hud: [2_301.08, 0] + +- name: Case 8, a medical-facility month keeps continued SSI-E countable. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + person_id: 1 + is_disabled: true + meets_ssi_disability_criteria: true + is_household_head: true + pre_subsidy_rent: 12_000 + wi_ssi_e_certified: true + wi_ssi_e_for_home_care: true + ssi_lives_in_medical_treatment_facility: + 2026-05: true + ssi_medicaid_pays_majority_of_care: + 2026-05: true + wi_ssp_institutional_continuation: + 2026-05: true + person2: + age: 30 + person_id: 2 + parent_1_id: 1 + is_household_head: false + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + families: + family1: + members: [person1] + family2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + spm_units: + unit: + members: [person1, person2] + receives_housing_assistance: true + households: + home: + members: [person1, person2] + state_code: WI + county_fips: '55079' + bedrooms: 2 + tenant_pays_utilities: false + output: + wi_ssi_e: + 2026-05: [105.59, 0] + wi_ssp_countable_for_hud: + 2026-05: [197.75, 0] + +- name: Case 9, the home-care exclusion holds across the May rate change. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + person_id: 1 + is_disabled: true + meets_ssi_disability_criteria: true + is_household_head: true + pre_subsidy_rent: 12_000 + wi_ssi_e_certified: true + wi_ssi_e_for_home_care: true + person2: + age: 30 + person_id: 2 + parent_1_id: 1 + is_household_head: false + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + families: + family1: + members: [person1] + family2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + spm_units: + unit: + members: [person1, person2] + receives_housing_assistance: true + households: + home: + members: [person1, person2] + state_code: WI + county_fips: '55079' + bedrooms: 2 + tenant_pays_utilities: false + output: + wi_ssp_countable_for_hud: + 2026-04: [83.78, 0] + 2026-05: [92.16, 0] + +- name: Case 10, home-care inputs cannot exclude regular SSI when no SSI-E is awarded. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + person_id: 1 + is_disabled: true + meets_ssi_disability_criteria: true + is_household_head: true + pre_subsidy_rent: 12_000 + wi_ssi_e_certified: false + wi_ssi_e_for_home_care: true + person2: + age: 30 + person_id: 2 + parent_1_id: 1 + is_household_head: false + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + families: + family1: + members: [person1] + family2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + spm_units: + unit: + members: [person1, person2] + receives_housing_assistance: true + households: + home: + members: [person1, person2] + state_code: WI + county_fips: '55079' + bedrooms: 2 + tenant_pays_utilities: false + output: + wi_ssi_e: [0, 0] + wi_ssp_countable_for_hud: [1_072.4, 0] + +- name: Case 11, with two adult children in the assisted unit only the recipient's SSI-E is excluded. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + person_id: 1 + is_disabled: true + meets_ssi_disability_criteria: true + is_household_head: true + pre_subsidy_rent: 12_000 + wi_ssi_e_certified: true + wi_ssi_e_for_home_care: true + person2: + age: 30 + person_id: 2 + parent_1_id: 1 + is_household_head: false + person3: + age: 31 + person_id: 3 + parent_1_id: 1 + is_household_head: false + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + third: + members: [person3] + families: + family1: + members: [person1] + family2: + members: [person2] + third: + members: [person3] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + third: + members: [person3] + spm_units: + unit: + members: [person1, person2, person3] + receives_housing_assistance: true + households: + home: + members: [person1, person2, person3] + state_code: WI + county_fips: '55079' + bedrooms: 2 + tenant_pays_utilities: false + output: + # 2,301.08 - 1,228.68 SSI-E = 1,072.40; the adult children have no supplement. + wi_ssp_countable_for_hud: [1_072.4, 0, 0] + +- name: Case 12, qualifying SSI-E exclusion leaves the derived caretaker supplement countable. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + person_id: 1 + is_disabled: true + meets_ssi_disability_criteria: true + is_household_head: true + pre_subsidy_rent: 12_000 + wi_ssi_e_certified: true + wi_ssi_e_for_home_care: true + person2: + age: 30 + person_id: 2 + parent_1_id: 1 + is_household_head: false + person3: + age: 8 + person_id: 3 + parent_1_id: 1 + is_household_head: false + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + child: + members: [person3] + families: + family1: + members: [person1, person3] + family2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + child: + members: [person3] + spm_units: + unit: + members: [person1, person2, person3] + receives_housing_assistance: true + households: + home: + members: [person1, person2, person3] + state_code: WI + county_fips: '55079' + bedrooms: 2 + tenant_pays_utilities: false + output: + wi_cts: [3_300, 0, 0] + wi_ssp_countable_for_hud: [4_372.4, 0, 0] + hud_unearned_income: [16_300.4, 0, 0] + +- name: Case 13, SSI disability criteria alone establish the HUD disability for the home-care exclusion. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + person_id: 1 + # SSI-disabled through the SSI criteria, with no is_disabled input. + meets_ssi_disability_criteria: true + is_household_head: true + pre_subsidy_rent: 12_000 + wi_ssi_e_certified: true + wi_ssi_e_for_home_care: true + person2: + age: 30 + person_id: 2 + parent_1_id: 1 + is_household_head: false + marital_units: + unit1: + members: [person1] + unit2: + members: [person2] + families: + family1: + members: [person1] + family2: + members: [person2] + tax_units: + unit1: + members: [person1] + unit2: + members: [person2] + spm_units: + unit: + members: [person1, person2] + receives_housing_assistance: true + households: + home: + members: [person1, person2] + state_code: WI + county_fips: '55079' + bedrooms: 2 + tenant_pays_utilities: false + output: + # Meets the SSI disability criteria with no earnings, so no SGA. + is_ssi_disabled: [true, false] + # 4 * 95.99 + 8 * 105.59 = 1,228.68. + wi_ssi_e: [1_228.68, 0] + # 1,072.40 regular + 1,228.68 SSI-E - 1,228.68 excluded = 1,072.40. + wi_ssp_countable_for_hud: [1_072.4, 0] + # 994 * 12 = 11,928 SSI + 1,072.40 = 13,000.40. + hud_annual_income: 13_000.4 + # TTP = 0.3 * (13,000.40 - 550 elderly/disabled deduction) = 3,735.12; + # assistance = 12,000 rent - 3,735.12 = 8,264.88. + housing_assistance: 8_264.88 diff --git a/policyengine_us/variables/gov/states/wi/dcf/works/eligibility/wi_works_eligible.py b/policyengine_us/variables/gov/states/wi/dcf/works/eligibility/wi_works_eligible.py index 0f62fc2d6f8..c30c717c431 100644 --- a/policyengine_us/variables/gov/states/wi/dcf/works/eligibility/wi_works_eligible.py +++ b/policyengine_us/variables/gov/states/wi/dcf/works/eligibility/wi_works_eligible.py @@ -1,4 +1,8 @@ from policyengine_us.model_api import * +from policyengine_us.variables.household.demographic.person._parent_links import ( + co_resident_parent_indices, + household_has_parent_ids, +) class wi_works_eligible(Variable): @@ -8,6 +12,7 @@ class wi_works_eligible(Variable): definition_period = MONTH reference = ( "https://docs.legis.wisconsin.gov/statutes/statutes/49/iii/145", + "https://dcf.wisconsin.gov/manuals/w-2-manual/Production/02/2.02.1_List_of_Criteria.htm", "https://docs.legis.wisconsin.gov/code/admin_code/dcf/101_199/101/09", ) defined_for = StateCode.WI @@ -19,4 +24,33 @@ def formula(spm_unit, period, parameters): citizenship = spm_unit.any(is_qualified) income = spm_unit("wi_works_income_eligible", period) resources = spm_unit("wi_works_resources_eligible", period) - return demographic & citizenship & income & resources + # Wis. Stat. 49.145(2)(a) and (i): the applicant is a custodial parent + # who does not receive SSI. Grandfathered state-only SSI recipients + # are not modeled. + ssi_recipient = (person("ssi", period) > 0) | person("receives_ssi", period) + dependent_child = person("is_person_demographic_tanf_eligible", period) + unit = spm_unit.members_entity_id + custodial = np.zeros(person.count, dtype=bool) + for parent in co_resident_parent_indices(person, period.this_year): + rows = dependent_child & (parent >= 0) & (unit[parent] == unit) + custodial = custodial | ( + np.bincount(parent[rows], minlength=person.count) > 0 + ) + # Without parent links every parent in the unit counts as custodial. + custodial = where( + household_has_parent_ids(person, period.this_year), + custodial, + person("is_parent", period.this_year), + ) + # SSI receipt excludes the applicant, not an otherwise eligible + # co-parent or a household merely containing a child on SSI. + all_custodial_parents_on_ssi = spm_unit.any( + custodial & ssi_recipient + ) & ~spm_unit.any(custodial & ~ssi_recipient) + return ( + demographic + & citizenship + & income + & resources + & ~all_custodial_parents_on_ssi + ) diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/_wi_cts.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/_wi_cts.py new file mode 100644 index 00000000000..a51f196536b --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/_wi_cts.py @@ -0,0 +1,152 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.household.demographic.person._parent_links import ( + co_resident_parent_indices, + household_has_parent_ids, +) + + +def cts_ssi_recipient(person, period): + return (person("ssi", period) > 0) | person("receives_ssi", period) + + +def cts_relationships(person, period): + first, second = co_resident_parent_indices(person, period.this_year) + linked = household_has_parent_ids(person, period.this_year) + # Handbook 3.1.3: a CTS parent receives the Wisconsin state SSI payment. + # Grandfathered state-only SSI recipients are not modeled. + receipt = person("wi_ssp_regular", period) > 0 + parents = (first >= 0).astype(int) + (second >= 0) + ssi_parents = ((first >= 0) & receipt[first]).astype(int) + ( + (second >= 0) & receipt[second] + ) + # Without parent IDs (as in microsimulation) every is_parent member of the + # family, from own_children_in_household, is a parent of every child: a + # family with any non-SSI parent has no eligible child, and one SSI parent + # receives the whole award. + is_parent = person("is_parent", period.this_year) + parents = where(linked, parents, person.family.sum(is_parent)) + ssi_parents = where(linked, ssi_parents, person.family.sum(is_parent & receipt)) + return first, second, linked, receipt, parents, ssi_parents + + +def cts_unit_sum(unit, values): + """Total of values over each person's filing unit; 0 outside any unit.""" + in_unit = unit >= 0 + totals = np.bincount( + unit[in_unit], + weights=np.asarray(values, dtype=float)[in_unit], + minlength=unit.size, + ) + return where(in_unit, totals[max_(unit, 0)], 0) + + +def _lowest_child_unit(unit, first, second, child, count): + """Lowest unit key among each parent's co-resident children (count if none).""" + lowest = np.full(count, count) + for parent in (first, second): + rows = child & (parent >= 0) + np.minimum.at(lowest, parent[rows], unit[rows]) + return lowest + + +def cts_filing_unit(person, period): + """Each person's standard filing unit key (-1 if none), members and Buening subgroup. + + Handbook 3.1.1 and 3.2.1.2.1 (#page=18, #page=30): non-SSI dependent + children who share a co-resident parent belong to one unit with their + parents, so a unit holds a target child's full and half siblings and + their parents; half-sibling links are followed transitively. An SSI + child does not link its siblings (5.4.1 Scenarios 7 and 8, #page=71). A + unit forms only around a child with an SSI parent. Without parent links + each family is one unit. + """ + first, second, linked, _, _, ssi_parents = cts_relationships(person, period) + count = person.count + index = np.arange(count) + on_ssi = cts_ssi_recipient(person, period) + child = person("wi_cts_dependent_child", period) & ~on_ssi + # Give every child the lowest key reachable through shared parents. + unit = where(child, index, count) + while True: + parent_unit = _lowest_child_unit(unit, first, second, child, count) + joined = unit + for parent in (first, second): + joined = where( + child & (parent >= 0), min_(joined, parent_unit[parent]), joined + ) + if np.array_equal(joined, unit): + break + unit = joined + parent = parent_unit < count + unit = where(child, unit, where(parent, parent_unit, -1)) + unit = where(linked, unit, person.family.min(index)).astype(int) + target = child & (ssi_parents > 0) + unit = where(cts_unit_sum(unit, target) > 0, unit, -1) + parent = where(linked, parent, person("is_parent", period.this_year)) + member = (child | parent) & ~on_ssi & (unit >= 0) + # Handbook 3.3.1 (#page=33): the non-SSI co-parent and the children + # related to them are tested separately under Buening. + co_parent = linked & member & ~child + related = ((first >= 0) & co_parent[first]) | ((second >= 0) & co_parent[second]) + return unit, member, member & (co_parent | related) + + +def cts_financial_test(person, period, parameters, unit, group, large_group_limit): + """Whether each person's unit group passes the income and asset tests. + + Also returns whether the group's net income limit is known: the + published tables end at one size, and a larger group needs a verified + limit (large_group_limit, 0 when none). + """ + p = parameters(period).gov.states.wi.dhs.ssp.cts + size = cts_unit_sum(unit, group) + pregnant = cts_unit_sum(unit, group & person("is_pregnant", period.this_year)) + area_i = person("wi_cts_area_i", period) + gross_limit = where(area_i, p.gross.area_1.calc(size), p.gross.area_2.calc(size)) + pregnancy_gross_limit = where( + area_i, + p.gross_pregnant.area_1.calc(size), + p.gross_pregnant.area_2.calc(size), + ) + # The pregnancy table includes one allowance; each further pregnant + # woman adds another (Handbook 5.2.2). + gross_limit = where( + pregnant > 0, + pregnancy_gross_limit + max_(pregnant - 1, 0) * p.pregnancy_allowance, + gross_limit, + ) + # The gross, pregnancy and net tables all end at the same group size. + table_size = p.net.area_1.thresholds[-1] + gross_limit = gross_limit + max_(size - table_size, 0) * p.gross_additional + published = size <= table_size + net_limit = where( + published, + where(area_i, p.net.area_1.calc(size), p.net.area_2.calc(size)) + + pregnant * p.pregnancy_allowance, + large_group_limit, + ) + income = person("wi_cts_gross_income", period) + gross = cts_unit_sum(unit, group * income) + net_income = person("wi_cts_net_income", period) + # AFDC disregards dependent care from earned income, after the other + # disregards (42 USC 602(a)(8)(A)(iii) as amended in 1988; 45 CFR + # 233.20(a)(11)(i)(D)), so the group's care deduction is capped at its + # earned income left after the $90, $30 and one-third disregards. AFDC + # took the care disregard from each earner's own earned income; the model + # pools the group's remaining earnings because it does not know who pays + # for care. + care = min_( + cts_unit_sum(unit, group * person("wi_cts_dependent_care_deduction", period)), + cts_unit_sum(unit, group * person("wi_cts_countable_earned_income", period)), + ) + support_paid = max_(person("child_support_expense", period), 0) + net = cts_unit_sum(unit, group * (net_income - support_paid)) - care + assets = cts_unit_sum( + unit, group * max_(person("wi_cts_countable_resources", period), 0) + ) + eligible = ( + (gross <= gross_limit) + & (max_(net, 0) <= net_limit) + & (assets <= p.resource_limit) + ) + return eligible, published | (large_group_limit > 0) diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts.py new file mode 100644 index 00000000000..9e737e79905 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts.py @@ -0,0 +1,51 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.wi.dhs.ssp._wi_cts import ( + cts_filing_unit, + cts_financial_test, +) + + +class wi_cts(Variable): + value_type = float + entity = Person + label = "Wisconsin Caretaker Supplement" + definition_period = MONTH + unit = USD + reference = ( + "https://docs.legis.wisconsin.gov/document/statutes/49.775", + # PDF pages 30-34, 65 + "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=30", + ) + defined_for = StateCode.WI + + def formula(person, period, parameters): + p = parameters(period).gov.states.wi.dhs.ssp.cts + unit, _, _ = cts_filing_unit(person, period) + members = person("wi_cts_sfu_member", period) + subgroup = members & person("wi_cts_buening_member", period) + # Buening keeps the co-parent group in the unit only when it is needy. + needy, subgroup_known = cts_financial_test( + person, period, parameters, unit, subgroup, 0 + ) + members = members & ~(subgroup & ~needy) + financially_eligible, known = cts_financial_test( + person, + period, + parameters, + unit, + members, + person.family("wi_cts_large_group_net_income_limit", period), + ) + # Each SSI caretaker's payment covers their own assistance group, and + # the caretaker shares the filing unit of those children. + children = person("wi_cts_caretaker_children", period) + amount = (children > 0) * p.first_child + max_( + children - 1, 0 + ) * p.additional_child + return ( + amount + * financially_eligible + * known + * subgroup_known + * ~person.family("wi_cts_nonfinancially_ineligible", period) + ) diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_additional_flat_disregard.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_additional_flat_disregard.py new file mode 100644 index 00000000000..046b9fdd965 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_additional_flat_disregard.py @@ -0,0 +1,9 @@ +from policyengine_us.model_api import * + + +class wi_cts_additional_flat_disregard(Variable): + value_type = bool + entity = Person + label = "Wisconsin CTS additional flat earnings disregard applies" + definition_period = MONTH + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31" diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_additional_fraction_disregard.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_additional_fraction_disregard.py new file mode 100644 index 00000000000..3653abeeaa3 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_additional_fraction_disregard.py @@ -0,0 +1,9 @@ +from policyengine_us.model_api import * + + +class wi_cts_additional_fraction_disregard(Variable): + value_type = bool + entity = Person + label = "Wisconsin CTS additional one-third earnings disregard applies" + definition_period = MONTH + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31" diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_area_i.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_area_i.py new file mode 100644 index 00000000000..d24fe5465bf --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_area_i.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class wi_cts_area_i(Variable): + value_type = bool + entity = Person + label = "Wisconsin CTS uses Area I income limits" + definition_period = MONTH + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=63" + + def formula(person, period, parameters): + p = parameters(period).gov.states.wi.dhs.ssp.cts + county = person.household("county", period.this_year).decode_to_str() + return np.isin(county, p.area_i_counties) | person.household( + "wi_cts_tribal_area_i", period + ) diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_buening_member.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_buening_member.py new file mode 100644 index 00000000000..2958ed56ea0 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_buening_member.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.wi.dhs.ssp._wi_cts import cts_filing_unit + + +class wi_cts_buening_member(Variable): + value_type = bool + entity = Person + label = "Wisconsin CTS non-SSI co-parent subgroup member" + definition_period = MONTH + # PDF pages 33-34 + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=33" + documentation = "The non-SSI co-parent and children whose needs must be tested separately under Buening. Requires parent IDs." + + def formula(person, period, parameters): + _, _, subgroup = cts_filing_unit(person, period) + return subgroup diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_caretaker_children.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_caretaker_children.py new file mode 100644 index 00000000000..f284c052f60 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_caretaker_children.py @@ -0,0 +1,41 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.wi.dhs.ssp._wi_cts import cts_relationships + + +class wi_cts_caretaker_children(Variable): + value_type = int + entity = Person + label = "Wisconsin CTS eligible children in this SSI parent's assistance group" + definition_period = MONTH + reference = ( + "https://docs.legis.wisconsin.gov/document/statutes/49.775", + # PDF pages 20, 68-71 + "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=20", + ) + documentation = "Each eligible child counts for one co-resident SSI parent. A child in common counts for the parent with more eligible children, and ties go to the lower person_id. Without parent links one SSI parent per family receives the award." + + def formula(person, period, parameters): + first, second, linked, receipt, _, _ = cts_relationships(person, period) + child = person("wi_cts_child_eligible", period) & person( + "wi_cts_sfu_member", period + ) + count = person.count + own_children = np.zeros(count) + for parent in (first, second): + rows = child & (parent >= 0) + own_children = own_children + np.bincount(parent[rows], minlength=count) + # Wis. Stat. 49.775(3) pays once for a child in common, and Handbook + # 3.1.8 codes one parent as caring for it. Scenarios 3 to 6 give it to + # the parent with the most children. + person_id = person("person_id", period.this_year) + first_cares = (own_children[first] > own_children[second]) | ( + (own_children[first] == own_children[second]) + & (person_id[first] < person_id[second]) + ) + caretaker = where((second < 0) | ((first >= 0) & first_cares), first, second) + rows = child & (caretaker >= 0) + linked_children = np.bincount(caretaker[rows], minlength=count) + candidate = person("is_parent", period.this_year) & receipt + index = np.arange(count) + payee = candidate & (index == person.family.min(where(candidate, index, count))) + return where(linked, linked_children, payee * person.family.sum(child)) diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_child_eligible.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_child_eligible.py new file mode 100644 index 00000000000..e9dc0ce725e --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_child_eligible.py @@ -0,0 +1,34 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.wi.dhs.ssp._wi_cts import ( + cts_relationships, + cts_ssi_recipient, +) + + +class wi_cts_child_eligible(Variable): + value_type = bool + entity = Person + label = "Wisconsin CTS nonfinancially eligible child" + definition_period = MONTH + reference = ( + "https://docs.legis.wisconsin.gov/document/statutes/49.775", + # PDF pages 19-20 + "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=19", + ) + documentation = "Both co-resident parents named by parent IDs must receive Wisconsin state SSI. The Huber Law childcare-release exception (Handbook 3.1.6) is not modeled." + + def formula(person, period, parameters): + p = parameters(period).gov.states.wi.dhs.ssp.cts + _, _, _, _, parents, ssi_parents = cts_relationships(person, period) + status = person("immigration_status", period.this_year).decode_to_str() + return ( + person("wi_cts_dependent_child", period) + & ~cts_ssi_recipient(person, period) + & (ssi_parents > 0) + & (parents == ssi_parents) + & ( + np.isin(status, p.eligible_immigration_statuses) + | person("wi_cts_other_qualifying_immigration_status", period) + ) + & ~person("is_incarcerated", period) + ) diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_child_excluded.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_child_excluded.py new file mode 100644 index 00000000000..53144a093fc --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_child_excluded.py @@ -0,0 +1,10 @@ +from policyengine_us.model_api import * + + +class wi_cts_child_excluded(Variable): + value_type = bool + entity = Person + label = "Wisconsin CTS child excluded by a nonfinancial condition" + definition_period = MONTH + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=18" + documentation = "Set for a currently married or divorced minor, a step or other nonqualifying relationship, or a child-specific exclusion such as kinship care." diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_countable_earned_income.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_countable_earned_income.py new file mode 100644 index 00000000000..a61933bb35a --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_countable_earned_income.py @@ -0,0 +1,39 @@ +from policyengine_us.model_api import * + + +class wi_cts_countable_earned_income(Variable): + value_type = float + entity = Person + label = "Wisconsin CTS individual countable earned income" + definition_period = MONTH + unit = USD + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31" + + def formula(person, period, parameters): + p = parameters(period).gov.states.wi.dhs.ssp.cts + earned = max_(person("ssi_earned_income", period), 0) + continuing_minor = ( + person("age", period.this_year) < p.minor_age_limit + ) & person("wi_cts_received_recently", period) + exempt = continuing_minor & ( + person("is_full_time_student", period.this_year) + | ( + person("wi_cts_part_time_student", period) + & ( + person("weekly_hours_worked", period.this_year) + < p.student_hours_limit + ) + ) + ) + flat = ( + continuing_minor + | person("wi_cts_additional_flat_disregard", period) + | person("wi_cts_additional_fraction_disregard", period) + ) + fraction = continuing_minor | person( + "wi_cts_additional_fraction_disregard", period + ) + earned = max_(earned - p.work_expense - flat * p.earned_flat, 0) * ( + 1 - fraction * p.earned_fraction + ) + return where(exempt, 0, earned) diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_countable_resources.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_countable_resources.py new file mode 100644 index 00000000000..78afc327f6d --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_countable_resources.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class wi_cts_countable_resources(Variable): + value_type = float + entity = Person + label = "Wisconsin CTS individual countable resources" + definition_period = MONTH + unit = USD + quantity_type = STOCK + # PDF pages 31-32 + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31" + documentation = "SSI countable resources plus other CTS countable resources. SSI recipients are excluded at the group calculation." + + def formula(person, period, parameters): + return person("ssi_countable_resources", period.this_year) + person( + "wi_cts_other_countable_resources", period + ) diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_dependent_care_deduction.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_dependent_care_deduction.py new file mode 100644 index 00000000000..ed479820bc5 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_dependent_care_deduction.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class wi_cts_dependent_care_deduction(Variable): + value_type = float + entity = Person + label = "Wisconsin CTS allowed dependent care deduction" + definition_period = MONTH + unit = USD + reference = ( + "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31", + "https://www.govinfo.gov/content/pkg/CFR-1997-title45-vol2/pdf/CFR-1997-title45-vol2-sec233-20.pdf#page=14", + "https://www.govinfo.gov/content/pkg/STATUTE-102/pdf/STATUTE-102-Pg2343.pdf#page=55", + ) + documentation = "Childcare cost per care recipient, subject to the Handbook 3.2.1.2.3 limits. Incapacitated-adult care and the work-related condition are not modeled. The net income test deducts the group's total only from its earned income left after the $90, $30 and one-third disregards. AFDC took the care disregard from each earner's own earned income; the model pools the group's remaining earnings because it does not know who pays for care." + + def formula(person, period, parameters): + p = parameters(period).gov.states.wi.dhs.ssp.cts + limit = where( + person("age", period.this_year) < p.care_young_age, + p.care_young_limit, + p.care_other_limit, + ) + return min_(max_(person("pre_subsidy_childcare_expenses", period), 0), limit) diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_dependent_child.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_dependent_child.py new file mode 100644 index 00000000000..c1a9cbcfadf --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_dependent_child.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class wi_cts_dependent_child(Variable): + value_type = bool + entity = Person + label = "Wisconsin CTS dependent child" + definition_period = MONTH + # PDF pages 18, 21 + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=18" + documentation = "Requires a natural or adopted child. Set wi_cts_child_excluded for married or divorced minors or nonqualifying step/other relationships; annulled marriages do not exclude a minor." + + def formula(person, period, parameters): + p = parameters(period).gov.states.wi.dhs.ssp.cts + age = person("age", period.this_year) + older_student = ( + (age < p.student_age_limit) + & person("is_in_secondary_school", period.this_year) + & person("wi_cts_graduates_before_19", period) + ) + return ((age < p.minor_age_limit) | older_student) & ~person( + "wi_cts_child_excluded", period + ) diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_graduates_before_19.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_graduates_before_19.py new file mode 100644 index 00000000000..06307dc03ac --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_graduates_before_19.py @@ -0,0 +1,9 @@ +from policyengine_us.model_api import * + + +class wi_cts_graduates_before_19(Variable): + value_type = bool + entity = Person + label = "Wisconsin CTS student expected to graduate before age 19" + definition_period = MONTH + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=21" diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_gross_income.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_gross_income.py new file mode 100644 index 00000000000..caa84a3826f --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_gross_income.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class wi_cts_gross_income(Variable): + value_type = float + entity = Person + label = "Wisconsin CTS individual gross countable income" + definition_period = MONTH + unit = USD + # PDF pages 30-31 + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=30" + documentation = "All child support is excluded. Income sources outside the SSI cash-income sources are not counted. SSI recipients are excluded from the filing unit." + + def formula(person, period, parameters): + return max_(person("ssi_earned_income", period), 0) + max_( + person("ssi_unearned_income", period) + - person("child_support_received", period), + 0, + ) diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_large_group_net_income_limit.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_large_group_net_income_limit.py new file mode 100644 index 00000000000..33c9a0b23c1 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_large_group_net_income_limit.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class wi_cts_large_group_net_income_limit(Variable): + value_type = float + entity = Family + label = "Wisconsin CTS agency-verified large assistance group net income limit" + definition_period = MONTH + unit = USD + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=64" + documentation = "Supply the agency-verified monthly net income limit, including any pregnancy allowance, for a filing unit larger than the published net income table. Zero means no verified limit has been supplied; the model cannot establish entitlement for that unit. A Buening subgroup larger than the table is likewise treated as unknown." diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_net_income.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_net_income.py new file mode 100644 index 00000000000..56775a083a9 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_net_income.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class wi_cts_net_income(Variable): + value_type = float + entity = Person + label = "Wisconsin CTS individual net countable income" + definition_period = MONTH + unit = USD + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31" + + def formula(person, period, parameters): + earned = max_(person("ssi_earned_income", period), 0) + unearned = max_(person("wi_cts_gross_income", period) - earned, 0) + return person("wi_cts_countable_earned_income", period) + unearned diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_nonfinancially_ineligible.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_nonfinancially_ineligible.py new file mode 100644 index 00000000000..9f837210c82 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_nonfinancially_ineligible.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class wi_cts_nonfinancially_ineligible(Variable): + value_type = bool + entity = Family + label = "Wisconsin CTS family fails a procedural requirement" + definition_period = MONTH + # PDF pages 22-28, 32 + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=22" + documentation = "Includes unresolved child-support noncooperation without good cause, disqualifying divestment or lump-sum ineligibility, simultaneous W-2 participation, SSI fully recouped, or unverified residence/custody/SSN requirements. Child-specific kinship care or relationship exclusions use wi_cts_child_excluded." diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_other_countable_resources.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_other_countable_resources.py new file mode 100644 index 00000000000..35fd9fa621e --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_other_countable_resources.py @@ -0,0 +1,14 @@ +from policyengine_us.model_api import * + + +class wi_cts_other_countable_resources(Variable): + value_type = float + entity = Person + label = "Wisconsin CTS countable resources outside SSI countable resources" + definition_period = MONTH + unit = USD + quantity_type = STOCK + defined_for = StateCode.WI + # PDF pages 31-32 + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31" + documentation = "Handbook 3.2.2 countable assets that SSI countable resources omit, such as the cash value of life insurance, loan proceeds available for living expenses, the equity value of non-home real property, and vehicle equity above the disregarded first $1,500 of one vehicle." diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_other_qualifying_immigration_status.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_other_qualifying_immigration_status.py new file mode 100644 index 00000000000..545874ef6d5 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_other_qualifying_immigration_status.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class wi_cts_other_qualifying_immigration_status(Variable): + value_type = bool + entity = Person + label = "Wisconsin CTS child has another qualifying immigration status" + definition_period = MONTH + defined_for = StateCode.WI + # PDF pages 19-20 + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=19" + documentation = "True for a child with qualifying lawful temporary resident status or verified PRUCOL status under Handbook 3.1.4 items 3 and 4 that the immigration status input does not identify. Temporary protected status alone does not qualify (8 U.S.C. 1254a(f)(1))." diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_part_time_student.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_part_time_student.py new file mode 100644 index 00000000000..48ceabbdccd --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_part_time_student.py @@ -0,0 +1,9 @@ +from policyengine_us.model_api import * + + +class wi_cts_part_time_student(Variable): + value_type = bool + entity = Person + label = "Wisconsin CTS child attends school part time" + definition_period = MONTH + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31" diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_received_recently.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_received_recently.py new file mode 100644 index 00000000000..09d734da155 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_received_recently.py @@ -0,0 +1,9 @@ +from policyengine_us.model_api import * + + +class wi_cts_received_recently(Variable): + value_type = bool + entity = Person + label = "Wisconsin CTS received in one of the previous four months" + definition_period = MONTH + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=31" diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_sfu_member.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_sfu_member.py new file mode 100644 index 00000000000..f23828585f0 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_sfu_member.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.wi.dhs.ssp._wi_cts import cts_filing_unit + + +class wi_cts_sfu_member(Variable): + value_type = bool + entity = Person + label = "Wisconsin CTS standard filing unit member before Buening" + definition_period = MONTH + # PDF pages 18, 30, 68-75 + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=18" + documentation = "Co-resident parent IDs group non-SSI dependent children who share a parent, with those parents, into separate filing units; an SSI child does not link its siblings. Without parent links the family is treated as one nuclear family. Parent IDs do not distinguish step-parents, whom Handbook 3.1.1 excludes; a step-parent named in a child's parent IDs is treated as a parent." + + def formula(person, period, parameters): + _, member, _ = cts_filing_unit(person, period) + return member diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_tribal_area_i.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_tribal_area_i.py new file mode 100644 index 00000000000..098a168ca9b --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_cts_tribal_area_i.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class wi_cts_tribal_area_i(Variable): + value_type = bool + entity = Household + label = "Wisconsin CTS tribal household in Area I" + definition_period = MONTH + defined_for = StateCode.WI + reference = "https://www.dhs.wisconsin.gov/publications/p23131-25-01.pdf#page=63" + documentation = "True for an Oneida Tribe household outside the listed Area I counties, which Handbook 5.2.3 places in Area I. Winnebago Tribe households on tax-free land in La Crosse or Marathon counties already use Area I through the county list." diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssi_e.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssi_e.py new file mode 100644 index 00000000000..b011abddf89 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssi_e.py @@ -0,0 +1,41 @@ +from policyengine_us.model_api import * + + +class wi_ssi_e(Variable): + value_type = float + entity = Person + label = "Wisconsin SSI Exceptional Expense Supplement" + definition_period = MONTH + unit = USD + defined_for = "wi_ssp_eligible" + reference = ( + "https://www.dhs.wisconsin.gov/dms/memos/ops/dms-ops-2026-12.pdf#page=2", + "https://docs.legis.wisconsin.gov/document/statutes/49.77", + "https://www.emhandbooks.wisconsin.gov/ssi-admin/3/3.1_state-only_ssi_recipients.htm", + # PDF pages 10, 13, 18 + "https://www.dhs.wisconsin.gov/publications/p20679-26-01.pdf#page=10", + ) + + # Grandfathered state-only awards remain outside this formula. DMS Operations + # Memo 26-12 establishes a 10% increase to an existing April 2026 award. + # The references are unclear about a NEW SSI-E certification: whether + # to add E to the protected regular award or recompute a combined + # income budget, and how any historical floor or cap carries forward. + # Wis. Stat. 49.77(2)(a)3, (3s), (5) and Handbook 3.1 establish eligibility + # and payment standards, but do not specify that calculation sequence. + + def formula(person, period, parameters): + p = parameters(period).gov.states.wi.dhs.ssp.exceptional_expense + # Recipients in the "household of another" (one-third reduction) + # arrangement are not eligible for SSI-E (P-20679 3.1.1). + arrangement = person("ssi_federal_living_arrangement", period) + household_of_another = ( + arrangement == arrangement.possible_values.ANOTHER_PERSONS_HOUSEHOLD + ) + certified = ( + person("wi_ssi_e_certified", period) + & person("wi_ssp_eligible", period) + & ~household_of_another + ) + both = person.marital_unit.sum(certified) == 2 + return certified * where(both, p.couple / 2, p.individual) diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssi_e_certified.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssi_e_certified.py new file mode 100644 index 00000000000..15d60b1c2e4 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssi_e_certified.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class wi_ssi_e_certified(Variable): + value_type = bool + entity = Person + label = "Certified for Wisconsin SSI Exceptional Expense Supplement" + documentation = "County certification is effective in the requested month and ongoing SSI-E care requirements are met. Certification incorporates care needs, costs, approved placement or in-home services, and household support availability." + definition_period = MONTH + # PDF pages 7, 13 + reference = "https://www.dhs.wisconsin.gov/publications/p20679-26-01.pdf#page=7" diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssi_e_for_home_care.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssi_e_for_home_care.py new file mode 100644 index 00000000000..4ed4dae509d --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssi_e_for_home_care.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class wi_ssi_e_for_home_care(Variable): + value_type = bool + entity = Person + label = "Wisconsin SSI-E pays for family-member care in the assisted home" + definition_period = MONTH + reference = ( + "https://www.law.cornell.edu/cfr/text/24/5.609", + "https://www.hud.gov/sites/dfiles/OCHCO/documents/2023-27pihn.pdf#page=81", + "https://www.dhs.wisconsin.gov/publications/p20679-26-01.pdf#page=13", + ) + # The certified SSI-E payment funds care, provided by a member of the assisted + # family, that enables this disabled person to remain in the family's assisted + # unit (24 CFR 5.609(b)(19)). False for a substitute-care or facility award, care + # by someone outside the assisted family, or certification alone. diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp.py new file mode 100644 index 00000000000..9b56ef8c5df --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class wi_ssp(Variable): + value_type = float + entity = Person + label = "Wisconsin State SSI Supplement" + definition_period = MONTH + unit = USD + defined_for = StateCode.WI + reference = ( + "https://www.emhandbooks.wisconsin.gov/ssi-admin/2/2.1_federal_and_state_ssi_recipients.htm", + "https://www.dhs.wisconsin.gov/dms/memos/ops/dms-ops-2026-12.pdf#page=2", + ) + adds = ["wi_ssp_regular", "wi_ssi_e", "wi_cts"] diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_countable_for_hud.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_countable_for_hud.py new file mode 100644 index 00000000000..bbee18bf5c5 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_countable_for_hud.py @@ -0,0 +1,35 @@ +from policyengine_us.model_api import * + + +class wi_ssp_countable_for_hud(Variable): + value_type = float + entity = Person + label = "Wisconsin SSI supplement countable for HUD" + definition_period = MONTH + unit = USD + defined_for = StateCode.WI + reference = ( + "https://www.law.cornell.edu/cfr/text/24/5.609", + "https://www.dhs.wisconsin.gov/publications/p20679-26-01.pdf#page=24", + "https://www.hud.gov/sites/dfiles/OCHCO/documents/2023-27pihn.pdf#page=81", + # PDF pages 3-4 + "https://www.hud.gov/sites/dfiles/OCHCO/documents/2024-38pihn.pdf#page=3", + ) + + def formula(person, period, parameters): + # Source conflict: SSI-E Handbook 4.1.1 counts SSI-E; 24 CFR 5.609(b)(19) + # governs. + # HUD person with disabilities (42 U.S.C. 1437a(b)(3)(E)), as in + # is_hud_elderly_disabled_family, plus blindness. + disabled = ( + person("is_disabled", period.this_year) + | person("is_ssi_disabled", period.this_year) + | (person("social_security_disability", period) > 0) + | person("is_blind", period.this_year) + ) + excluded = ( + disabled + & person("wi_ssi_e_for_home_care", period) + & ~person("ssi_lives_in_medical_treatment_facility", period) + ) + return person("wi_ssp", period) - excluded * person("wi_ssi_e", period) diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_countable_for_snap.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_countable_for_snap.py new file mode 100644 index 00000000000..426404630f2 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_countable_for_snap.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class wi_ssp_countable_for_snap(Variable): + value_type = float + entity = Person + label = "Wisconsin state SSI supplements countable for FoodShare" + definition_period = MONTH + unit = USD + defined_for = StateCode.WI + reference = "https://www.emhandbooks.wisconsin.gov/fsh/policy_files/4/43/4.3.4.htm" + # The current FoodShare income manual explicitly excludes SSI-E. + # The SSI-E handbook's older FoodShare discussion says otherwise; + # use the administering program's current, specific income rule. + adds = ["wi_ssp_regular", "wi_cts"] diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_eligible.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_eligible.py new file mode 100644 index 00000000000..2dae649a7c3 --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_eligible.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class wi_ssp_eligible(Variable): + value_type = bool + entity = Person + label = "Eligible for Wisconsin State SSI Supplement" + definition_period = MONTH + defined_for = StateCode.WI + reference = ( + "https://docs.legis.wisconsin.gov/document/statutes/49.77", + "https://www.emhandbooks.wisconsin.gov/ssi-admin/2/2.1_federal_and_state_ssi_recipients.htm", + ) + + def formula(person, period, parameters): + # This models federal-linked recipients. Grandfathered state-only + # recipients can qualify without federal SSI; their protected award + # and unresolved new SSI-E certification budget are documented in + # wi_ssi_e rather than inferred from the ordinary payment schedule. + receives_ssi = (person("ssi", period) > 0) | person("receives_ssi", period) + institutional = person("ssi_lives_in_medical_treatment_facility", period) + continuation = person("wi_ssp_institutional_continuation", period) + incarcerated = person("is_incarcerated", period) + return receives_ssi & ~incarcerated & (~institutional | continuation) diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_institutional_continuation.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_institutional_continuation.py new file mode 100644 index 00000000000..d2a44eb39cb --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_institutional_continuation.py @@ -0,0 +1,10 @@ +from policyengine_us.model_api import * + + +class wi_ssp_institutional_continuation(Variable): + value_type = bool + entity = Person + label = "Wisconsin SSP temporary institutional continuation" + documentation = "State payment remains authorized during a temporary institutional stay. The continuation ends with the first month following the 90th day in a nursing home." + definition_period = MONTH + reference = "https://www.emhandbooks.wisconsin.gov/ssi-admin/2/2.1_federal_and_state_ssi_recipients.htm" diff --git a/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_regular.py b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_regular.py new file mode 100644 index 00000000000..05b9a4b6fcc --- /dev/null +++ b/policyengine_us/variables/gov/states/wi/dhs/ssp/wi_ssp_regular.py @@ -0,0 +1,37 @@ +from policyengine_us.model_api import * + + +class wi_ssp_regular(Variable): + value_type = float + entity = Person + label = "Wisconsin basic state SSI supplement" + definition_period = MONTH + unit = USD + defined_for = "wi_ssp_eligible" + reference = "https://www.dhs.wisconsin.gov/dms/memos/ops/dms-ops-2026-12.pdf#page=2" + + def formula(person, period, parameters): + p = parameters(period).gov.states.wi.dhs.ssp + eligible = person("wi_ssp_eligible", period) + eligible_couple = person.marital_unit.sum(eligible) == 2 + # The one-eligible-spouse rate requires an SSI-ineligible spouse. A spouse + # who is SSI-eligible but excluded from the state payment leaves the + # recipient on the individual rate. + ineligible_spouse = person("is_ssi_ineligible_spouse", period.this_year) + has_ineligible_spouse = ( + person.marital_unit.sum(ineligible_spouse) - ineligible_spouse + ) > 0 + arrangement = person("ssi_federal_living_arrangement", period) + other_household = ( + arrangement == arrangement.possible_values.ANOTHER_PERSONS_HOUSEHOLD + ) + with_ineligible_spouse = where( + other_household, + p.amount.ineligible_spouse_other_household, + p.amount.ineligible_spouse_independent, + ) + return select( + [eligible_couple, has_ineligible_spouse], + [p.amount.couple / 2, with_ineligible_spouse], + default=p.amount.individual, + ) diff --git a/policyengine_us/variables/household/income/spm_unit/spm_unit_benefits.py b/policyengine_us/variables/household/income/spm_unit/spm_unit_benefits.py index a473c2b438d..d3ff039e903 100644 --- a/policyengine_us/variables/household/income/spm_unit/spm_unit_benefits.py +++ b/policyengine_us/variables/household/income/spm_unit/spm_unit_benefits.py @@ -22,6 +22,7 @@ def formula(spm_unit, period, parameters): "ky_ssp", # Kentucky benefits "de_ssp", # Delaware benefits "fl_oss", + "wi_ssp", # Wisconsin benefits "ks_sspp", # Kansas benefits "hi_oss", "la_oss", # Louisiana benefits