diff --git a/changelog.d/mn-msa.added.md b/changelog.d/mn-msa.added.md new file mode 100644 index 00000000000..02ae8cdd9ab --- /dev/null +++ b/changelog.d/mn-msa.added.md @@ -0,0 +1 @@ +Minnesota Supplemental Aid (MSA) — State Supplementary Payment to SSI. diff --git a/policyengine_us/parameters/gov/household/household_state_benefits.yaml b/policyengine_us/parameters/gov/household/household_state_benefits.yaml index b74241a36b5..712134de1ee 100644 --- a/policyengine_us/parameters/gov/household/household_state_benefits.yaml +++ b/policyengine_us/parameters/gov/household/household_state_benefits.yaml @@ -16,6 +16,8 @@ values: - ma_state_supplement # Michigan benefits - mi_ssp + # Minnesota benefits + - mn_msa # Colorado benefits - co_state_supplement - co_oap @@ -83,6 +85,8 @@ values: - ma_state_supplement # Michigan benefits - mi_ssp + # Minnesota benefits + - mn_msa # Colorado benefits - co_state_supplement - co_oap diff --git a/policyengine_us/parameters/gov/states/mn/dhs/msa/assistance_standard/amount.yaml b/policyengine_us/parameters/gov/states/mn/dhs/msa/assistance_standard/amount.yaml new file mode 100644 index 00000000000..3769b478bdd --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/dhs/msa/assistance_standard/amount.yaml @@ -0,0 +1,54 @@ +description: Minnesota provides this amount as the combined federal-and-state assistance standard under the Minnesota Supplemental Aid program. + +metadata: + unit: currency-USD + period: month + label: Minnesota Supplemental Aid assistance standard amount + breakdown: + - mn_msa_living_arrangement + reference: + - title: Minn. Stat. § 256D.44 Subd. 1 (Use of standards; SSI COLA escalator) + href: https://www.revisor.mn.gov/statutes/cite/256D.44 + - title: Minn. Stat. § 256D.44 Subd. 3 (Standards of assistance for basic needs) + href: https://www.revisor.mn.gov/statutes/cite/256D.44 + - title: MN DHS Combined Manual 0020.21 - MSA Assistance Standards (01/2026) + href: https://www.dhs.state.mn.us/main/groups/county_access/documents/pub/mndhs-073585.pdf#page=4 + - title: MN DHS Combined Manual 0020.24 - Personal Needs Allowance (01/2026) + href: https://www.dhs.state.mn.us/main/groups/county_access/documents/pub/mndhs-073585.pdf#page=6 + - title: MN House Research Department - Minnesota Supplemental Aid (October 2024), MSA Assistance Standards table + href: https://www.house.mn.gov/hrd/pubs/pap_MSA.pdf#page=6 + - title: SSA State Assistance Programs for SSI Recipients, January 2011 - Minnesota, Table 1 + href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/mn.html + +INDIVIDUAL_LIVING_ALONE: + 2011-01-01: 735 + 2024-01-01: 1_004 + 2025-01-01: 1_028 + 2026-01-01: 1_055 + +INDIVIDUAL_LIVING_WITH_OTHERS: + 2011-01-01: 542 + 2024-01-01: 721 + 2025-01-01: 737.33 + 2026-01-01: 755.33 + +COUPLE_LIVING_ALONE: + 2011-01-01: 1_102 + 2024-01-01: 1_506 + 2025-01-01: 1_541 + 2026-01-01: 1_582 + +COUPLE_LIVING_WITH_OTHERS: + 2011-01-01: 738 + 2024-01-01: 1_007 + 2025-01-01: 1_030.67 + 2026-01-01: 1_058 + +MEDICAID_FACILITY: + 2011-01-01: 89 + 2024-01-01: 125 + 2025-01-01: 128 + 2026-01-01: 132 + +NONE: + 2011-01-01: 0 diff --git a/policyengine_us/parameters/gov/states/mn/dhs/msa/eligibility/asset_limit/non_ssi_track.yaml b/policyengine_us/parameters/gov/states/mn/dhs/msa/eligibility/asset_limit/non_ssi_track.yaml new file mode 100644 index 00000000000..855900d2e87 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/dhs/msa/eligibility/asset_limit/non_ssi_track.yaml @@ -0,0 +1,16 @@ +description: Minnesota limits countable resources to this amount under the Minnesota Supplemental Aid program for the non-SSI excess-income track. + +values: + 1989-01-01: 10_000 + +metadata: + unit: currency-USD + period: year + label: Minnesota Supplemental Aid non-SSI track asset limit + reference: + - title: Minn. Stat. § 256P.02 Subd. 2 (Resource limit) + href: https://www.revisor.mn.gov/statutes/cite/256P.02 + - title: Minn. Stat. § 256D.425 Subd. 2(b) (Resource standards via § 256P.02) + href: https://www.revisor.mn.gov/statutes/cite/256D.425 + - title: MN House Research Department - Minnesota Supplemental Aid (October 2024), Resource and asset limits + href: https://www.house.mn.gov/hrd/pubs/pap_MSA.pdf#page=4 diff --git a/policyengine_us/parameters/gov/states/mn/dhs/msa/eligibility/income_limit/couple_fbr_multiplier.yaml b/policyengine_us/parameters/gov/states/mn/dhs/msa/eligibility/income_limit/couple_fbr_multiplier.yaml new file mode 100644 index 00000000000..70a52176b44 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/dhs/msa/eligibility/income_limit/couple_fbr_multiplier.yaml @@ -0,0 +1,14 @@ +description: Minnesota limits couple gross income to this multiple of the federal Supplemental Security Income individual benefit rate under the Minnesota Supplemental Aid program. + +values: + 1989-01-01: 6 + +metadata: + unit: /1 + period: year + label: Minnesota Supplemental Aid couple gross income FBR multiplier + reference: + - title: MN DHS Combined Manual 0019.06 - Gross Income Limits (MSA) + href: https://www.dhs.state.mn.us/main/idcplg?IdcService=GET_DYNAMIC_CONVERSION&RevisionSelectionMethod=LatestReleased&dDocName=cm_001906 + - title: MN House Research Department - Minnesota Supplemental Aid (October 2024), Income standards and treatment of income + href: https://www.house.mn.gov/hrd/pubs/pap_MSA.pdf#page=3 diff --git a/policyengine_us/parameters/gov/states/mn/dhs/msa/eligibility/income_limit/individual_fbr_multiplier.yaml b/policyengine_us/parameters/gov/states/mn/dhs/msa/eligibility/income_limit/individual_fbr_multiplier.yaml new file mode 100644 index 00000000000..6cf19f21b19 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/dhs/msa/eligibility/income_limit/individual_fbr_multiplier.yaml @@ -0,0 +1,14 @@ +description: Minnesota limits individual gross income to this multiple of the federal Supplemental Security Income individual benefit rate under the Minnesota Supplemental Aid program. + +values: + 1989-01-01: 3 + +metadata: + unit: /1 + period: year + label: Minnesota Supplemental Aid individual gross income FBR multiplier + reference: + - title: MN DHS Combined Manual 0019.06 - Gross Income Limits (MSA) + href: https://www.dhs.state.mn.us/main/idcplg?IdcService=GET_DYNAMIC_CONVERSION&RevisionSelectionMethod=LatestReleased&dDocName=cm_001906 + - title: MN House Research Department - Minnesota Supplemental Aid (October 2024), Income standards and treatment of income + href: https://www.house.mn.gov/hrd/pubs/pap_MSA.pdf#page=3 diff --git a/policyengine_us/parameters/gov/states/mn/dhs/msa/housing_assistance/fbr_multiplier.yaml b/policyengine_us/parameters/gov/states/mn/dhs/msa/housing_assistance/fbr_multiplier.yaml new file mode 100644 index 00000000000..891d5611887 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/dhs/msa/housing_assistance/fbr_multiplier.yaml @@ -0,0 +1,14 @@ +description: Minnesota provides this share of the federal Supplemental Security Income individual benefit rate as the housing allowance under the Minnesota Supplemental Aid program. + +values: + 1989-01-01: 0.5 + +metadata: + unit: /1 + period: year + label: Minnesota Supplemental Aid housing allowance FBR multiplier + reference: + - title: Minn. Stat. § 256D.44 Subd. 5(g)(1) + href: https://www.revisor.mn.gov/statutes/cite/256D.44 + - title: MN DHS Combined Manual 0023.24 - MSA Housing Assistance + href: https://www.dhs.state.mn.us/main/idcplg?IdcService=GET_DYNAMIC_CONVERSION&dDocName=cm_002324&RevisionSelectionMethod=LatestReleased diff --git a/policyengine_us/parameters/gov/states/mn/dhs/msa/special_needs/guardian_fee/max_amount.yaml b/policyengine_us/parameters/gov/states/mn/dhs/msa/special_needs/guardian_fee/max_amount.yaml new file mode 100644 index 00000000000..a4bef844f81 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/dhs/msa/special_needs/guardian_fee/max_amount.yaml @@ -0,0 +1,14 @@ +description: Minnesota caps the guardian or conservator fee special-needs allowance at this amount under the Minnesota Supplemental Aid program. + +values: + 1989-01-01: 100 + +metadata: + unit: currency-USD + period: month + label: Minnesota Supplemental Aid guardian fee maximum amount + reference: + - title: Minn. Stat. § 256D.44 Subd. 5(d) (Guardian or conservator fee) + href: https://www.revisor.mn.gov/statutes/cite/256D.44 + - title: SSA State Assistance Programs for SSI Recipients, January 2011 - Minnesota, Special Needs Circumstances - Guardianship fees + href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/mn.html diff --git a/policyengine_us/parameters/gov/states/mn/dhs/msa/special_needs/guardian_fee/rate.yaml b/policyengine_us/parameters/gov/states/mn/dhs/msa/special_needs/guardian_fee/rate.yaml new file mode 100644 index 00000000000..e46e61af960 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/dhs/msa/special_needs/guardian_fee/rate.yaml @@ -0,0 +1,14 @@ +description: Minnesota provides this share of gross monthly income as the guardian or conservator fee special-needs allowance under the Minnesota Supplemental Aid program. + +values: + 1989-01-01: 0.05 + +metadata: + unit: /1 + period: year + label: Minnesota Supplemental Aid guardian fee rate + reference: + - title: Minn. Stat. § 256D.44 Subd. 5(d) (Guardian or conservator fee) + href: https://www.revisor.mn.gov/statutes/cite/256D.44 + - title: SSA State Assistance Programs for SSI Recipients, January 2011 - Minnesota, Special Needs Circumstances - Guardianship fees + href: https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/mn.html diff --git a/policyengine_us/parameters/gov/states/mn/dhs/msa/special_needs/representative_payee_fee/amount.yaml b/policyengine_us/parameters/gov/states/mn/dhs/msa/special_needs/representative_payee_fee/amount.yaml new file mode 100644 index 00000000000..7a30ab4b1f5 --- /dev/null +++ b/policyengine_us/parameters/gov/states/mn/dhs/msa/special_needs/representative_payee_fee/amount.yaml @@ -0,0 +1,15 @@ +description: Minnesota provides this amount as the representative payee service special-needs allowance under the Minnesota Supplemental Aid program. + +values: + 2011-01-01: 25 + 2026-01-01: 57 + +metadata: + unit: currency-USD + period: month + label: Minnesota Supplemental Aid representative payee fee amount + reference: + - title: Minn. Stat. § 256D.44 Subd. 5(f) (Representative payee fee) + href: https://www.revisor.mn.gov/statutes/cite/256D.44 + - title: MN DHS Combined Manual 0023.21 - Representative Payee Services (01/2026) + href: https://www.dhs.state.mn.us/main/groups/county_access/documents/pub/mndhs-073585.pdf#page=7 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 76b5377b5f3..16a8fe079be 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -712,6 +712,12 @@ programs: name: Maine SSP full_name: Maine State Supplemental Income Program variable: me_ssp + - state: MN + status: complete + name: Minnesota MSA + full_name: Minnesota Supplemental Aid + variable: mn_msa + parameter_prefix: gov.states.mn.dhs.msa - state: KS status: complete name: Kansas SSPP diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_eligible_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_eligible_person.yaml new file mode 100644 index 00000000000..e9d29b5979d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_eligible_person.yaml @@ -0,0 +1,316 @@ +- name: Case 1, aged SSI recipient is eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_000 + ssi: 11_928 # $994/mo + employment_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_eligible_person: true + +- name: Case 2, SSI-eligible-except-for-income is eligible on the non-SSI track. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 5_000 # below non-SSI $10k cap, above SSI $2k cap + ssi: 0 + ssi_unearned_income: 12_000 # $1,000/mo unearned (above SSI FBR but below MSA standard) + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Income $1,000 < $1,055 individual living alone standard. + # Gross < 300% FBR ($2,982). + mn_msa_eligible_person: true + +- name: Case 3, non-aged non-blind non-disabled adult is ineligible. + period: 2026-01 + input: + people: + person1: + age: 40 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_eligible_person: false + +- name: Case 4, income above MSA standard is ineligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 0 + ssi_unearned_income: 24_000 # $2,000/mo > $1,055 standard + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Countable $2,000 > $1,055 standard -> not income eligible. + mn_msa_eligible_person: false + +- name: Case 5, child applicant with high parent-deemed income fails gross income test. + period: 2026-01 + input: + people: + person1: + age: 10 + is_blind: false + is_disabled: true + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 0 + ssi_unearned_income: 0 + ssi_unearned_income_deemed_from_ineligible_parent: 60_000 # $5,000/mo + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Parent-deemed $5,000/mo > 300% individual FBR (~$2,982/mo in 2026) + # -> gross income test fails. + mn_msa_eligible_person: false + +- name: Case 6, non-qualifying living arrangement is ineligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + mn_msa_living_arrangement: NONE + mn_msa_uses_representative_payee: true + ssi_countable_resources: 500 + ssi: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_eligible_person: false + mn_msa_person: 0 + +- name: Case 7, disabled child who is not blind is ineligible. + period: 2026-01 + input: + people: + person1: + age: 10 + is_blind: false + is_disabled: true + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_eligible_person: false + +- name: Case 8, legal permanent resident aged senior is eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: LEGAL_PERMANENT_RESIDENT + ssi_countable_resources: 1_000 + ssi: 11_928 # $994/mo + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_eligible_person: true + +- name: Case 9, undocumented immigrant fails the immigration check. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: UNDOCUMENTED + ssi_countable_resources: 500 + ssi: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_eligible_person: false + +- name: Case 10, blind 10-year-old citizen is eligible (blind has no age cap). + period: 2026-01 + input: + people: + person1: + age: 10 + is_blind: true + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 11_928 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Blind branch in (aged | blind | disabled_adult) does not gate on age >= 18. + mn_msa_eligible_person: true + +- name: Case 11, Medicaid facility resident is eligible. + period: 2026-01 + input: + people: + person1: + age: 80 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 200 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + ssi: 360 # $30/mo FLA-D + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Aged + receives federal SSI + low resources + facility category != NONE. + mn_msa_eligible_person: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_gross_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_gross_income_eligible.yaml new file mode 100644 index 00000000000..db93bcfe88f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_gross_income_eligible.yaml @@ -0,0 +1,262 @@ +- name: Case 1, individual at exactly 300% of SSI FBR is gross-income eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + employment_income: 35_784 # $2,982/mo = 3 x $994 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Cap = 3 x $994 = $2,982 -> $2,982 <= $2,982 passes. + mn_msa_gross_income_eligible: true + +- name: Case 2, couple at exactly 600% of SSI FBR is gross-income eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + ssi_claim_is_joint: true + employment_income: 35_784 # $2,982/mo + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + ssi_claim_is_joint: true + employment_income: 35_784 # $2,982/mo -> couple total $5,964 = 6 x $994 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # Couple cap = 6 x $994 = $5,964 -> $5,964 <= $5,964 passes. + mn_msa_gross_income_eligible: [true, true] + +- name: Case 3, individual above 300% of SSI FBR is not gross-income eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + employment_income: 36_000 # $3,000/mo > $2,982 cap + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_gross_income_eligible: false + +- name: Case 4, individual at $1 below 300% of SSI FBR is gross-income eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi_unearned_income: 35_772 # $2,981/mo, $1 below the $2,982 cap + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # $2,981 < $2,982 cap -> eligible. + mn_msa_gross_income_eligible: true + +- name: Case 5, individual at $1 above 300% of SSI FBR is not gross-income eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi_unearned_income: 35_796 # $2,983/mo, $1 above the $2,982 cap + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # $2,983 > $2,982 cap -> not eligible. + mn_msa_gross_income_eligible: false + +- name: Case 6, couple at $2 below 600% of SSI FBR is gross-income eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + ssi_claim_is_joint: true + ssi_unearned_income: 35_772 # $2,981/mo + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + ssi_claim_is_joint: true + ssi_unearned_income: 35_772 # $2,981/mo -> couple total $5,962 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # Couple gross $5,962 < $5,964 cap -> eligible. + mn_msa_gross_income_eligible: [true, true] + +- name: Case 7, couple at $2 above 600% of SSI FBR is not gross-income eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + ssi_claim_is_joint: true + ssi_unearned_income: 35_796 # $2,983/mo + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + ssi_claim_is_joint: true + ssi_unearned_income: 35_796 # $2,983/mo -> couple total $5,966 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # Couple gross $5,966 > $5,964 cap -> not eligible. + mn_msa_gross_income_eligible: [false, false] + +- name: Case 8, non-SSI aged couple uses the 600% couple cap regardless of joint claim. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 4_000 + ssi: 0 + ssi_claim_is_joint: false # not on SSI -> no joint claim flag + employment_income: 36_000 # $3,000/mo, above $2,982 individual cap + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 4_000 + ssi: 0 + ssi_claim_is_joint: false + employment_income: 24_000 # $2,000/mo + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # Both spouses are aged -> couple gross cap $5,964 applies. + # Combined gross $5,000 < $5,964 -> both eligible (would have failed + # under per-person individual $2,982 cap on the higher-earning spouse). + mn_msa_gross_income_eligible: [true, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_net_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_net_income_eligible.yaml new file mode 100644 index 00000000000..8a3412abefe --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_net_income_eligible.yaml @@ -0,0 +1,267 @@ +- name: Case 1, countable income exactly at MSA standard is net-income eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 5_000 + ssi: 0 + ssi_unearned_income: 12_900 # $1,075/mo; minus $20 general = $1,055 countable + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Countable $1,055 <= $1,055 standard -> eligible. + mn_msa_net_income_eligible: true + +- name: Case 2, countable income $1 above MSA standard is not net-income eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 5_000 + ssi: 0 + ssi_unearned_income: 12_912 # $1,076/mo; minus $20 general = $1,056 countable + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Countable $1,056 > $1,055 standard -> not eligible. + mn_msa_net_income_eligible: false + +- name: Case 3, countable income $1 below MSA standard is net-income eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 5_000 + ssi: 0 + ssi_unearned_income: 12_888 # $1,074/mo; minus $20 general = $1,054 countable + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Countable $1,054 <= $1,055 standard -> eligible. + mn_msa_net_income_eligible: true + +- name: Case 4, couple countable income above the couple standard is not net-income eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_countable_resources: 5_000 + ssi: 0 + ssi_unearned_income: 9_618 # $801.50/mo + person2: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_countable_resources: 5_000 + ssi: 0 + ssi_unearned_income: 9_618 # $801.50/mo + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # Non-SSI couple: AU-aggregate raw unearned $1,603/mo - $20 general + # disregard = $1,603 countable. $1,603 > $1,582 couple standard -> + # ineligible for both spouses. + mn_msa_net_income_eligible: [false, false] + +- name: Case 5, non-SSI couple at exact-equal couple standard is eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_countable_resources: 5_000 + ssi: 0 + ssi_unearned_income: 9_612 # $801/mo each = AU $1,602 + person2: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_countable_resources: 5_000 + ssi: 0 + ssi_unearned_income: 9_612 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # AU unearned $1,602/mo - $20 = $1,582 = couple standard -> eligible. + mn_msa_net_income_eligible: [true, true] + +- name: Case 6, non-SSI couple $1 below couple standard is eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_countable_resources: 5_000 + ssi: 0 + ssi_unearned_income: 9_606 # $800.50/mo each = AU $1,601 + person2: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_countable_resources: 5_000 + ssi: 0 + ssi_unearned_income: 9_606 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # AU unearned $1,601/mo - $20 = $1,581 < $1,582 couple standard -> eligible. + mn_msa_net_income_eligible: [true, true] + +- name: Case 7, Medicaid facility recipient with $30 FBR and $0 unearned passes net-income test. + period: 2026-01 + input: + people: + person1: + age: 80 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 200 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + ssi: 360 # $30/mo FLA-D + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # FLA-D carve-out: disregard = 0. SSI track countable = $30 FBR + 0 unearned + # = $30. Standard $132 PNA -> $30 <= $132 -> eligible. + mn_msa_net_income_eligible: true + +- name: Case 8, special needs are included in the net-income standard. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 5_000 + mn_msa_uses_representative_payee: true + ssi: 0 + ssi_unearned_income: 12_996 # $1,083/mo; minus $20 general = $1,063 countable + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Countable $1,063 > $1,055 basic standard, but <= $1,112 standard + # after the $57 representative-payee allowance. + mn_msa_net_income_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_resource_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_resource_eligible.yaml new file mode 100644 index 00000000000..f62853a0132 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/eligibility/mn_msa_resource_eligible.yaml @@ -0,0 +1,306 @@ +- name: Case 1, SSI recipient with low resources is resource eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_500 + ssi: 11_928 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # SSI recipients pass MSA's resource test by virtue of receiving SSI + # (federal $2,000/$3,000 caps are enforced upstream in the SSI calc). + mn_msa_resource_eligible: true + +- name: Case 2, non-SSI track at $10,000 boundary is resource eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 10_000 + ssi: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Non-SSI track: $10,000 cap, exact boundary passes. + mn_msa_resource_eligible: true + +- name: Case 3, non-SSI track above $10,000 is not resource eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 10_500 + ssi: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_resource_eligible: false + +- name: Case 4, non-SSI track at $9,999 is resource eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 9_999 + ssi: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Non-SSI track: $9,999 <= $10,000 cap -> eligible. + mn_msa_resource_eligible: true + +- name: Case 5, non-SSI track at $10,001 is not resource eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 10_001 + ssi: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Non-SSI track: $10,001 > $10,000 cap -> not eligible. + mn_msa_resource_eligible: false + +- name: Case 6, single SSI recipient with resources just below SSI $2,000 cap. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_999 + ssi: 11_928 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # SSI recipient: passes MSA resource test by virtue of receiving SSI. + # The federal $2,000 cap is enforced upstream and is not exercised here. + mn_msa_resource_eligible: true + +- name: Case 7, SSI couple with combined resources just below $3,000 cap. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_499 + ssi_claim_is_joint: true + ssi: 8_946 + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_499 + ssi_claim_is_joint: true + ssi: 8_946 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # Both spouses are SSI recipients so they pass MSA's resource test. + # The federal $3,000 couple cap is enforced upstream and not exercised. + mn_msa_resource_eligible: [true, true] + +- name: Case 8, person with high resources but ssi=0 falls back to non-SSI track. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 9_500 # > $2k SSI cap, < $10k non-SSI cap + ssi: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # ssi=0 -> non-SSI track applies; $9,500 <= $10,000 -> eligible. + mn_msa_resource_eligible: true + +- name: Case 9, non-SSI couple with combined resources above $10,000 cap is ineligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 6_000 # individually under $10k + ssi: 0 + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 6_000 # individually under $10k + ssi: 0 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # § 256P.02 Subd. 2 (applied via § 256D.425 Subd. 2(b)): $10,000 cap + # applies to the assistance unit. Combined $12,000 > $10,000 -> both + # spouses ineligible. + mn_msa_resource_eligible: [false, false] + +- name: Case 10, non-SSI couple with combined resources at the $10,000 boundary is eligible. + period: 2026-01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 5_000 + ssi: 0 + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 5_000 + ssi: 0 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # Combined $10,000 == cap -> eligible. + mn_msa_resource_eligible: [true, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/integration.yaml new file mode 100644 index 00000000000..b255c1bd7ef --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/integration.yaml @@ -0,0 +1,472 @@ +- name: Case 1, single SSI recipient living alone with no other income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_000 + ssi: 11_928 # $994/mo + ssi_earned_income: 0 + ssi_unearned_income: 0 + employment_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_living_arrangement: INDIVIDUAL_LIVING_ALONE + mn_msa_assistance_standard: 1_055 + mn_msa_eligible_person: true + # Need $1,055 - max($994 SSI - $20 general, 0) - countable $0 = $81. + mn_msa_person: 81 + mn_msa: 81 + +- name: Case 2, SSI couple living with others gets the couple-rate gating. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + mn_msa_living_arrangement: COUPLE_LIVING_WITH_OTHERS + ssi_claim_is_joint: true + ssi: 8_946 # $745.50/mo (couple FBR $1,491 / 2) + ssi_earned_income: 0 + ssi_unearned_income: 0 + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + mn_msa_living_arrangement: COUPLE_LIVING_WITH_OTHERS + ssi_claim_is_joint: true + ssi: 8_946 + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + mn_msa_living_arrangement: [COUPLE_LIVING_WITH_OTHERS, COUPLE_LIVING_WITH_OTHERS] + mn_msa_assistance_standard: [1_058, 1_058] + # Couple SSI track countable = $1,491 FBR + $0 unearned - $20 = $1,471. + # Standard $1,058 < $1,471, so the net-income test fails -> not eligible + # and no state supplement (couple FBR exceeds the CLWO standard). + mn_msa_eligible_person: [false, false] + mn_msa_person: [0, 0] + mn_msa: 0 + +- name: Case 3, non-SSI track recipient with income above SSI but below MSA standard. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 5_000 # above $2k SSI cap, below $10k non-SSI cap + ssi: 0 + ssi_earned_income: 0 + ssi_unearned_income: 12_000 # $1,000/mo + employment_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_living_arrangement: INDIVIDUAL_LIVING_ALONE + mn_msa_assistance_standard: 1_055 + mn_msa_eligible_person: true + # Standard $1,055 - countable ($1,000 - $20 general) = $1,055 - $980 = $75. + mn_msa_person: 75 + mn_msa: 75 + +- name: Case 4, Medicaid facility recipient receives PNA-only state portion. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 200 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + ssi: 360 # $30/mo FLA-D + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # The bare-input mn_msa_living_arrangement defaults to INDIVIDUAL_LIVING_ALONE; + # the federal medical-facility status is detected by mn_msa_payment_category, + # which the assistance_standard formula reads. + mn_msa_payment_category: MEDICAID_FACILITY + mn_msa_assistance_standard: 132 + mn_msa_eligible_person: true + # Combined PNA standard $132 - federal SSI FBR $30 = $102 state supplement. + mn_msa_person: 102 + mn_msa: 102 + +- name: Case 5, recipient with MSA Housing Assistance add-on. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + is_blind: false + is_disabled: true + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_housing_assistance_eligible: true + ssi: 11_928 + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_living_arrangement: INDIVIDUAL_LIVING_ALONE + mn_msa_assistance_standard: 1_055 + mn_msa_housing_assistance: 497 + mn_msa_eligible_person: true + # Base: $1,055 - max($994 SSI - $20, 0) = $81; plus $497 housing add-on = $578. + mn_msa_person: 578 + mn_msa: 578 + +- name: Case 6, negative countable income does not inflate benefit. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 11_928 + self_employment_income: -60_000_000 # extreme negative + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Countable income components are floored at 0; benefit cannot exceed need - SSI. + # $1,055 - max($994 SSI - $20 general, 0) = $1,055 - $974 = $81. + mn_msa_assistance_standard: 1_055 + mn_msa_person: 81 + mn_msa: 81 + +- name: Case 7, non-ABD adult is ineligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_eligible_person: false + mn_msa_person: 0 + mn_msa: 0 + +- name: Case 8, 2024 single SSI recipient living alone uses 2024 rates. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 1_000 + ssi: 11_316 # $943/mo (2024 federal individual FBR) + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_living_arrangement: INDIVIDUAL_LIVING_ALONE + mn_msa_assistance_standard: 1_004 + mn_msa_eligible_person: true + # Need $1,004 - max($943 SSI - $20 general, 0) = $1,004 - $923 = $81. + mn_msa_person: 81 + mn_msa: 81 + +- name: Case 9, asymmetric eligibility couple — only one spouse SSI-eligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + ssi_claim_is_joint: false + ssi: 11_928 # eligible spouse, full FBR + ssi_earned_income: 0 + ssi_unearned_income: 0 + person2: + age: 40 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + ssi_claim_is_joint: false + ssi: 0 # ineligible spouse, not aged/blind/disabled + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # Only one spouse is SSI-eligible -> individual rate, not couple rate. + # Both spouses default to INDIVIDUAL_LIVING_ALONE; ineligible spouse is + # zeroed out by the mn_msa_eligible_person filter. + mn_msa_living_arrangement: [INDIVIDUAL_LIVING_ALONE, INDIVIDUAL_LIVING_ALONE] + mn_msa_eligible_person: [true, false] + # person1: $1,055 - max($994 SSI - $20 general, 0) = $1,055 - $974 = $81. + # person2: not categorically eligible. + mn_msa_person: [81, 0] + mn_msa: 81 + +- name: Case 10, couple living-with-others where one spouse has housing assistance triggers couple "living alone" upgrade. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_living_arrangement: COUPLE_LIVING_WITH_OTHERS + mn_msa_housing_assistance_eligible: true + ssi_claim_is_joint: true + ssi: 8_946 # $745.50/mo each + ssi_earned_income: 0 + ssi_unearned_income: 0 + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_living_arrangement: COUPLE_LIVING_WITH_OTHERS + mn_msa_housing_assistance_eligible: false + ssi_claim_is_joint: true + ssi: 8_946 + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # marital_unit.any(housing_assistance_eligible) -> True for both spouses. + # COUPLE_LIVING_WITH_OTHERS upgrades to COUPLE_LIVING_ALONE standard ($1,582). + mn_msa_payment_category: [COUPLE_LIVING_ALONE, COUPLE_LIVING_ALONE] + mn_msa_assistance_standard: [1_582, 1_582] + # Couple SSI track countable = $1,491 FBR + 0 unearned - $20 = $1,471. + # Supplement = max(0, $1,582 - $1,471) / 2 = $55.50 each. + # Housing add-on (0.5 * $994) goes only to person1 (the eligible spouse). + mn_msa_housing_assistance: [497, 0] + mn_msa_person: [552.50, 55.50] + mn_msa: 608 + +- name: Case 11, non-SSI track recipient with earned income, rep payee, and guardian fee. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 # under $10k non-SSI track cap + mn_msa_uses_representative_payee: true + mn_msa_has_guardian: true + # $2,000/mo earned exceeds the federal SSI cap, so the recipient + # qualifies for MSA via the non-SSI track. Force ssi: 0 explicitly + # to make the test deterministic. + ssi: 0 + employment_income: 24_000 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_assistance_standard: 1_055 + mn_msa_representative_payee_fee: 57 + # Guardian fee: 5% of $2,000 gross monthly income = $100 (at cap). + mn_msa_guardian_fee: 100 + # Non-SSI track countable: $20 disregard hits unearned ($0), so all + # $20 + $65 = $85 plus 1/2 remainder applies to earned. Countable + # earned = ($2,000 - $85) * 0.5 = $957.50. Base supp = $1,055 - $957.50 + # = $97.50; plus $57 payee fee + $100 guardian fee = $254.50. + mn_msa_person: 254.50 + mn_msa: 254.50 + +- name: Case 12, person not lawfully present is ineligible regardless of resources or income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: UNDOCUMENTED + ssi_countable_resources: 500 + ssi: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Not receiving SSI and not citizen/legal immigrant -> immigration test fails. + mn_msa_eligible_person: false + mn_msa_person: 0 + mn_msa: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/mn_msa_housing_assistance_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/mn_msa_housing_assistance_eligible.yaml new file mode 100644 index 00000000000..a824e991268 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/mn_msa_housing_assistance_eligible.yaml @@ -0,0 +1,26 @@ +- name: Case 1, default value is false. + period: 2026-01 + input: + people: + person1: + age: 70 + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_housing_assistance_eligible: false + +- name: Case 2, user-provided true passes through. + period: 2026-01 + input: + people: + person1: + age: 70 + mn_msa_housing_assistance_eligible: true + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_housing_assistance_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/mn_msa_living_arrangement.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/mn_msa_living_arrangement.yaml new file mode 100644 index 00000000000..a77cbbbdb15 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/mn_msa_living_arrangement.yaml @@ -0,0 +1,82 @@ +- name: Case 1, default value is INDIVIDUAL_LIVING_ALONE. + period: 2026-01 + input: + people: + person1: + age: 70 + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_living_arrangement: INDIVIDUAL_LIVING_ALONE + +- name: Case 2, user-provided INDIVIDUAL_LIVING_WITH_OTHERS passes through. + period: 2026-01 + input: + people: + person1: + age: 70 + mn_msa_living_arrangement: INDIVIDUAL_LIVING_WITH_OTHERS + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_living_arrangement: INDIVIDUAL_LIVING_WITH_OTHERS + +- name: Case 3, user-provided COUPLE_LIVING_ALONE passes through. + period: 2026-01 + input: + people: + person1: + age: 70 + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + +- name: Case 4, user-provided MEDICAID_FACILITY passes through. + period: 2026-01 + input: + people: + person1: + age: 80 + mn_msa_living_arrangement: MEDICAID_FACILITY + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_living_arrangement: MEDICAID_FACILITY + +- name: Case 5, user-provided COUPLE_LIVING_WITH_OTHERS passes through. + period: 2026-01 + input: + people: + person1: + age: 70 + mn_msa_living_arrangement: COUPLE_LIVING_WITH_OTHERS + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_living_arrangement: COUPLE_LIVING_WITH_OTHERS + +- name: Case 6, user-provided NONE passes through. + period: 2026-01 + input: + people: + person1: + age: 70 + mn_msa_living_arrangement: NONE + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_living_arrangement: NONE diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/mn_msa_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/mn_msa_person.yaml new file mode 100644 index 00000000000..ad2ae9b4085 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/mn_msa_person.yaml @@ -0,0 +1,558 @@ +- name: Case 1, SSI-track aged person living alone with no countable income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 11_928 # $994/mo + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Need standard $1,055 - max($994 SSI - $20 general, 0) - countable $0 = $81. + mn_msa_person: 81 + +- name: Case 2, non-SSI track aged person with $1,000/mo unearned income living alone. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 5_000 + ssi: 0 + ssi_unearned_income: 12_000 # $1,000/mo + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Standard $1,055 - countable ($1,000 - $20 general) = $1,055 - $980 = $75. + mn_msa_person: 75 + +- name: Case 3, Medicaid facility recipient receives PNA-only state portion. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 200 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + ssi: 360 # $30/mo FLA-D + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Combined PNA standard $132 - federal SSI FBR $30 = $102 state supplement. + mn_msa_person: 102 + +- name: Case 4, SSI couple living alone splits the couple-rate 50/50 across spouses. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_claim_is_joint: true + ssi: 8_946 # $745.50/mo (couple FBR $1,491 / 2) + ssi_earned_income: 0 + ssi_unearned_income: 0 + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_claim_is_joint: true + ssi: 8_946 + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # Per person: $1,582 / 2 = $791 standard - max($745.50 SSI - $20/2, 0) + # = $791 - $735.50 = $55.50. Couple total $111. (P2.1: $20 disregard + # is applied once per couple, allocated half to each spouse.) + mn_msa_person: [55.50, 55.50] + +- name: Case 5, asymmetric eligibility couple — only one spouse SSI-eligible. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + ssi_claim_is_joint: false + ssi: 11_928 # eligible spouse, full FBR + ssi_earned_income: 0 + ssi_unearned_income: 0 + person2: + age: 40 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + ssi_claim_is_joint: false + ssi: 0 # ineligible spouse, not aged/blind/disabled + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # Eligible spouse defaults to INDIVIDUAL_LIVING_ALONE: + # $1,055 - max($994 SSI - $20, 0) = $1,055 - $974 = $81. + # Ineligible spouse zeroed by mn_msa_eligible_person filter. + mn_msa_person: [81, 0] + +- name: Case 6, 2024 individual living alone with SSI receipt. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 11_316 # $943/mo (2024 federal individual FBR) + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # 2024: $1,004 standard - max($943 SSI - $20, 0) = $1,004 - $923 = $81. + mn_msa_person: 81 + +- name: Case 7, single-person marital unit defaults to individual rate. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 11_928 # $994/mo + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Default INDIVIDUAL_LIVING_ALONE: + # $1,055 - max($994 SSI - $20, 0) = $1,055 - $974 = $81. + mn_msa_living_arrangement: INDIVIDUAL_LIVING_ALONE + mn_msa_person: 81 + +- name: Case 8, SSI-track amount uses the federal benefit rate when actual SSI is reduced. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 6_000 # $500/mo actual payment after federal reductions + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # MSA counts the $994 FBR: $1,055 - max($994 - $20, 0) = $81. + mn_msa_person: 81 + +- name: Case 9, housing-assistance eligibility applies the living-alone standard. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + is_blind: false + is_disabled: true + immigration_status: CITIZEN + mn_msa_living_arrangement: INDIVIDUAL_LIVING_WITH_OTHERS + mn_msa_housing_assistance_eligible: true + ssi_countable_resources: 500 + ssi: 11_928 + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Housing assistance switches the base standard from $755.33 to $1,055. + # Base $81 plus housing allowance $497 = $578. + mn_msa_payment_category: INDIVIDUAL_LIVING_ALONE + mn_msa_person: 578 + +- name: Case 10, asymmetric SSI couple — only one spouse has extra unearned income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_claim_is_joint: true + ssi: 8_946 # $745.50/mo (couple FBR / 2) + ssi_earned_income: 0 + ssi_unearned_income: 2_400 # $200/mo to spouse A only + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 800 + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_claim_is_joint: true + ssi: 8_946 + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # Couple-level: SSI couple FBR $1,491 + $200 unearned - $20 disregard = $1,671 countable. + # Standard $1,582 - $1,671 = floored at $0. Bug fix: no over-payment from per-spouse floor. + mn_msa_person: [0, 0] + +- name: Case 11, asymmetric non-SSI couple — only one spouse has earned income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 5_000 + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi: 0 + ssi_earned_income: 12_000 # $1,000/mo to spouse A only + ssi_unearned_income: 0 + person2: + age: 68 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 5_000 + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi: 0 + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1, person2] + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + # Couple earned $1,000 - ($20 + $65) = $915 over flat; disregard = $85 + $915*0.5 = $542.50. + # Couple countable = max($1,000 - $542.50, 0) = $457.50. + # Couple supplement = max($1,582 - $457.50, 0) = $1,124.50, split 50/50 = $562.25 per spouse. + mn_msa_person: [562.25, 562.25] + +- name: Case 12, SSI-track recipient with extra unearned income reduces supplement. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 11_928 # $994/mo SSI + ssi_earned_income: 0 + ssi_unearned_income: 2_400 # $200/mo extra unearned + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Standard $1,055 - max($994 + $200 - $20, 0) = $1,055 - $1,174 = floored at $0. + mn_msa_person: 0 + +- name: Case 13, negative self-employment does not inflate the supplement. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 11_928 # $994/mo SSI + self_employment_income: -12_000_000 # -$1M/mo extreme negative + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Negative earnings must not push supplement above the standard. + # SSI-track countable floors at 0; supplement = $1,055 - max($994 - $20, 0) = $81. + mn_msa_person: 81 + +- name: Case 14, Medicaid facility with non-zero unearned exercises the FLA-D zero-disregard branch. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 200 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + ssi: 360 # $30/mo FLA-D + ssi_unearned_income: 1_200 # $100/mo + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # FLA-D carve-out: disregard = 0 (no $20). Countable = $30 FBR + $100 unearned = $130. + # Standard $132 - $130 = $2 state supplement. + mn_msa_person: 2 + +- name: Case 15, special needs are reduced by income above the basic standard. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 5_000 + mn_msa_uses_representative_payee: true + ssi: 0 + ssi_unearned_income: 13_200 # $1,100/mo; minus $20 general = $1,080 countable + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Combined need standard $1,055 + $57 = $1,112. + # $1,112 - $1,080 countable income = $32. + mn_msa_person: 32 + +- name: Case 16, 2025 individual living alone with SSI receipt. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi: 11_604 # $967/mo for 2025 + ssi_earned_income: 0 + ssi_unearned_income: 0 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # 2025: $1,028 standard - max($967 SSI - $20, 0) = $81. + mn_msa_person: 81 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_assistance_standard.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_assistance_standard.yaml new file mode 100644 index 00000000000..3cd794332eb --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_assistance_standard.yaml @@ -0,0 +1,316 @@ +- name: Case 1, individual living alone in 2026. + period: 2026-01 + input: + people: + person1: + age: 70 + ssi_countable_resources: 500 + ssi: 11_928 + marital_units: + marital_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_assistance_standard: 1_055 + +- name: Case 2, individual living with others in 2026. + period: 2026-01 + input: + people: + person1: + age: 70 + ssi_countable_resources: 500 + mn_msa_living_arrangement: INDIVIDUAL_LIVING_WITH_OTHERS + ssi: 11_928 + marital_units: + marital_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_assistance_standard: 755.33 + +- name: Case 3, couple living alone joint claim in 2026. + period: 2026-01 + input: + people: + person1: + age: 70 + ssi_countable_resources: 800 + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_claim_is_joint: true + ssi: 8_946 + person2: + age: 68 + ssi_countable_resources: 800 + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_claim_is_joint: true + ssi: 8_946 + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + mn_msa_assistance_standard: [1_582, 1_582] + +- name: Case 4, couple living with others joint claim in 2026. + period: 2026-01 + input: + people: + person1: + age: 72 + ssi_countable_resources: 800 + mn_msa_living_arrangement: COUPLE_LIVING_WITH_OTHERS + ssi_claim_is_joint: true + ssi: 8_946 + person2: + age: 70 + ssi_countable_resources: 800 + mn_msa_living_arrangement: COUPLE_LIVING_WITH_OTHERS + ssi_claim_is_joint: true + ssi: 8_946 + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + mn_msa_assistance_standard: [1_058, 1_058] + +- name: Case 5, person in Medicaid facility in 2026. + period: 2026-01 + input: + people: + person1: + age: 80 + ssi_countable_resources: 200 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + ssi: 360 + marital_units: + marital_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_assistance_standard: 132 + +- name: Case 6, NONE arrangement returns zero standard. + period: 2026-01 + input: + people: + person1: + age: 40 + ssi_countable_resources: 500 + mn_msa_living_arrangement: NONE + ssi: 0 + marital_units: + marital_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_assistance_standard: 0 + +- name: Case 7, individual living alone in 2024 uses 2024 rate. + period: 2024-01 + input: + people: + person1: + age: 70 + ssi_countable_resources: 500 + ssi: 11_316 # $943/mo for 2024 + marital_units: + marital_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_assistance_standard: 1_004 + +- name: Case 8, individual living alone in 2011 uses 2011 rate. + period: 2011-01 + input: + people: + person1: + age: 70 + ssi_countable_resources: 500 + ssi: 8_088 # $674/mo 2011 federal individual FBR + marital_units: + marital_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_assistance_standard: 735 + +- name: Case 9, couple living alone in 2011 uses 2011 rate. + period: 2011-01 + input: + people: + person1: + age: 70 + ssi_countable_resources: 500 + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_claim_is_joint: true + person2: + age: 68 + ssi_countable_resources: 500 + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_claim_is_joint: true + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + mn_msa_assistance_standard: [1_102, 1_102] + +- name: Case 10, Medicaid facility in 2011 uses 2011 PNA convention. + period: 2011-01 + input: + people: + person1: + age: 80 + ssi_countable_resources: 200 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + ssi: 360 # $30/mo FLA-D + marital_units: + marital_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_assistance_standard: 89 + +- name: Case 11, individual living alone in 2025. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi_countable_resources: 500 + ssi: 11_604 + marital_units: + marital_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_assistance_standard: 1_028 + +- name: Case 12, individual living with others in 2025. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi_countable_resources: 500 + mn_msa_living_arrangement: INDIVIDUAL_LIVING_WITH_OTHERS + ssi: 11_604 + marital_units: + marital_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_assistance_standard: 737.33 + +- name: Case 13, couple living alone joint claim in 2025. + period: 2025-01 + input: + people: + person1: + age: 70 + ssi_countable_resources: 800 + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_claim_is_joint: true + ssi: 8_700 + person2: + age: 68 + ssi_countable_resources: 800 + mn_msa_living_arrangement: COUPLE_LIVING_ALONE + ssi_claim_is_joint: true + ssi: 8_700 + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + mn_msa_assistance_standard: [1_541, 1_541] + +- name: Case 14, couple living with others joint claim in 2025. + period: 2025-01 + input: + people: + person1: + age: 72 + ssi_countable_resources: 800 + mn_msa_living_arrangement: COUPLE_LIVING_WITH_OTHERS + ssi_claim_is_joint: true + ssi: 8_700 + person2: + age: 70 + ssi_countable_resources: 800 + mn_msa_living_arrangement: COUPLE_LIVING_WITH_OTHERS + ssi_claim_is_joint: true + ssi: 8_700 + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + mn_msa_assistance_standard: [1_030.67, 1_030.67] + +- name: Case 15, person in Medicaid facility in 2025. + period: 2025-01 + input: + people: + person1: + age: 80 + ssi_countable_resources: 200 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + ssi: 360 + marital_units: + marital_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_assistance_standard: 128 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_guardian_fee.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_guardian_fee.yaml new file mode 100644 index 00000000000..f9824946ec7 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_guardian_fee.yaml @@ -0,0 +1,179 @@ +- name: Case 1, guardian fee bound by 5% of gross income (under $100 cap). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_has_guardian: true + ssi_unearned_income: 24_000 # $2,000/mo gross + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # 5% of $2,000 = $100; min($100, $100 cap) = $100. + mn_msa_guardian_fee: 100 + +- name: Case 2, guardian fee bound by $100 hard cap. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_has_guardian: true + ssi_unearned_income: 36_000 # $3,000/mo gross -> 5% = $150 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # min(5% of $3,000 = $150, $100 cap) = $100. + mn_msa_guardian_fee: 100 + +- name: Case 3, guardian fee bound by 5% of low gross income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_has_guardian: true + ssi: 0 + ssi_unearned_income: 12_000 # $1,000/mo -> 5% = $50 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # min(5% of $1,000 = $50, $100 cap) = $50. + mn_msa_guardian_fee: 50 + +- name: Case 4, no guardian (zero fee). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_has_guardian: false + ssi_unearned_income: 24_000 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_guardian_fee: 0 + +- name: Case 5, gross income $1 below $2,000 boundary uses 5%, not the $100 cap. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_has_guardian: true + ssi_unearned_income: 23_988 # $1,999/mo gross -> 5% = $99.95 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # min(5% of $1,999 = $99.95, $100 cap) = $99.95. + mn_msa_guardian_fee: 99.95 + +- name: Case 6, gross income $1 above $2,000 boundary is capped at $100. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_has_guardian: true + ssi_unearned_income: 24_012 # $2,001/mo gross -> 5% = $100.05 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # min(5% of $2,001 = $100.05, $100 cap) = $100. + mn_msa_guardian_fee: 100 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_housing_assistance.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_housing_assistance.yaml new file mode 100644 index 00000000000..01bb5bda0dd --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_housing_assistance.yaml @@ -0,0 +1,88 @@ +- name: Case 1, housing-assistance eligible person receives half of SSI individual FBR in 2026. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + is_blind: false + is_disabled: true + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_housing_assistance_eligible: true + ssi: 11_928 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # 0.5 * $994 (2026 individual FBR) = $497. + mn_msa_housing_assistance: 497 + +- name: Case 2, person not pathway-eligible receives nothing. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + is_blind: false + is_disabled: true + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_housing_assistance_eligible: false + ssi: 11_928 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_housing_assistance: 0 + +- name: Case 3, 2024 housing assistance uses 2024 individual FBR. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + is_blind: false + is_disabled: true + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_housing_assistance_eligible: true + ssi: 11_316 # $943/mo (2024 individual FBR) + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # 0.5 × $943 = $471.50. + mn_msa_housing_assistance: 471.50 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_payment_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_payment_category.yaml new file mode 100644 index 00000000000..950d70c9a8d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_payment_category.yaml @@ -0,0 +1,82 @@ +- name: Case 1, default category mirrors the bare-input default. + period: 2026-01 + input: + people: + person1: + age: 70 + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_payment_category: INDIVIDUAL_LIVING_ALONE + +- name: Case 2, user-provided arrangement passes through when not in a Medicaid facility. + period: 2026-01 + input: + people: + person1: + age: 70 + mn_msa_living_arrangement: INDIVIDUAL_LIVING_WITH_OTHERS + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_payment_category: INDIVIDUAL_LIVING_WITH_OTHERS + +- name: Case 3, federal Medicaid-facility status overrides the input arrangement. + period: 2026-01 + input: + people: + person1: + age: 80 + mn_msa_living_arrangement: INDIVIDUAL_LIVING_ALONE + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_payment_category: MEDICAID_FACILITY + +- name: Case 4, housing-assistance eligibility applies individual living-alone category. + period: 2026-01 + input: + people: + person1: + age: 50 + is_disabled: true + mn_msa_living_arrangement: INDIVIDUAL_LIVING_WITH_OTHERS + mn_msa_housing_assistance_eligible: true + ssi: 11_928 + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_payment_category: INDIVIDUAL_LIVING_ALONE + +- name: Case 5, housing-assistance eligibility applies couple living-alone category. + period: 2026-01 + input: + people: + person1: + age: 70 + mn_msa_living_arrangement: COUPLE_LIVING_WITH_OTHERS + mn_msa_housing_assistance_eligible: true + ssi: 11_928 + person2: + age: 70 + mn_msa_living_arrangement: COUPLE_LIVING_WITH_OTHERS + mn_msa_housing_assistance_eligible: false + marital_units: + marital_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: MN + output: + mn_msa_payment_category: [COUPLE_LIVING_ALONE, COUPLE_LIVING_ALONE] diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_representative_payee_fee.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_representative_payee_fee.yaml new file mode 100644 index 00000000000..f85ffc7970e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_representative_payee_fee.yaml @@ -0,0 +1,55 @@ +- name: Case 1, person using representative payee receives $57 fee in 2026. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_uses_representative_payee: true + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_representative_payee_fee: 57 + +- name: Case 2, person not using representative payee receives nothing. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_uses_representative_payee: false + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_representative_payee_fee: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_special_needs_total.yaml b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_special_needs_total.yaml new file mode 100644 index 00000000000..41df2492f2f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/mn/dhs/msa/payment/mn_msa_special_needs_total.yaml @@ -0,0 +1,184 @@ +- name: Case 1, facility resident receives only representative payee special need. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 80 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi_lives_in_medical_treatment_facility: true + ssi_medicaid_pays_majority_of_care: true + mn_msa_uses_representative_payee: true + mn_msa_has_guardian: true + mn_msa_housing_assistance_eligible: true + ssi: 360 + ssi_unearned_income: 24_000 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Guardian and housing special needs are unavailable in facilities; + # representative payee services remain allowed. + mn_msa_special_needs_total: 57 + +- name: Case 2, community resident receives all modeled ongoing special needs. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_uses_representative_payee: true + mn_msa_has_guardian: true + mn_msa_housing_assistance_eligible: true + ssi_unearned_income: 24_000 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # Representative payee $57 + guardian $100 + housing $497. + mn_msa_special_needs_total: 654 + +- name: Case 3, no special needs returns zero. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + ssi_unearned_income: 12_000 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_special_needs_total: 0 + +- name: Case 4, guardian only (no payee, no housing). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_has_guardian: true + ssi: 11_928 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # 5% × $994 SSI FBR (per CM 0017) = $49.70. + mn_msa_special_needs_total: 49.70 + +- name: Case 5, representative payee only. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_blind: false + is_disabled: false + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_uses_representative_payee: true + ssi: 11_928 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + mn_msa_special_needs_total: 57 + +- name: Case 6, housing assistance only. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 50 + is_blind: false + is_disabled: true + immigration_status: CITIZEN + ssi_countable_resources: 500 + mn_msa_housing_assistance_eligible: true + ssi: 11_928 + marital_units: + marital_unit: + members: [person1] + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: MN + output: + # 0.5 × $994 SSI individual FBR = $497. + mn_msa_special_needs_total: 497 diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_eligible_person.py b/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_eligible_person.py new file mode 100644 index 00000000000..48c83e954c7 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_eligible_person.py @@ -0,0 +1,31 @@ +from policyengine_us.model_api import * + + +class mn_msa_eligible_person(Variable): + value_type = bool + entity = Person + label = "Eligible person for Minnesota Supplemental Aid" + definition_period = MONTH + defined_for = StateCode.MN + reference = ( + "https://www.revisor.mn.gov/statutes/cite/256D.44", + "https://www.house.mn.gov/hrd/pubs/pap_MSA.pdf#page=2", + ) + + def formula(person, period, parameters): + # Per Minn. Stat. § 256D.44 Subd. 1: aged 65+, blind, or 18+ with a + # disability; resource/gross/net income tests; MN resident; citizen + # or qualified noncitizen; in a qualifying living arrangement. + age = person("age", period.this_year) + aged = person("is_ssi_aged", period.this_year) + blind = person("is_blind", period.this_year) + disabled_adult = (age >= 18) & person("is_ssi_disabled", period.this_year) + arrangement = person("mn_msa_payment_category", period) + return ( + (arrangement != arrangement.possible_values.NONE) + & (aged | blind | disabled_adult) + & person("mn_msa_resource_eligible", period) + & person("mn_msa_gross_income_eligible", period) + & person("mn_msa_net_income_eligible", period) + & person("is_citizen_or_legal_immigrant", period.this_year) + ) diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_gross_income_eligible.py b/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_gross_income_eligible.py new file mode 100644 index 00000000000..e13a80161b3 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_gross_income_eligible.py @@ -0,0 +1,43 @@ +from policyengine_us.model_api import * + + +class mn_msa_gross_income_eligible(Variable): + value_type = bool + entity = Person + label = "Minnesota Supplemental Aid gross income eligible" + definition_period = MONTH + defined_for = StateCode.MN + reference = ( + "https://www.dhs.state.mn.us/main/idcplg?IdcService=GET_DYNAMIC_CONVERSION&RevisionSelectionMethod=LatestReleased&dDocName=cm_001906", + "https://www.house.mn.gov/hrd/pubs/pap_MSA.pdf#page=3", + ) + + def formula(person, period, parameters): + # Per CM 0019.06, gross income may not exceed 300% of the federal + # SSI individual benefit rate for an individual or 600% for a couple + # where both spouses are MSA-categorically eligible. Per CM 0017, + # for SSI recipients count the full SSI FBR as gross unearned + # income (even when the actual SSI check is less). + p = parameters(period).gov.states.mn.dhs.msa.eligibility.income_limit + ssi_individual_fbr = parameters(period).gov.ssa.ssi.amount.individual + categorically_eligible = person("is_ssi_aged_blind_disabled", period.this_year) + both_eligible = person.marital_unit.sum(categorically_eligible) == 2 + income = add( + person, + period, + [ + "ssi_earned_income", + "ssi_unearned_income", + "ssi_earned_income_deemed_from_ineligible_spouse", + "ssi_unearned_income_deemed_from_ineligible_spouse", + "ssi_unearned_income_deemed_from_ineligible_parent", + ], + ) + ssi = person("ssi", period) + ssi_fbr = person("ssi_amount_if_eligible", period) + gross = income + where(ssi > 0, ssi_fbr, 0) + au_income = where(both_eligible, person.marital_unit.sum(gross), gross) + cap = ssi_individual_fbr * where( + both_eligible, p.couple_fbr_multiplier, p.individual_fbr_multiplier + ) + return au_income <= cap diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_net_income_eligible.py b/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_net_income_eligible.py new file mode 100644 index 00000000000..7543e4d17a8 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_net_income_eligible.py @@ -0,0 +1,105 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.ssa.ssi.eligibility.income._apply_ssi_exclusions import ( + _apply_ssi_exclusions, +) + + +class mn_msa_net_income_eligible(Variable): + value_type = bool + entity = Person + label = "Minnesota Supplemental Aid net income eligible" + definition_period = MONTH + defined_for = StateCode.MN + reference = ( + "https://www.revisor.mn.gov/statutes/cite/256D.44", + "https://www.dhs.state.mn.us/main/groups/county_access/documents/pub/mndhs-073585.pdf#page=2", + ) + + def formula(person, period, parameters): + # Countable-income logic intentionally duplicates mn_msa_person to + # avoid a defined_for cycle (mn_msa_person is gated on + # mn_msa_eligible_person, which depends on this variable). Keep the + # two formulas in sync when changing income treatment. + # Per House Research Oct 2024 p.3 and CM 0018.18: for SSI recipients, + # MSA's net-income calc counts the full federal SSI FBR as gross + # unearned income and applies only the $20 general disregard + # (federal SSI already consumed the $65 + 1/2 earned disregards). + # Non-SSI track recipients get the standard $20 + $65 + 1/2 + # disregards on actual earned and unearned income. + # FLA-D recipients are exempt from the $20 disregard so the formula + # collapses to FBR + unearned vs PNA. + arrangement = person("mn_msa_payment_category", period) + LA = arrangement.possible_values + is_couple = (arrangement == LA.COUPLE_LIVING_ALONE) | ( + arrangement == LA.COUPLE_LIVING_WITH_OTHERS + ) + is_medicaid_facility = arrangement == LA.MEDICAID_FACILITY + ssi = person("ssi", period) + receives_ssi = ssi > 0 + ssi_fbr = person("ssi_amount_if_eligible", period) + p = parameters(period).gov.ssa.ssi.income.exclusions + disregard = where(is_medicaid_facility, 0, p.general) + raw_unearned = add( + person, + period, + [ + "ssi_unearned_income", + "ssi_unearned_income_deemed_from_ineligible_spouse", + "ssi_unearned_income_deemed_from_ineligible_parent", + ], + ) + + # SSI track: count FBR as unearned, apply $20 once at AU level for + # couples (matches mn_msa_person.py SSI track formula). + couple_ssi_countable = max_( + person.marital_unit.sum(ssi_fbr) + + person.marital_unit.sum(raw_unearned) + - disregard, + 0, + ) + individual_ssi_countable = max_(ssi_fbr + raw_unearned - disregard, 0) + ssi_countable = where(is_couple, couple_ssi_countable, individual_ssi_countable) + + # Non-SSI track: federal $20 + $65 + 1/2 disregards on actual + # earned and unearned. _apply_ssi_exclusions takes annual amounts + # and returns annual countable; convert to monthly. + annual_earned = add( + person, + period.this_year, + [ + "ssi_earned_income", + "ssi_earned_income_deemed_from_ineligible_spouse", + ], + ) + annual_unearned = add( + person, + period.this_year, + [ + "ssi_unearned_income", + "ssi_unearned_income_deemed_from_ineligible_spouse", + "ssi_unearned_income_deemed_from_ineligible_parent", + ], + ) + couple_earned = person.marital_unit.sum(annual_earned) + couple_unearned = person.marital_unit.sum(annual_unearned) + couple_non_ssi_countable = ( + _apply_ssi_exclusions(couple_earned, couple_unearned, parameters, period) + / MONTHS_IN_YEAR + ) + individual_non_ssi_countable = ( + _apply_ssi_exclusions(annual_earned, annual_unearned, parameters, period) + / MONTHS_IN_YEAR + ) + non_ssi_countable = where( + is_couple, couple_non_ssi_countable, individual_non_ssi_countable + ) + + # For couples both ssi_countable and non_ssi_countable are already + # AU-aggregate (computed via marital_unit.sum); the couple standard + # is the AU total, so compare directly. + countable = where(receives_ssi, ssi_countable, non_ssi_countable) + special_needs = person("mn_msa_special_needs_total", period) + need_standard = person("mn_msa_assistance_standard", period) + where( + is_couple, person.marital_unit.sum(special_needs), special_needs + ) + return countable <= need_standard diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_resource_eligible.py b/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_resource_eligible.py new file mode 100644 index 00000000000..6475f145a17 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/eligibility/mn_msa_resource_eligible.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class mn_msa_resource_eligible(Variable): + value_type = bool + entity = Person + label = "Minnesota Supplemental Aid resource eligible" + definition_period = MONTH + defined_for = StateCode.MN + reference = ( + "https://www.revisor.mn.gov/statutes/cite/256P.02", + "https://www.revisor.mn.gov/statutes/cite/256D.425", + "https://www.house.mn.gov/hrd/pubs/pap_MSA.pdf#page=2", + ) + + def formula(person, period, parameters): + # SSI recipients have already passed the federal $2,000/$3,000 + # resource test. Per § 256P.02 Subd. 2 (applied to MSA via + # § 256D.425 Subd. 2(b)), the non-SSI $10,000 cap applies to the + # assistance unit (married couple combined), not per person. + # We use ssi_countable_resources here as a proxy; § 256P.02 Subd. 2(b) + # has a narrower personal-property definition (cash, bank accounts, + # liquid stocks/bonds, non-excluded vehicles, business accounts) but + # we don't track that breakdown at the moment. + p = parameters(period).gov.states.mn.dhs.msa.eligibility + receives_ssi = person("ssi", period) > 0 + countable_resources = person("ssi_countable_resources", period.this_year) + unit_resources = person.marital_unit.sum(countable_resources) + return receives_ssi | (unit_resources <= p.asset_limit.non_ssi_track) diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa.py b/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa.py new file mode 100644 index 00000000000..2bad4d616f8 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class mn_msa(Variable): + value_type = float + entity = SPMUnit + label = "Minnesota Supplemental Aid" + unit = USD + definition_period = MONTH + defined_for = StateCode.MN + reference = "https://www.revisor.mn.gov/statutes/cite/256D.44" + + adds = ["mn_msa_person"] diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_has_guardian.py b/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_has_guardian.py new file mode 100644 index 00000000000..87de43fd885 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_has_guardian.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class mn_msa_has_guardian(Variable): + value_type = bool + entity = Person + label = "Whether the person has a court-appointed guardian or conservator under Minnesota Supplemental Aid" + definition_period = MONTH + defined_for = StateCode.MN + reference = ( + "https://www.revisor.mn.gov/statutes/cite/256D.44", + "https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/mn.html", + ) diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_housing_assistance_eligible.py b/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_housing_assistance_eligible.py new file mode 100644 index 00000000000..bd8db027a41 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_housing_assistance_eligible.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class mn_msa_housing_assistance_eligible(Variable): + value_type = bool + entity = Person + label = "Eligible for the Minnesota Supplemental Aid housing allowance" + definition_period = MONTH + defined_for = StateCode.MN + reference = ( + "https://www.revisor.mn.gov/statutes/cite/256D.44", + "https://www.dhs.state.mn.us/main/idcplg?IdcService=GET_DYNAMIC_CONVERSION&dDocName=cm_002324&RevisionSelectionMethod=LatestReleased", + ) + # TODO: model the § 256D.44 Subd. 5(g) eligibility test in a follow-up + # PR — non-financial pathway (institution-relocation / HCBS-waiver / + # chronic homelessness / housing stabilization), shelter cost > 40% + # of unit gross income, and no concurrent housing subsidy. For now + # this is a bare bool input. + # + # The same follow-up should also model the other two § 256D.44 Subd. 2 + # "living alone" upgrade pathways: HCBS waiver enrollment (CADI / EW / + # BI / CAC / DD per CM 0020.21) and GRH/Housing Support placement + # under § 256I.04 subd. 1a. We don't track HCBS-waiver enrollment or + # Housing Support residency at the moment, so recipients in those + # programs who are classified as "living with others" currently + # receive the lower standard rather than the upgraded "living alone" + # standard the statute requires. diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_living_arrangement.py b/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_living_arrangement.py new file mode 100644 index 00000000000..110809143f1 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_living_arrangement.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class MNMSALivingArrangement(Enum): + INDIVIDUAL_LIVING_ALONE = "Individual living alone" + INDIVIDUAL_LIVING_WITH_OTHERS = "Individual living with others" + COUPLE_LIVING_ALONE = "Couple living alone" + COUPLE_LIVING_WITH_OTHERS = "Couple living with others" + MEDICAID_FACILITY = "Medicaid facility" + NONE = "Not in a qualifying arrangement" + + +class mn_msa_living_arrangement(Variable): + value_type = Enum + entity = Person + label = "Minnesota Supplemental Aid living arrangement" + definition_period = MONTH + defined_for = StateCode.MN + possible_values = MNMSALivingArrangement + # Defaults to INDIVIDUAL_LIVING_ALONE; users modeling persons in shared + # housing, congregate care, or Medicaid facilities should set this + # explicitly. The default is reasonable for single-person households but + # may overstate benefits for elderly persons living with relatives. + default_value = MNMSALivingArrangement.INDIVIDUAL_LIVING_ALONE + reference = ( + "https://www.revisor.mn.gov/statutes/cite/256D.44", + "https://www.dhs.state.mn.us/main/groups/county_access/documents/pub/mndhs-073585.pdf#page=4", + "https://www.house.mn.gov/hrd/pubs/pap_MSA.pdf#page=6", + ) diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_person.py b/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_person.py new file mode 100644 index 00000000000..997a757ec09 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_person.py @@ -0,0 +1,123 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.ssa.ssi.eligibility.income._apply_ssi_exclusions import ( + _apply_ssi_exclusions, +) + + +class mn_msa_person(Variable): + value_type = float + entity = Person + label = "Minnesota Supplemental Aid per-person amount" + unit = USD + definition_period = MONTH + defined_for = "mn_msa_eligible_person" + reference = ( + "https://www.revisor.mn.gov/statutes/cite/256D.44", + "https://www.house.mn.gov/hrd/pubs/pap_MSA.pdf#page=2", + "https://www.dhs.state.mn.us/main/groups/county_access/documents/pub/mndhs-073585.pdf#page=4", + ) + + def formula(person, period, parameters): + # Countable-income logic intentionally duplicates + # mn_msa_net_income_eligible to avoid a defined_for cycle (this + # variable is gated on mn_msa_eligible_person, which depends on + # mn_msa_net_income_eligible). Keep the two formulas in sync when + # changing income treatment. + # MSA inherits federal SSI's $20 / $65 / 1/2 disregards (CM 0018.18). + # The SSI track substitutes the federal SSI FBR for the recipient's + # post-disregard SSI payment so MSA tops up against the FBR rather + # than the federal payment. FLA-D recipients are exempt from the $20 + # general disregard. Couples are computed at the marital unit then + # split 50/50 to avoid wasting disregards on asymmetric income. + arrangement = person("mn_msa_payment_category", period) + LA = arrangement.possible_values + is_couple = (arrangement == LA.COUPLE_LIVING_ALONE) | ( + arrangement == LA.COUPLE_LIVING_WITH_OTHERS + ) + is_medicaid_facility = arrangement == LA.MEDICAID_FACILITY + standard = person("mn_msa_assistance_standard", period) + special_needs = person("mn_msa_special_needs_total", period) + need_standard = standard + special_needs + # Couple income is tested at the assistance-unit level, but modeled + # special needs remain attached to the spouse with the allowance. + couple_special_needs = person.marital_unit.sum(special_needs) + special_needs_share = special_needs / max_(couple_special_needs, 1) + ssi = person("ssi", period) + receives_ssi = ssi > 0 + ssi_fbr = person("ssi_amount_if_eligible", period) + p = parameters(period).gov.ssa.ssi.income.exclusions + raw_unearned = add( + person, + period, + [ + "ssi_unearned_income", + "ssi_unearned_income_deemed_from_ineligible_spouse", + "ssi_unearned_income_deemed_from_ineligible_parent", + ], + ) + disregard = where(is_medicaid_facility, 0, p.general) + + # SSI track: aggregate FBR + unearned at marital unit for couples, + # apply $20 once, then split supplement 50/50. + couple_ssi_countable = max_( + person.marital_unit.sum(ssi_fbr) + + person.marital_unit.sum(raw_unearned) + - disregard, + 0, + ) + couple_ssi_supplement = ( + max_(standard - couple_ssi_countable, 0) / 2 + + max_(couple_special_needs - max_(couple_ssi_countable - standard, 0), 0) + * special_needs_share + ) + individual_ssi_countable = max_(ssi_fbr + raw_unearned - disregard, 0) + individual_ssi_supplement = max_(need_standard - individual_ssi_countable, 0) + ssi_track = where(is_couple, couple_ssi_supplement, individual_ssi_supplement) + + # Non-SSI track: applies federal SSI exclusions ($20 + $65 + 1/2) + # to raw earned and unearned income. Helper accepts annual amounts + # and returns annual countable; convert to monthly to match MSA. + annual_earned = add( + person, + period.this_year, + [ + "ssi_earned_income", + "ssi_earned_income_deemed_from_ineligible_spouse", + ], + ) + annual_unearned = add( + person, + period.this_year, + [ + "ssi_unearned_income", + "ssi_unearned_income_deemed_from_ineligible_spouse", + "ssi_unearned_income_deemed_from_ineligible_parent", + ], + ) + couple_earned = person.marital_unit.sum(annual_earned) + couple_unearned = person.marital_unit.sum(annual_unearned) + couple_non_ssi_countable_annual = _apply_ssi_exclusions( + couple_earned, couple_unearned, parameters, period + ) + individual_non_ssi_countable_annual = _apply_ssi_exclusions( + annual_earned, annual_unearned, parameters, period + ) + couple_non_ssi_countable = couple_non_ssi_countable_annual / MONTHS_IN_YEAR + individual_non_ssi_countable = ( + individual_non_ssi_countable_annual / MONTHS_IN_YEAR + ) + couple_non_ssi_supplement = ( + max_(standard - couple_non_ssi_countable, 0) / 2 + + max_( + couple_special_needs - max_(couple_non_ssi_countable - standard, 0), 0 + ) + * special_needs_share + ) + individual_non_ssi_supplement = max_( + need_standard - individual_non_ssi_countable, 0 + ) + non_ssi_track = where( + is_couple, couple_non_ssi_supplement, individual_non_ssi_supplement + ) + + return where(receives_ssi, ssi_track, non_ssi_track) diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_uses_representative_payee.py b/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_uses_representative_payee.py new file mode 100644 index 00000000000..2ad2c0aa6f5 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/mn_msa_uses_representative_payee.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class mn_msa_uses_representative_payee(Variable): + value_type = bool + entity = Person + label = "Whether the person uses a representative payee under Minnesota Supplemental Aid" + definition_period = MONTH + defined_for = StateCode.MN + reference = ( + "https://www.revisor.mn.gov/statutes/cite/256D.44", + "https://www.dhs.state.mn.us/main/groups/county_access/documents/pub/mndhs-073585.pdf#page=7", + ) diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_assistance_standard.py b/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_assistance_standard.py new file mode 100644 index 00000000000..fae943af1ec --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_assistance_standard.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class mn_msa_assistance_standard(Variable): + value_type = float + entity = Person + label = "Minnesota Supplemental Aid assistance standard" + unit = USD + definition_period = MONTH + defined_for = StateCode.MN + reference = ( + "https://www.revisor.mn.gov/statutes/cite/256D.44", + "https://www.dhs.state.mn.us/main/groups/county_access/documents/pub/mndhs-073585.pdf#page=4", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.mn.dhs.msa.assistance_standard + return p.amount[person("mn_msa_payment_category", period)] diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_guardian_fee.py b/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_guardian_fee.py new file mode 100644 index 00000000000..87d919c7654 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_guardian_fee.py @@ -0,0 +1,41 @@ +from policyengine_us.model_api import * + + +class mn_msa_guardian_fee(Variable): + value_type = float + entity = Person + label = "Minnesota Supplemental Aid guardian or conservator fee allowance" + unit = USD + definition_period = MONTH + defined_for = StateCode.MN + reference = ( + "https://www.revisor.mn.gov/statutes/cite/256D.44", + "https://www.ssa.gov/policy/docs/progdesc/ssi_st_asst/2011/mn.html", + ) + + def formula(person, period, parameters): + # Per Minn. Stat. § 256D.44 Subd. 5(d) and CM 0023.15, the fee + # shall not exceed five percent of the assistance unit's gross + # monthly income up to a maximum of $100 per month. Per CM 0017, + # for SSI recipients count the full SSI FBR as gross unearned + # income (even when the actual SSI check is less). Aggregate to + # the marital unit before applying the cap. + p = parameters(period).gov.states.mn.dhs.msa.special_needs.guardian_fee + has_guardian = person("mn_msa_has_guardian", period) + income = add( + person, + period, + [ + "ssi_earned_income", + "ssi_unearned_income", + "ssi_earned_income_deemed_from_ineligible_spouse", + "ssi_unearned_income_deemed_from_ineligible_spouse", + "ssi_unearned_income_deemed_from_ineligible_parent", + ], + ) + ssi = person("ssi", period) + ssi_fbr = person("ssi_amount_if_eligible", period) + gross = income + where(ssi > 0, ssi_fbr, 0) + unit_gross = person.marital_unit.sum(gross) + unit_fee = min_(unit_gross * p.rate, p.max_amount) + return has_guardian * unit_fee diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_housing_assistance.py b/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_housing_assistance.py new file mode 100644 index 00000000000..c273311329b --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_housing_assistance.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class mn_msa_housing_assistance(Variable): + value_type = float + entity = Person + label = "Minnesota Supplemental Aid housing allowance under § 256D.44 Subd. 5(g)" + unit = USD + definition_period = MONTH + defined_for = StateCode.MN + reference = ( + "https://www.revisor.mn.gov/statutes/cite/256D.44", + "https://www.dhs.state.mn.us/main/idcplg?IdcService=GET_DYNAMIC_CONVERSION&dDocName=cm_002324&RevisionSelectionMethod=LatestReleased", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.mn.dhs.msa.housing_assistance + ssi_fbr = parameters(period).gov.ssa.ssi.amount.individual + eligible = person("mn_msa_housing_assistance_eligible", period) + return eligible * ssi_fbr * p.fbr_multiplier diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_payment_category.py b/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_payment_category.py new file mode 100644 index 00000000000..1dde9b760ed --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_payment_category.py @@ -0,0 +1,62 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.mn.dhs.msa.mn_msa_living_arrangement import ( + MNMSALivingArrangement, +) + + +class mn_msa_payment_category(Variable): + value_type = Enum + entity = Person + label = "Minnesota Supplemental Aid payment category" + definition_period = MONTH + defined_for = StateCode.MN + possible_values = MNMSALivingArrangement + default_value = MNMSALivingArrangement.INDIVIDUAL_LIVING_ALONE + reference = ( + "https://www.revisor.mn.gov/statutes/cite/256D.44", + "https://www.dhs.state.mn.us/main/groups/county_access/documents/pub/mndhs-073585.pdf#page=4", + ) + + def formula(person, period, parameters): + # Recipients in Medicaid-financed institutional care are paid under + # the FLA-D personal-needs cap regardless of reported arrangement. + # Housing-allowance recipients receive the higher living-alone rate. + federal_arrangement = person("ssi_federal_living_arrangement", period.this_year) + federal_values = federal_arrangement.possible_values + in_medicaid_facility = person("is_in_medicaid_facility", period.this_year) | ( + federal_arrangement == federal_values.MEDICAL_TREATMENT_FACILITY + ) + living_arrangement = person("mn_msa_living_arrangement", period) + LA = MNMSALivingArrangement + housing_assistance_eligible = person( + "mn_msa_housing_assistance_eligible", period + ) + is_couple = (living_arrangement == LA.COUPLE_LIVING_ALONE) | ( + living_arrangement == LA.COUPLE_LIVING_WITH_OTHERS + ) + apply_housing_standard = where( + is_couple, + person.marital_unit.any(housing_assistance_eligible), + housing_assistance_eligible, + ) + housing_standard_arrangement = select( + [ + living_arrangement == LA.INDIVIDUAL_LIVING_WITH_OTHERS, + living_arrangement == LA.COUPLE_LIVING_WITH_OTHERS, + ], + [ + LA.INDIVIDUAL_LIVING_ALONE, + LA.COUPLE_LIVING_ALONE, + ], + default=living_arrangement, + ) + community_arrangement = where( + apply_housing_standard, + housing_standard_arrangement, + living_arrangement, + ) + return where( + in_medicaid_facility, + LA.MEDICAID_FACILITY, + community_arrangement, + ) diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_representative_payee_fee.py b/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_representative_payee_fee.py new file mode 100644 index 00000000000..489ae3c7493 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_representative_payee_fee.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class mn_msa_representative_payee_fee(Variable): + value_type = float + entity = Person + label = "Minnesota Supplemental Aid representative payee fee allowance" + unit = USD + definition_period = MONTH + defined_for = StateCode.MN + reference = ( + "https://www.revisor.mn.gov/statutes/cite/256D.44", + "https://www.dhs.state.mn.us/main/groups/county_access/documents/pub/mndhs-073585.pdf#page=7", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.mn.dhs.msa.special_needs + uses_payee = person("mn_msa_uses_representative_payee", period) + return uses_payee * p.representative_payee_fee.amount diff --git a/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_special_needs_total.py b/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_special_needs_total.py new file mode 100644 index 00000000000..8ab21353883 --- /dev/null +++ b/policyengine_us/variables/gov/states/mn/dhs/msa/payment/mn_msa_special_needs_total.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class mn_msa_special_needs_total(Variable): + value_type = float + entity = Person + label = "Minnesota Supplemental Aid total special-needs allowance" + unit = USD + definition_period = MONTH + defined_for = StateCode.MN + reference = ( + "https://www.revisor.mn.gov/statutes/cite/256D.44", + "https://www.dhs.state.mn.us/main/groups/county_access/documents/pub/mndhs-073585.pdf#page=4", + ) + + def formula(person, period, parameters): + # Guardian fee and housing allowance are not paid in Medicaid + # facilities; representative payee fee is paid in all settings. + arrangement = person("mn_msa_payment_category", period) + in_facility = arrangement == arrangement.possible_values.MEDICAID_FACILITY + representative_payee = person("mn_msa_representative_payee_fee", period) + community_special_needs = add( + person, + period, + ["mn_msa_guardian_fee", "mn_msa_housing_assistance"], + ) + return representative_payee + where(in_facility, 0, community_special_needs) 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 4c7705cf267..0da6c4667da 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 @@ -29,6 +29,7 @@ def formula(spm_unit, period, parameters): "wa_ssp", # Washington benefits "mi_ssp", # Michigan benefits "me_ssp", # Maine benefits + "mn_msa", # Minnesota benefits # California programs. "ca_cvrp", # California Clean Vehicle Rebate Project. # Colorado programs.