diff --git a/changelog.d/al-ssi-ssp.added.md b/changelog.d/al-ssi-ssp.added.md new file mode 100644 index 00000000000..249168cd6b3 --- /dev/null +++ b/changelog.d/al-ssi-ssp.added.md @@ -0,0 +1 @@ +Implement Alabama State Supplementary Payment (SSP). diff --git a/policyengine_us/parameters/gov/household/household_state_benefits.yaml b/policyengine_us/parameters/gov/household/household_state_benefits.yaml index b1c0b77dd2e..2dac436bb5f 100644 --- a/policyengine_us/parameters/gov/household/household_state_benefits.yaml +++ b/policyengine_us/parameters/gov/household/household_state_benefits.yaml @@ -19,6 +19,8 @@ values: - ca_la_expectant_parent_payment - ca_capi - ca_state_supplement + # Alabama benefits + - al_ssp # Nebraska benefits - ne_child_care_subsidies # Massachusetts benefits @@ -43,6 +45,8 @@ values: - ca_la_expectant_parent_payment - ca_capi - ca_state_supplement + # Alabama benefits + - al_ssp # Nebraska benefits - ne_child_care_subsidies # North Carolina benefits diff --git a/policyengine_us/parameters/gov/states/al/dhr/ssp/amount.yaml b/policyengine_us/parameters/gov/states/al/dhr/ssp/amount.yaml new file mode 100644 index 00000000000..87a005745da --- /dev/null +++ b/policyengine_us/parameters/gov/states/al/dhr/ssp/amount.yaml @@ -0,0 +1,32 @@ +description: Alabama provides this amount as the monthly supplement under the State Supplementary Payment program. + +metadata: + unit: currency-USD + period: month + label: Alabama SSP supplement amount + breakdown: + - al_ssp_living_arrangement + reference: + - title: Ala. Admin. Code r. 660-2-4-.19a -- Attachment, Special Needs of Applicants and Recipients + href: https://admincode.legislature.state.al.us/api/chapter/660-2-4#page=24 + +FCMP_NURSING_CARE: + 1995-01-01: 100 + +NURSING_CARE: + 1995-01-01: 60 + +IHC_LEVEL_A: + 1995-01-01: 60 + +IHC_LEVEL_B: + 1995-01-01: 56 + +FOSTER_CARE: + 1995-01-01: 110 + +CEREBRAL_PALSY: + 1995-01-01: 196 + +NONE: + 1995-01-01: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ssp/al_ssp.yaml b/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ssp/al_ssp.yaml new file mode 100644 index 00000000000..46565e9be12 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ssp/al_ssp.yaml @@ -0,0 +1,55 @@ +- name: FCMP Nursing Care individual + period: 2025-01 + input: + al_ssp_eligible: true + al_ssp_living_arrangement: FCMP_NURSING_CARE + output: + al_ssp: 100 + +- name: Nursing Care individual + period: 2025-01 + input: + al_ssp_eligible: true + al_ssp_living_arrangement: NURSING_CARE + output: + al_ssp: 60 + +- name: IHC Level A individual + period: 2025-01 + input: + al_ssp_eligible: true + al_ssp_living_arrangement: IHC_LEVEL_A + output: + al_ssp: 60 + +- name: IHC Level B individual + period: 2025-01 + input: + al_ssp_eligible: true + al_ssp_living_arrangement: IHC_LEVEL_B + output: + al_ssp: 56 + +- name: Foster Home Care individual + period: 2025-01 + input: + al_ssp_eligible: true + al_ssp_living_arrangement: FOSTER_CARE + output: + al_ssp: 110 + +- name: Cerebral Palsy individual + period: 2025-01 + input: + al_ssp_eligible: true + al_ssp_living_arrangement: CEREBRAL_PALSY + output: + al_ssp: 196 + +- name: Not eligible + period: 2025-01 + input: + al_ssp_eligible: false + al_ssp_living_arrangement: IHC_LEVEL_A + output: + al_ssp: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ssp/al_ssp_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ssp/al_ssp_eligible.yaml new file mode 100644 index 00000000000..d6257249c36 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ssp/al_ssp_eligible.yaml @@ -0,0 +1,117 @@ +- name: SSI eligible in IHC Level A + period: 2025-01 + input: + is_ssi_eligible: true + uncapped_ssi: 1 + al_ssp_living_arrangement: IHC_LEVEL_A + state_code: AL + output: + al_ssp_eligible: true + +- name: SSI eligible but no qualifying arrangement + period: 2025-01 + input: + is_ssi_eligible: true + al_ssp_living_arrangement: NONE + state_code: AL + output: + al_ssp_eligible: false + +- name: Not SSI eligible in IHC Level B + period: 2025-01 + input: + is_ssi_eligible: false + al_ssp_living_arrangement: IHC_LEVEL_B + state_code: AL + output: + al_ssp_eligible: false + +- name: Not SSI eligible and no arrangement + period: 2025-01 + input: + is_ssi_eligible: false + al_ssp_living_arrangement: NONE + state_code: AL + output: + al_ssp_eligible: false + +- name: SSI eligible in Foster Care + period: 2025-01 + input: + is_ssi_eligible: true + uncapped_ssi: 1 + al_ssp_living_arrangement: FOSTER_CARE + state_code: AL + output: + al_ssp_eligible: true + +- name: SSI eligible in Cerebral Palsy center + period: 2025-01 + input: + is_ssi_eligible: true + uncapped_ssi: 1 + al_ssp_living_arrangement: CEREBRAL_PALSY + state_code: AL + output: + al_ssp_eligible: false + +- name: SSI eligible in FCMP Nursing Care + period: 2025-01 + input: + is_ssi_eligible: true + uncapped_ssi: 1 + al_ssp_living_arrangement: FCMP_NURSING_CARE + state_code: AL + output: + al_ssp_eligible: true + +- name: SSI eligible in Nursing Care + period: 2025-01 + input: + is_ssi_eligible: true + uncapped_ssi: 1 + al_ssp_living_arrangement: NURSING_CARE + state_code: AL + output: + al_ssp_eligible: true + +- name: SSI eligible but income too high to receive SSI + period: 2025-01 + input: + is_ssi_eligible: true + uncapped_ssi: 0 + al_ssp_living_arrangement: IHC_LEVEL_A + state_code: AL + output: + al_ssp_eligible: false + +- name: Grandfathered cerebral palsy recipient remains eligible + period: 2025-01 + input: + is_ssi_eligible: false + uncapped_ssi: 0 + al_ssp_grandfathered: true + al_ssp_living_arrangement: CEREBRAL_PALSY + state_code: AL + output: + al_ssp_eligible: true + +- name: Grandfathered non-SSI recipient remains eligible + period: 2025-01 + input: + is_ssi_eligible: false + uncapped_ssi: 0 + al_ssp_grandfathered: true + al_ssp_living_arrangement: IHC_LEVEL_A + state_code: AL + output: + al_ssp_eligible: true + +- name: Wrong state + period: 2025-01 + input: + is_ssi_eligible: true + al_ssp_living_arrangement: IHC_LEVEL_A + state_code: CO + output: + al_ssp_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ssp/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ssp/integration.yaml new file mode 100644 index 00000000000..9db413e2768 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/al/dhr/ssp/integration.yaml @@ -0,0 +1,413 @@ +- name: Case 1, SSI eligible person in IHC Level A. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_eligible: true + uncapped_ssi: 1 + al_ssp_living_arrangement: IHC_LEVEL_A + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: AL + output: + al_ssp_eligible: [true] + al_ssp: [60] + spm_unit_benefits: 353.58334 + +- name: Case 2, SSI eligible couple in Foster Care. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 68 + is_ssi_eligible: true + uncapped_ssi: 1 + al_ssp_living_arrangement: FOSTER_CARE + person2: + age: 65 + is_ssi_eligible: true + uncapped_ssi: 1 + al_ssp_living_arrangement: FOSTER_CARE + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AL + output: + al_ssp_eligible: [true, true] + al_ssp: [110, 110] + +- name: Case 3, person not SSI eligible receives zero. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + is_ssi_eligible: false + al_ssp_living_arrangement: IHC_LEVEL_A + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: AL + output: + al_ssp_eligible: [false] + al_ssp: [0] + +- name: Case 4, SSI eligible person with no qualifying arrangement. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 55 + is_ssi_eligible: true + al_ssp_living_arrangement: NONE + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: AL + output: + al_ssp_eligible: [false] + al_ssp: [0] + +- name: Case 5, non-grandfathered cerebral palsy case is not eligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 60 + is_ssi_eligible: true + uncapped_ssi: 1 + al_ssp_living_arrangement: CEREBRAL_PALSY + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: AL + output: + al_ssp_eligible: [false] + al_ssp: [0] + +- name: Case 5b, grandfathered cerebral palsy case remains eligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 60 + al_ssp_grandfathered: true + al_ssp_living_arrangement: CEREBRAL_PALSY + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: AL + output: + al_ssp_eligible: [true] + al_ssp: [196] + +- name: Case 6, mixed eligibility couple, one SSI eligible one not. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_eligible: true + uncapped_ssi: 1 + al_ssp_living_arrangement: IHC_LEVEL_A + person2: + age: 65 + is_ssi_eligible: false + al_ssp_living_arrangement: IHC_LEVEL_A + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AL + output: + # person1: SSI eligible + Level A = $60 + # person2: not SSI eligible = $0 + al_ssp_eligible: [true, false] + al_ssp: [60, 0] + +- name: Case 7, mixed living arrangement couple. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_eligible: true + uncapped_ssi: 1 + al_ssp_living_arrangement: FOSTER_CARE + person2: + age: 68 + is_ssi_eligible: true + uncapped_ssi: 1 + al_ssp_living_arrangement: IHC_LEVEL_B + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AL + output: + # person1: Foster Care = $110 + # person2: Level B = $56 + al_ssp_eligible: [true, true] + al_ssp: [110, 56] + +- name: Case 7b, FCMP nursing care uses the $100 payment amount. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_eligible: true + uncapped_ssi: 1 + al_ssp_living_arrangement: FCMP_NURSING_CARE + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: AL + output: + al_ssp_eligible: [true] + al_ssp: [100] + +- name: Case 8, wrong state receives zero. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + is_ssi_eligible: true + uncapped_ssi: 1 + al_ssp_living_arrangement: IHC_LEVEL_A + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: GA + output: + al_ssp_eligible: [false] + al_ssp: [0] + +# Combined Federal SSI + State SSP verification against WorkWorld 2010 data. +# Source: https://help.workworldapp.com/wwwebhelp/ssi_state_supplement_alabama.htm +# 2010 FBR: Individual = $674/month, Couple = $1,011/month. +# ssi is a YEAR variable; at monthly period it auto-divides by 12. + +- name: Case 9, WorkWorld 2010 IHC Level A individual combined $734/month. + period: 2010-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + al_ssp_living_arrangement: IHC_LEVEL_A + tax_units: + tax_unit: + members: [person1] + marital_units: + marital_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: AL + output: + # Federal SSI: $674/month + ssi: [674] + # State SSP: $60/month (Level A) + al_ssp: [60] + # Combined: $674 + $60 = $734/month (matches WorkWorld) + +- name: Case 10, WorkWorld 2010 IHC Level B individual combined $730/month. + period: 2010-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + al_ssp_living_arrangement: IHC_LEVEL_B + tax_units: + tax_unit: + members: [person1] + marital_units: + marital_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: AL + output: + # Federal SSI: $674/month + ssi: [674] + # State SSP: $56/month (Level B) + al_ssp: [56] + # Combined: $674 + $56 = $730/month (matches WorkWorld) + +- name: Case 11, WorkWorld 2010 Foster Care individual combined $784/month. + period: 2010-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + al_ssp_living_arrangement: FOSTER_CARE + tax_units: + tax_unit: + members: [person1] + marital_units: + marital_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: AL + output: + # Federal SSI: $674/month + ssi: [674] + # State SSP: $110/month (Foster Care) + al_ssp: [110] + # Combined: $674 + $110 = $784/month (matches WorkWorld) + +- name: Case 12, WorkWorld 2010 Cerebral Palsy individual combined $870/month. + period: 2010-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + al_ssp_grandfathered: true + al_ssp_living_arrangement: CEREBRAL_PALSY + tax_units: + tax_unit: + members: [person1] + marital_units: + marital_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: AL + output: + # Federal SSI: $674/month + ssi: [674] + # State SSP: $196/month (Cerebral Palsy) + al_ssp: [196] + # Combined: $674 + $196 = $870/month (matches WorkWorld) + +- name: Case 13, WorkWorld 2010 IHC Level A couple combined $1,131/month. + period: 2010-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + al_ssp_living_arrangement: IHC_LEVEL_A + person2: + age: 68 + employment_income: 0 + al_ssp_living_arrangement: IHC_LEVEL_A + tax_units: + tax_unit: + members: [person1, person2] + marital_units: + marital_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AL + output: + # Federal SSI: couple FBR $1,011/month / 2 = $505.50/month each + ssi: [505.50, 505.50] + # State SSP: $60/month each (Level A) + al_ssp: [60, 60] + # Combined: ($505.50 + $60) x 2 = $1,131/month (matches WorkWorld) + +- name: Case 14, WorkWorld 2010 Foster Care couple combined $1,231/month. + period: 2010-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 70 + employment_income: 0 + al_ssp_living_arrangement: FOSTER_CARE + person2: + age: 68 + employment_income: 0 + al_ssp_living_arrangement: FOSTER_CARE + tax_units: + tax_unit: + members: [person1, person2] + marital_units: + marital_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AL + output: + # Federal SSI: couple FBR $1,011/month / 2 = $505.50/month each + ssi: [505.50, 505.50] + # State SSP: $110/month each (Foster Care) + al_ssp: [110, 110] + # Combined: ($505.50 + $110) x 2 = $1,231/month (matches WorkWorld) diff --git a/policyengine_us/variables/gov/states/al/dhr/ssp/al_ssp.py b/policyengine_us/variables/gov/states/al/dhr/ssp/al_ssp.py new file mode 100644 index 00000000000..d7dd89fbddf --- /dev/null +++ b/policyengine_us/variables/gov/states/al/dhr/ssp/al_ssp.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class al_ssp(Variable): + value_type = float + entity = Person + label = "Alabama State Supplementary Payment" + unit = USD + definition_period = MONTH + defined_for = "al_ssp_eligible" + reference = "https://admincode.legislature.state.al.us/api/chapter/660-2-4#page=24" + + def formula(person, period, parameters): + p = parameters(period).gov.states.al.dhr.ssp + living_arrangement = person("al_ssp_living_arrangement", period) + return p.amount[living_arrangement] diff --git a/policyengine_us/variables/gov/states/al/dhr/ssp/al_ssp_eligible.py b/policyengine_us/variables/gov/states/al/dhr/ssp/al_ssp_eligible.py new file mode 100644 index 00000000000..98cd98f1f72 --- /dev/null +++ b/policyengine_us/variables/gov/states/al/dhr/ssp/al_ssp_eligible.py @@ -0,0 +1,30 @@ +from policyengine_us.model_api import * + + +class al_ssp_eligible(Variable): + value_type = bool + entity = Person + label = "Alabama SSP eligible" + definition_period = MONTH + defined_for = StateCode.AL + reference = ( + "https://admincode.legislature.state.al.us/api/chapter/660-2-4#page=9", + "https://help.workworldapp.com/wwwebhelp/ssi_state_supplement_alabama.htm", + ) + + def formula(person, period, parameters): + is_ssi_eligible = person("is_ssi_eligible", period.this_year) + receives_ssi = person("uncapped_ssi", period) > 0 + living_arrangement = person("al_ssp_living_arrangement", period) + grandfathered = person("al_ssp_grandfathered", period) + values = living_arrangement.possible_values + in_qualifying_arrangement = living_arrangement != values.NONE + requires_closed_cohort = living_arrangement == values.CEREBRAL_PALSY + current_ssi_linked_eligibility = ( + is_ssi_eligible + & receives_ssi + & in_qualifying_arrangement + & ~requires_closed_cohort + ) + grandfathered_eligibility = grandfathered & in_qualifying_arrangement + return current_ssi_linked_eligibility | grandfathered_eligibility diff --git a/policyengine_us/variables/gov/states/al/dhr/ssp/al_ssp_grandfathered.py b/policyengine_us/variables/gov/states/al/dhr/ssp/al_ssp_grandfathered.py new file mode 100644 index 00000000000..30e3cdeb886 --- /dev/null +++ b/policyengine_us/variables/gov/states/al/dhr/ssp/al_ssp_grandfathered.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class al_ssp_grandfathered(Variable): + value_type = bool + entity = Person + label = "Alabama SSP grandfathered eligibility override" + definition_period = MONTH + defined_for = StateCode.AL + default_value = False + reference = ( + "https://admincode.legislature.state.al.us/api/chapter/660-2-4#page=9", + "https://admincode.legislature.state.al.us/api/rule/660-2-4-.26", + ) + documentation = """ + Flags people who remain eligible for Alabama supplementation through the + grandfathered non-SSI or closed-cohort rules. This is required for + arrangements such as the cerebral palsy treatment center that are no + longer broadly open to new recipients. + """ diff --git a/policyengine_us/variables/gov/states/al/dhr/ssp/al_ssp_living_arrangement.py b/policyengine_us/variables/gov/states/al/dhr/ssp/al_ssp_living_arrangement.py new file mode 100644 index 00000000000..fa375f27900 --- /dev/null +++ b/policyengine_us/variables/gov/states/al/dhr/ssp/al_ssp_living_arrangement.py @@ -0,0 +1,25 @@ +from policyengine_us.model_api import * + + +class ALSSPLivingArrangement(Enum): + FCMP_NURSING_CARE = "FCMP Nursing Care" + NURSING_CARE = "Nursing Care Supplement" + IHC_LEVEL_A = "Independent Homelife Care, Level A" + IHC_LEVEL_B = "Independent Homelife Care, Level B" + FOSTER_CARE = "Foster Home Care" + CEREBRAL_PALSY = "Cerebral Palsy Treatment Center" + NONE = "Not in a qualifying care arrangement" + + +class al_ssp_living_arrangement(Variable): + value_type = Enum + entity = Person + label = "Alabama SSP living arrangement" + definition_period = MONTH + possible_values = ALSSPLivingArrangement + default_value = ALSSPLivingArrangement.NONE + reference = ( + "https://admincode.legislature.state.al.us/api/chapter/660-2-4#page=9", + "https://admincode.legislature.state.al.us/api/chapter/660-2-4#page=10", + "https://admincode.legislature.state.al.us/api/chapter/660-2-4#page=14", + ) 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 61aac666cbc..e5f8b302f25 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 @@ -12,6 +12,7 @@ def formula(spm_unit, period, parameters): BENEFITS = [ "social_security", "ssi", + "al_ssp", "de_ssp", # Delaware benefits "ma_state_supplement", # Massachusetts benefits # California programs.