diff --git a/changelog.d/fix-ca-mce-net-income-test.fixed.md b/changelog.d/fix-ca-mce-net-income-test.fixed.md new file mode 100644 index 00000000000..123305757c2 --- /dev/null +++ b/changelog.d/fix-ca-mce-net-income-test.fixed.md @@ -0,0 +1,2 @@ +Remove the SNAP net income test from California's broad-based categorical eligibility (CalFresh Modified Categorical Eligibility) for households with and without elderly or disabled members, per CDSS ACLs 12-62, 13-32, 14-56 and 15-42. +Apply California's zero-allotment participation screen to SNAP households of three or more while preserving Modified Categorical Eligibility's net-income waiver and smaller households' minimum allotments. diff --git a/policyengine_us/parameters/gov/hhs/tanf/non_cash/income_limit/net_applies/hheod.yaml b/policyengine_us/parameters/gov/hhs/tanf/non_cash/income_limit/net_applies/hheod.yaml index 85355ff472d..8326c5f22b7 100644 --- a/policyengine_us/parameters/gov/hhs/tanf/non_cash/income_limit/net_applies/hheod.yaml +++ b/policyengine_us/parameters/gov/hhs/tanf/non_cash/income_limit/net_applies/hheod.yaml @@ -5,7 +5,16 @@ AL: AZ: 2015-10-01: false CA: - 2015-10-01: true + # Elderly or disabled households with gross income at or below 200% of the + # poverty line are conferred MCE like any other household, and MCE has no + # net income test (CDSS ACL 13-32 note; ACL 15-42). Those above 200% are + # not MCE and face the regular net income and resource tests instead, + # which gross_hheod.yaml routes them to. + # ACL 11-11 expanded MCE to all non-assistance CalFresh households on + # 2011-02-01. Retain 2015-10-01 as this model's BBCE baseline, matching + # the surrounding California gross, asset, and poverty-year parameters; + # this flag alone does not establish modeled eligibility in 2011. + 2015-10-01: false CO: 2015-10-01: true 2024-07-01: false @@ -104,5 +113,23 @@ metadata: href: https://www.snapscreener.com/?p=table - title: USDA ERS SNAP Policy Database (bbce_elddisinclmt column, Jan 1996 - Dec 2020) href: https://www.ers.usda.gov/data-products/snap-policy-data-sets + - title: CDSS All County Letter 13-32, MCE/BBCE and elderly/disabled CalFresh households + href: https://www.cdss.ca.gov/lettersnotices/EntRes/getinfo/acl/2013/13-32.pdf#page=3 + - title: "CDSS All County Letter 14-56, CalFresh Modified Categorical Eligibility #page 2,4" + href: https://www.cdss.ca.gov/lettersnotices/entres/getinfo/acl/2014/14-56.pdf#page=2 + - title: CDSS All County Letter 14-63, CalFresh households eligible but entitled to no benefits + href: https://www.cdss.ca.gov/lettersnotices/entres/getinfo/acl/2014/14-63.pdf#page=2 + - title: CDSS All County Letter 15-42, MCE gross income limit and income reporting thresholds + href: https://www.cdss.ca.gov/lettersnotices/EntRes/getinfo/acl/2015/15-42.pdf#page=4 + - title: CDSS Manual of Policies and Procedures 63-409.1, requirements for participation + href: https://www.cdss.ca.gov/ord/entres/getinfo/pdf/fsman04b.pdf#page=34 + - title: CDSS June 30, 2014 letter, CalFresh Modified Categorical Eligibility + href: https://www.cdss.ca.gov/lettersnotices/entres/getinfo/coletters/calfreshmodifiedcategoricaleligibility.pdf#page=3 + - title: CDSS All County Letter 11-11, statewide expansion of MCE to all NACF households + href: https://www.cdss.ca.gov/lettersnotices/entres/getinfo/acl/2011/11-11.pdf#page=1 + - title: 7 CFR 273.2(j)(2)(xi), categorical eligibility exemptions + href: https://www.law.cornell.edu/cfr/text/7/273.2#j_2_xi + - title: 7 CFR 273.9(a), income eligibility standards + href: https://www.law.cornell.edu/cfr/text/7/273.9#a breakdown: - state_code diff --git a/policyengine_us/parameters/gov/hhs/tanf/non_cash/income_limit/net_applies/non_hheod.yaml b/policyengine_us/parameters/gov/hhs/tanf/non_cash/income_limit/net_applies/non_hheod.yaml index bd3e7e648b3..84604db8095 100644 --- a/policyengine_us/parameters/gov/hhs/tanf/non_cash/income_limit/net_applies/non_hheod.yaml +++ b/policyengine_us/parameters/gov/hhs/tanf/non_cash/income_limit/net_applies/non_hheod.yaml @@ -5,7 +5,18 @@ AL: AZ: 2015-10-01: false CA: - 2015-10-01: true + # CalFresh Modified Categorical Eligibility (MCE) has no net income test. + # An MCE household of three or more receives the allotment the issuance + # table gives for its net income, even above the net standard, and a + # household of one or two receives the minimum allotment (CDSS ACL 12-62, + # examples 4-5; ACL 14-56; ACL 15-42). Zero-allotment households of three + # or more are denied for that reason, not for failing a net test + # (ACL 14-63). + # ACL 11-11 expanded MCE to all non-assistance CalFresh households on + # 2011-02-01. Retain 2015-10-01 as this model's BBCE baseline, matching + # the surrounding California gross, asset, and poverty-year parameters; + # this flag alone does not establish modeled eligibility in 2011. + 2015-10-01: false CO: 2015-10-01: true 2024-07-01: false @@ -102,5 +113,23 @@ metadata: href: https://www.snapscreener.com/?p=table - title: USDA ERS SNAP Policy Database (bbce_inclmt column, Jan 1996 - Dec 2020) href: https://www.ers.usda.gov/data-products/snap-policy-data-sets + - title: "CDSS All County Letter 12-62, examples of MCE/BBCE households for CalFresh #page 4-5" + href: https://www.cdss.ca.gov/lettersnotices/entres/getinfo/acl/2012/12-62.pdf#page=4 + - title: CDSS All County Letter 14-56, CalFresh Modified Categorical Eligibility + href: https://www.cdss.ca.gov/lettersnotices/entres/getinfo/acl/2014/14-56.pdf#page=4 + - title: CDSS All County Letter 14-63, CalFresh households eligible but entitled to no benefits + href: https://www.cdss.ca.gov/lettersnotices/entres/getinfo/acl/2014/14-63.pdf#page=2 + - title: CDSS All County Letter 15-42, MCE gross income limit and income reporting thresholds + href: https://www.cdss.ca.gov/lettersnotices/EntRes/getinfo/acl/2015/15-42.pdf#page=4 + - title: CDSS Manual of Policies and Procedures 63-409.1, requirements for participation + href: https://www.cdss.ca.gov/ord/entres/getinfo/pdf/fsman04b.pdf#page=34 + - title: CDSS June 30, 2014 letter, CalFresh Modified Categorical Eligibility + href: https://www.cdss.ca.gov/lettersnotices/entres/getinfo/coletters/calfreshmodifiedcategoricaleligibility.pdf#page=3 + - title: CDSS All County Letter 11-11, statewide expansion of MCE to all NACF households + href: https://www.cdss.ca.gov/lettersnotices/entres/getinfo/acl/2011/11-11.pdf#page=1 + - title: 7 CFR 273.2(j)(2)(xi), categorical eligibility exemptions + href: https://www.law.cornell.edu/cfr/text/7/273.2#j_2_xi + - title: 7 CFR 273.9(a), income eligibility standards + href: https://www.law.cornell.edu/cfr/text/7/273.9#a breakdown: - state_code diff --git a/policyengine_us/tests/policy/baseline/gov/hhs/tanf/non_cash/meets_tanf_non_cash_net_income_test.yaml b/policyengine_us/tests/policy/baseline/gov/hhs/tanf/non_cash/meets_tanf_non_cash_net_income_test.yaml index 8b0d0459554..aa355e00676 100644 --- a/policyengine_us/tests/policy/baseline/gov/hhs/tanf/non_cash/meets_tanf_non_cash_net_income_test.yaml +++ b/policyengine_us/tests/policy/baseline/gov/hhs/tanf/non_cash/meets_tanf_non_cash_net_income_test.yaml @@ -1,30 +1,37 @@ -- name: Default household meets California's BBCE net income test (100%). +# California's Modified Categorical Eligibility (MCE) has no net income +# test (CDSS ACL 12-62, ACL 13-32, ACL 14-56, ACL 15-42), so the cases on the +# mechanics of the net standard use Rhode Island, whose BBCE keeps the net +# test for both household types. +- name: Default California household meets the BBCE net income test because MCE has none. period: 2022 output: meets_tanf_non_cash_net_income_test: true -- name: California household with net income exactly at the standard meets the net income test. +- name: Rhode Island household with net income exactly at the standard meets the net income test. period: 2022 input: snap_fpg: 12_000 snap_net_income: 12_000 + state_code: RI output: # Monthly standard is ceil(1.0 x 1,000) = 1,000; net income of 1,000 # per month is exactly at it. meets_tanf_non_cash_net_income_test: true -- name: California household with net income above the standard fails the net income test. +- name: Rhode Island household with net income above the standard fails the net income test. period: 2022 input: snap_fpg: 12_000 snap_net_income: 12_120 + state_code: RI output: # Net income of 1,010 per month exceeds the 1,000 standard. meets_tanf_non_cash_net_income_test: false -- name: California household at the rounded-up whole-dollar standard meets the net income test. +- name: Rhode Island household at the rounded-up whole-dollar standard meets the net income test. period: 2022 input: + state_code: RI # Monthly poverty guideline of 2,220.83 yields a whole-dollar standard # of ceil(2,220.83) = 2,221, so a rounded net income of exactly 2,221 # still passes; a raw ratio comparison (2,221 / 2,220.83 > 1) would @@ -34,7 +41,7 @@ output: meets_tanf_non_cash_net_income_test: true -- name: California nine-person household at the published FY 2026 net standard meets the net income test. +- name: Rhode Island nine-person household at the published FY 2026 net standard meets the net income test. period: 2026-01 input: people: @@ -50,11 +57,11 @@ households: household: members: [person1] - state_code: CA + state_code: RI output: meets_tanf_non_cash_net_income_test: true -- name: California nine-person household just above the FY 2026 net standard fails the net income test. +- name: Rhode Island nine-person household just above the FY 2026 net standard fails the net income test. period: 2026-01 input: people: @@ -70,9 +77,75 @@ # $4,972 under 7 CFR 273.9(a)(3)(ii). Net income of $4,973 is $1 # above it. snap_net_income: 4_973 + households: + household: + members: [person1] + state_code: RI + output: + meets_tanf_non_cash_net_income_test: false + +- name: California MCE household of four above the FY 2026 net standard meets the net income test. + period: 2026-01 + input: + people: + person1: {} + spm_units: + spm_unit: + members: [person1] + snap_unit_size: 4 + is_tanf_non_cash_hheod: false + # $286 above the four-person FY 2026 net standard of $2,680 (CDSS + # ACIN I-46-25, attachment I). + snap_net_income: 2_966 households: household: members: [person1] state_code: CA output: + # An MCE household of three or more gets the issuance-table allotment + # "even if the household's net income exceeds the maximum amount + # allowable" (CDSS ACL 12-62, example 5; ACL 14-56; ACL 15-42). + meets_tanf_non_cash_net_income_test: true + +- name: California MCE elderly or disabled household above the FY 2026 net standard meets the net income test. + period: 2026-01 + input: + people: + person1: {} + spm_units: + spm_unit: + members: [person1] + snap_unit_size: 1 + is_tanf_non_cash_hheod: true + # $486 above the one-person FY 2026 net standard of $1,305 (CDSS + # ACIN I-46-25, attachment I). + snap_net_income: 1_791 + households: + household: + members: [person1] + state_code: CA + output: + # Elderly or disabled households at or below 200% of the poverty line + # are conferred MCE, and MCE households of one or two get the minimum + # allotment even above the net standard (CDSS ACL 13-32, note). + meets_tanf_non_cash_net_income_test: true + +- name: Rhode Island household of four above the FY 2026 net standard fails the net income test. + period: 2026-01 + input: + people: + person1: {} + spm_units: + spm_unit: + members: [person1] + snap_unit_size: 4 + is_tanf_non_cash_hheod: false + snap_net_income: 2_966 + households: + household: + members: [person1] + state_code: RI + output: + # The same household fails where the state's BBCE keeps the net test: + # $2,966 exceeds the four-person FY 2026 standard of $2,680. meets_tanf_non_cash_net_income_test: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ca/cdss/snap/eligibility/ca_snap_meets_allotment_requirement.yaml b/policyengine_us/tests/policy/baseline/gov/states/ca/cdss/snap/eligibility/ca_snap_meets_allotment_requirement.yaml new file mode 100644 index 00000000000..400008a6758 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ca/cdss/snap/eligibility/ca_snap_meets_allotment_requirement.yaml @@ -0,0 +1,1171 @@ +# California MCE has no net-income ceiling for any household size or +# elderly/disabled status (ACL 12-62 examples 4-5; ACL 13-32). ACL 14-56 +# page 6 and ACL 14-63 page 2 deny zero-allotment units of three or more. +# https://www.cdss.ca.gov/lettersnotices/entres/getinfo/acl/2012/12-62.pdf +# https://www.cdss.ca.gov/lettersnotices/entres/getinfo/acl/2013/13-32.pdf +# https://www.cdss.ca.gov/lettersnotices/entres/getinfo/acl/2014/14-56.pdf#page=6 +# https://www.cdss.ca.gov/lettersnotices/entres/getinfo/acl/2014/14-63.pdf#page=2 +# FY2026 maximum/minimum allotments: CDSS ACIN I-46-25 attachment I. +# Each pair holds gross income, size and member eligibility fixed while +# varying only net income. All categorical and member gates are derived. +# Gross inputs floor the model's exact 200%-FPG limit: twice +# ($15,650 + $5,500 x (size - 1))/12. This preserves the existing model's +# exact-ratio convention rather than imposing CDSS chart rounding. +# Expected benefits are hand-calculated as max(minimum, maximum minus +# ceil(30% x net)); minimum is $24 for one/two-person units and $0 otherwise. + +# Net 0 / 2608 gives contributions 0 / 783, +# so maximum $298 yields allotments $298 / $24. +- name: Case 1, California MCE size 1 without elderly or disabled members varies net income at fixed gross income. + period: 2026-01 + input: + people: + person1: &first_member_1 + age: 35 + monthly_age: 35 + immigration_status: CITIZEN + weekly_hours_worked_before_lsr: 40 + is_tax_unit_dependent: false + is_full_time_college_student: false + is_part_time_college_student: false + is_permanently_disabled_veteran: false + person2: + <<: *first_member_1 + spm_units: + spm_unit1: + members: [person1] + snap_gross_income: 2_608 + snap_net_income: 0 + spm_unit2: + members: [person2] + snap_gross_income: 2_608 + snap_net_income: 2_608 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + families: + family1: + members: [person1] + family2: + members: [person2] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + households: + household1: + members: [person1] + state_code: CA + household2: + members: [person2] + state_code: CA + output: + snap_unit_size: [1, 1] + is_snap_excluded_member: [false, false] + is_tanf_non_cash_hheod: [false, false] + snap_gross_test_income: [2_608, 2_608] + meets_tanf_non_cash_gross_income_test: [true, true] + meets_tanf_non_cash_net_income_test: [true, true] + is_tanf_non_cash_eligible: [true, true] + meets_snap_categorical_eligibility: [true, true] + snap_max_allotment: [298, 298] + snap_allotment_before_eligibility: [298, 24] + ca_snap_meets_allotment_requirement: [true, true] + is_snap_eligible: [true, true] + snap_normal_allotment: [298, 24] + snap: [298, 24] + +# Net 0 / 3525 gives contributions 0 / 1058, +# so maximum $546 yields allotments $546 / $24. +- name: Case 2, California MCE size 2 elderly varies net income at fixed gross income. + period: 2026-01 + input: + people: + person1: &first_member_2 + age: 65 + monthly_age: 65 + immigration_status: CITIZEN + weekly_hours_worked_before_lsr: 40 + is_tax_unit_dependent: false + is_full_time_college_student: false + is_part_time_college_student: false + is_permanently_disabled_veteran: false + person2: + <<: *first_member_2 + age: 35 + monthly_age: 35 + person3: + <<: *first_member_2 + person4: + <<: *first_member_2 + age: 35 + monthly_age: 35 + spm_units: + spm_unit1: + members: [person1, person2] + snap_gross_income: 3_525 + snap_net_income: 0 + spm_unit2: + members: [person3, person4] + snap_gross_income: 3_525 + snap_net_income: 3_525 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + tax_unit3: + members: [person3] + tax_unit4: + members: [person4] + families: + family1: + members: [person1] + family2: + members: [person2] + family3: + members: [person3] + family4: + members: [person4] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + marital_unit3: + members: [person3] + marital_unit4: + members: [person4] + households: + household1: + members: [person1, person2] + state_code: CA + household2: + members: [person3, person4] + state_code: CA + output: + snap_unit_size: [2, 2] + is_snap_excluded_member: [false, false, false, false] + is_tanf_non_cash_hheod: [true, true] + snap_gross_test_income: [3_525, 3_525] + meets_tanf_non_cash_gross_income_test: [true, true] + meets_tanf_non_cash_net_income_test: [true, true] + is_tanf_non_cash_eligible: [true, true] + meets_snap_categorical_eligibility: [true, true] + snap_max_allotment: [546, 546] + snap_allotment_before_eligibility: [546, 24] + ca_snap_meets_allotment_requirement: [true, true] + is_snap_eligible: [true, true] + snap_normal_allotment: [546, 24] + snap: [546, 24] + +# Net 2613 / 2614 gives contributions 784 / 785, +# so maximum $785 yields allotments $1 / $0. +- name: Case 3, California MCE size 3 disabled varies net income at fixed gross income. + period: 2026-01 + input: + people: + person1: &first_member_3 + age: 35 + monthly_age: 35 + immigration_status: CITIZEN + weekly_hours_worked_before_lsr: 40 + is_tax_unit_dependent: false + is_full_time_college_student: false + is_part_time_college_student: false + is_permanently_disabled_veteran: true + person2: + <<: *first_member_3 + is_permanently_disabled_veteran: false + person3: + <<: *first_member_3 + is_permanently_disabled_veteran: false + person4: + <<: *first_member_3 + person5: + <<: *first_member_3 + is_permanently_disabled_veteran: false + person6: + <<: *first_member_3 + is_permanently_disabled_veteran: false + spm_units: + spm_unit1: + members: [person1, person2, person3] + snap_gross_income: 4_441 + snap_net_income: 2_613 + spm_unit2: + members: [person4, person5, person6] + snap_gross_income: 4_441 + snap_net_income: 2_614 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + tax_unit3: + members: [person3] + tax_unit4: + members: [person4] + tax_unit5: + members: [person5] + tax_unit6: + members: [person6] + families: + family1: + members: [person1] + family2: + members: [person2] + family3: + members: [person3] + family4: + members: [person4] + family5: + members: [person5] + family6: + members: [person6] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + marital_unit3: + members: [person3] + marital_unit4: + members: [person4] + marital_unit5: + members: [person5] + marital_unit6: + members: [person6] + households: + household1: + members: [person1, person2, person3] + state_code: CA + household2: + members: [person4, person5, person6] + state_code: CA + output: + snap_unit_size: [3, 3] + is_snap_excluded_member: [false, false, false, false, false, false] + is_tanf_non_cash_hheod: [true, true] + snap_gross_test_income: [4_441, 4_441] + meets_tanf_non_cash_gross_income_test: [true, true] + meets_tanf_non_cash_net_income_test: [true, true] + is_tanf_non_cash_eligible: [true, true] + meets_snap_categorical_eligibility: [true, true] + snap_max_allotment: [785, 785] + snap_allotment_before_eligibility: [1, 0] + ca_snap_meets_allotment_requirement: [true, false] + is_snap_eligible: [true, false] + snap_normal_allotment: [1, 0] + snap: [1, 0] + +# Net 3310 / 3311 gives contributions 993 / 994, +# so maximum $994 yields allotments $1 / $0. +- name: Case 4, California MCE size 4 elderly and disabled varies net income at fixed gross income. + period: 2026-01 + input: + people: + person1: &first_member_4 + age: 65 + monthly_age: 65 + immigration_status: CITIZEN + weekly_hours_worked_before_lsr: 40 + is_tax_unit_dependent: false + is_full_time_college_student: false + is_part_time_college_student: false + is_permanently_disabled_veteran: true + person2: + <<: *first_member_4 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person3: + <<: *first_member_4 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person4: + <<: *first_member_4 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person5: + <<: *first_member_4 + person6: + <<: *first_member_4 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person7: + <<: *first_member_4 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person8: + <<: *first_member_4 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + spm_units: + spm_unit1: + members: [person1, person2, person3, person4] + snap_gross_income: 5_358 + snap_net_income: 3_310 + spm_unit2: + members: [person5, person6, person7, person8] + snap_gross_income: 5_358 + snap_net_income: 3_311 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + tax_unit3: + members: [person3] + tax_unit4: + members: [person4] + tax_unit5: + members: [person5] + tax_unit6: + members: [person6] + tax_unit7: + members: [person7] + tax_unit8: + members: [person8] + families: + family1: + members: [person1] + family2: + members: [person2] + family3: + members: [person3] + family4: + members: [person4] + family5: + members: [person5] + family6: + members: [person6] + family7: + members: [person7] + family8: + members: [person8] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + marital_unit3: + members: [person3] + marital_unit4: + members: [person4] + marital_unit5: + members: [person5] + marital_unit6: + members: [person6] + marital_unit7: + members: [person7] + marital_unit8: + members: [person8] + households: + household1: + members: [person1, person2, person3, person4] + state_code: CA + household2: + members: [person5, person6, person7, person8] + state_code: CA + output: + snap_unit_size: [4, 4] + is_snap_excluded_member: [false, false, false, false, false, false, false, false] + is_tanf_non_cash_hheod: [true, true] + snap_gross_test_income: [5_358, 5_358] + meets_tanf_non_cash_gross_income_test: [true, true] + meets_tanf_non_cash_net_income_test: [true, true] + is_tanf_non_cash_eligible: [true, true] + meets_snap_categorical_eligibility: [true, true] + snap_max_allotment: [994, 994] + snap_allotment_before_eligibility: [1, 0] + ca_snap_meets_allotment_requirement: [true, false] + is_snap_eligible: [true, false] + snap_normal_allotment: [1, 0] + snap: [1, 0] + +# Net 3940 / 3941 gives contributions 1182 / 1183, +# so maximum $1183 yields allotments $1 / $0. +- name: Case 5, California MCE size 5 without elderly or disabled members varies net income at fixed gross income. + period: 2026-01 + input: + people: + person1: &first_member_5 + age: 35 + monthly_age: 35 + immigration_status: CITIZEN + weekly_hours_worked_before_lsr: 40 + is_tax_unit_dependent: false + is_full_time_college_student: false + is_part_time_college_student: false + is_permanently_disabled_veteran: false + person2: + <<: *first_member_5 + person3: + <<: *first_member_5 + person4: + <<: *first_member_5 + person5: + <<: *first_member_5 + person6: + <<: *first_member_5 + person7: + <<: *first_member_5 + person8: + <<: *first_member_5 + person9: + <<: *first_member_5 + person10: + <<: *first_member_5 + spm_units: + spm_unit1: + members: [person1, person2, person3, person4, person5] + snap_gross_income: 6_275 + snap_net_income: 3_940 + spm_unit2: + members: [person6, person7, person8, person9, person10] + snap_gross_income: 6_275 + snap_net_income: 3_941 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + tax_unit3: + members: [person3] + tax_unit4: + members: [person4] + tax_unit5: + members: [person5] + tax_unit6: + members: [person6] + tax_unit7: + members: [person7] + tax_unit8: + members: [person8] + tax_unit9: + members: [person9] + tax_unit10: + members: [person10] + families: + family1: + members: [person1] + family2: + members: [person2] + family3: + members: [person3] + family4: + members: [person4] + family5: + members: [person5] + family6: + members: [person6] + family7: + members: [person7] + family8: + members: [person8] + family9: + members: [person9] + family10: + members: [person10] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + marital_unit3: + members: [person3] + marital_unit4: + members: [person4] + marital_unit5: + members: [person5] + marital_unit6: + members: [person6] + marital_unit7: + members: [person7] + marital_unit8: + members: [person8] + marital_unit9: + members: [person9] + marital_unit10: + members: [person10] + households: + household1: + members: [person1, person2, person3, person4, person5] + state_code: CA + household2: + members: [person6, person7, person8, person9, person10] + state_code: CA + output: + snap_unit_size: [5, 5] + is_snap_excluded_member: [false, false, false, false, false, false, false, false, false, false] + is_tanf_non_cash_hheod: [false, false] + snap_gross_test_income: [6_275, 6_275] + meets_tanf_non_cash_gross_income_test: [true, true] + meets_tanf_non_cash_net_income_test: [true, true] + is_tanf_non_cash_eligible: [true, true] + meets_snap_categorical_eligibility: [true, true] + snap_max_allotment: [1_183, 1_183] + snap_allotment_before_eligibility: [1, 0] + ca_snap_meets_allotment_requirement: [true, false] + is_snap_eligible: [true, false] + snap_normal_allotment: [1, 0] + snap: [1, 0] + +# Net 4733 / 4734 gives contributions 1420 / 1421, +# so maximum $1421 yields allotments $1 / $0. +- name: Case 6, California MCE size 6 elderly varies net income at fixed gross income. + period: 2026-01 + input: + people: + person1: &first_member_6 + age: 65 + monthly_age: 65 + immigration_status: CITIZEN + weekly_hours_worked_before_lsr: 40 + is_tax_unit_dependent: false + is_full_time_college_student: false + is_part_time_college_student: false + is_permanently_disabled_veteran: false + person2: + <<: *first_member_6 + age: 35 + monthly_age: 35 + person3: + <<: *first_member_6 + age: 35 + monthly_age: 35 + person4: + <<: *first_member_6 + age: 35 + monthly_age: 35 + person5: + <<: *first_member_6 + age: 35 + monthly_age: 35 + person6: + <<: *first_member_6 + age: 35 + monthly_age: 35 + person7: + <<: *first_member_6 + person8: + <<: *first_member_6 + age: 35 + monthly_age: 35 + person9: + <<: *first_member_6 + age: 35 + monthly_age: 35 + person10: + <<: *first_member_6 + age: 35 + monthly_age: 35 + person11: + <<: *first_member_6 + age: 35 + monthly_age: 35 + person12: + <<: *first_member_6 + age: 35 + monthly_age: 35 + spm_units: + spm_unit1: + members: [person1, person2, person3, person4, person5, person6] + snap_gross_income: 7_191 + snap_net_income: 4_733 + spm_unit2: + members: [person7, person8, person9, person10, person11, person12] + snap_gross_income: 7_191 + snap_net_income: 4_734 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + tax_unit3: + members: [person3] + tax_unit4: + members: [person4] + tax_unit5: + members: [person5] + tax_unit6: + members: [person6] + tax_unit7: + members: [person7] + tax_unit8: + members: [person8] + tax_unit9: + members: [person9] + tax_unit10: + members: [person10] + tax_unit11: + members: [person11] + tax_unit12: + members: [person12] + families: + family1: + members: [person1] + family2: + members: [person2] + family3: + members: [person3] + family4: + members: [person4] + family5: + members: [person5] + family6: + members: [person6] + family7: + members: [person7] + family8: + members: [person8] + family9: + members: [person9] + family10: + members: [person10] + family11: + members: [person11] + family12: + members: [person12] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + marital_unit3: + members: [person3] + marital_unit4: + members: [person4] + marital_unit5: + members: [person5] + marital_unit6: + members: [person6] + marital_unit7: + members: [person7] + marital_unit8: + members: [person8] + marital_unit9: + members: [person9] + marital_unit10: + members: [person10] + marital_unit11: + members: [person11] + marital_unit12: + members: [person12] + households: + household1: + members: [person1, person2, person3, person4, person5, person6] + state_code: CA + household2: + members: [person7, person8, person9, person10, person11, person12] + state_code: CA + output: + snap_unit_size: [6, 6] + is_snap_excluded_member: [false, false, false, false, false, false, false, false, false, false, false, false] + is_tanf_non_cash_hheod: [true, true] + snap_gross_test_income: [7_191, 7_191] + meets_tanf_non_cash_gross_income_test: [true, true] + meets_tanf_non_cash_net_income_test: [true, true] + is_tanf_non_cash_eligible: [true, true] + meets_snap_categorical_eligibility: [true, true] + snap_max_allotment: [1_421, 1_421] + snap_allotment_before_eligibility: [1, 0] + ca_snap_meets_allotment_requirement: [true, false] + is_snap_eligible: [true, false] + snap_normal_allotment: [1, 0] + snap: [1, 0] + +# Net 5233 / 5234 gives contributions 1570 / 1571, +# so maximum $1571 yields allotments $1 / $0. +- name: Case 7, California MCE size 7 disabled varies net income at fixed gross income. + period: 2026-01 + input: + people: + person1: &first_member_7 + age: 35 + monthly_age: 35 + immigration_status: CITIZEN + weekly_hours_worked_before_lsr: 40 + is_tax_unit_dependent: false + is_full_time_college_student: false + is_part_time_college_student: false + is_permanently_disabled_veteran: true + person2: + <<: *first_member_7 + is_permanently_disabled_veteran: false + person3: + <<: *first_member_7 + is_permanently_disabled_veteran: false + person4: + <<: *first_member_7 + is_permanently_disabled_veteran: false + person5: + <<: *first_member_7 + is_permanently_disabled_veteran: false + person6: + <<: *first_member_7 + is_permanently_disabled_veteran: false + person7: + <<: *first_member_7 + is_permanently_disabled_veteran: false + person8: + <<: *first_member_7 + person9: + <<: *first_member_7 + is_permanently_disabled_veteran: false + person10: + <<: *first_member_7 + is_permanently_disabled_veteran: false + person11: + <<: *first_member_7 + is_permanently_disabled_veteran: false + person12: + <<: *first_member_7 + is_permanently_disabled_veteran: false + person13: + <<: *first_member_7 + is_permanently_disabled_veteran: false + person14: + <<: *first_member_7 + is_permanently_disabled_veteran: false + spm_units: + spm_unit1: + members: [person1, person2, person3, person4, person5, person6, person7] + snap_gross_income: 8_108 + snap_net_income: 5_233 + spm_unit2: + members: [person8, person9, person10, person11, person12, person13, person14] + snap_gross_income: 8_108 + snap_net_income: 5_234 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + tax_unit3: + members: [person3] + tax_unit4: + members: [person4] + tax_unit5: + members: [person5] + tax_unit6: + members: [person6] + tax_unit7: + members: [person7] + tax_unit8: + members: [person8] + tax_unit9: + members: [person9] + tax_unit10: + members: [person10] + tax_unit11: + members: [person11] + tax_unit12: + members: [person12] + tax_unit13: + members: [person13] + tax_unit14: + members: [person14] + families: + family1: + members: [person1] + family2: + members: [person2] + family3: + members: [person3] + family4: + members: [person4] + family5: + members: [person5] + family6: + members: [person6] + family7: + members: [person7] + family8: + members: [person8] + family9: + members: [person9] + family10: + members: [person10] + family11: + members: [person11] + family12: + members: [person12] + family13: + members: [person13] + family14: + members: [person14] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + marital_unit3: + members: [person3] + marital_unit4: + members: [person4] + marital_unit5: + members: [person5] + marital_unit6: + members: [person6] + marital_unit7: + members: [person7] + marital_unit8: + members: [person8] + marital_unit9: + members: [person9] + marital_unit10: + members: [person10] + marital_unit11: + members: [person11] + marital_unit12: + members: [person12] + marital_unit13: + members: [person13] + marital_unit14: + members: [person14] + households: + household1: + members: [person1, person2, person3, person4, person5, person6, person7] + state_code: CA + household2: + members: [person8, person9, person10, person11, person12, person13, person14] + state_code: CA + output: + snap_unit_size: [7, 7] + is_snap_excluded_member: [false, false, false, false, false, false, false, false, false, false, false, false, false, false] + is_tanf_non_cash_hheod: [true, true] + snap_gross_test_income: [8_108, 8_108] + meets_tanf_non_cash_gross_income_test: [true, true] + meets_tanf_non_cash_net_income_test: [true, true] + is_tanf_non_cash_eligible: [true, true] + meets_snap_categorical_eligibility: [true, true] + snap_max_allotment: [1_571, 1_571] + snap_allotment_before_eligibility: [1, 0] + ca_snap_meets_allotment_requirement: [true, false] + is_snap_eligible: [true, false] + snap_normal_allotment: [1, 0] + snap: [1, 0] + +# Net 5960 / 5961 gives contributions 1788 / 1789, +# so maximum $1789 yields allotments $1 / $0. +- name: Case 8, California MCE size 8 elderly and disabled varies net income at fixed gross income. + period: 2026-01 + input: + people: + person1: &first_member_8 + age: 65 + monthly_age: 65 + immigration_status: CITIZEN + weekly_hours_worked_before_lsr: 40 + is_tax_unit_dependent: false + is_full_time_college_student: false + is_part_time_college_student: false + is_permanently_disabled_veteran: true + person2: + <<: *first_member_8 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person3: + <<: *first_member_8 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person4: + <<: *first_member_8 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person5: + <<: *first_member_8 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person6: + <<: *first_member_8 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person7: + <<: *first_member_8 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person8: + <<: *first_member_8 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person9: + <<: *first_member_8 + person10: + <<: *first_member_8 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person11: + <<: *first_member_8 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person12: + <<: *first_member_8 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person13: + <<: *first_member_8 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person14: + <<: *first_member_8 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person15: + <<: *first_member_8 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + person16: + <<: *first_member_8 + age: 35 + monthly_age: 35 + is_permanently_disabled_veteran: false + spm_units: + spm_unit1: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + snap_gross_income: 9_025 + snap_net_income: 5_960 + spm_unit2: + members: [person9, person10, person11, person12, person13, person14, person15, person16] + snap_gross_income: 9_025 + snap_net_income: 5_961 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + tax_unit3: + members: [person3] + tax_unit4: + members: [person4] + tax_unit5: + members: [person5] + tax_unit6: + members: [person6] + tax_unit7: + members: [person7] + tax_unit8: + members: [person8] + tax_unit9: + members: [person9] + tax_unit10: + members: [person10] + tax_unit11: + members: [person11] + tax_unit12: + members: [person12] + tax_unit13: + members: [person13] + tax_unit14: + members: [person14] + tax_unit15: + members: [person15] + tax_unit16: + members: [person16] + families: + family1: + members: [person1] + family2: + members: [person2] + family3: + members: [person3] + family4: + members: [person4] + family5: + members: [person5] + family6: + members: [person6] + family7: + members: [person7] + family8: + members: [person8] + family9: + members: [person9] + family10: + members: [person10] + family11: + members: [person11] + family12: + members: [person12] + family13: + members: [person13] + family14: + members: [person14] + family15: + members: [person15] + family16: + members: [person16] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + marital_unit3: + members: [person3] + marital_unit4: + members: [person4] + marital_unit5: + members: [person5] + marital_unit6: + members: [person6] + marital_unit7: + members: [person7] + marital_unit8: + members: [person8] + marital_unit9: + members: [person9] + marital_unit10: + members: [person10] + marital_unit11: + members: [person11] + marital_unit12: + members: [person12] + marital_unit13: + members: [person13] + marital_unit14: + members: [person14] + marital_unit15: + members: [person15] + marital_unit16: + members: [person16] + households: + household1: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: CA + household2: + members: [person9, person10, person11, person12, person13, person14, person15, person16] + state_code: CA + output: + snap_unit_size: [8, 8] + is_snap_excluded_member: [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] + is_tanf_non_cash_hheod: [true, true] + snap_gross_test_income: [9_025, 9_025] + meets_tanf_non_cash_gross_income_test: [true, true] + meets_tanf_non_cash_net_income_test: [true, true] + is_tanf_non_cash_eligible: [true, true] + meets_snap_categorical_eligibility: [true, true] + snap_max_allotment: [1_789, 1_789] + snap_allotment_before_eligibility: [1, 0] + ca_snap_meets_allotment_requirement: [true, false] + is_snap_eligible: [true, false] + snap_normal_allotment: [1, 0] + snap: [1, 0] + +# Net 2613 / 2614 gives contributions 784 / 785, +# so maximum $785 yields allotments $1 / $0. +- name: Case 9, Washington keeps categorical eligibility for a zero allotment outside California. + period: 2026-01 + input: + people: + person1: &first_member_9 + age: 35 + monthly_age: 35 + immigration_status: CITIZEN + weekly_hours_worked_before_lsr: 40 + is_tax_unit_dependent: false + is_full_time_college_student: false + is_part_time_college_student: false + is_permanently_disabled_veteran: false + person2: + <<: *first_member_9 + person3: + <<: *first_member_9 + person4: + <<: *first_member_9 + person5: + <<: *first_member_9 + person6: + <<: *first_member_9 + spm_units: + spm_unit1: + members: [person1, person2, person3] + snap_gross_income: 4_441 + snap_net_income: 2_613 + spm_unit2: + members: [person4, person5, person6] + snap_gross_income: 4_441 + snap_net_income: 2_614 + tax_units: + tax_unit1: + members: [person1] + tax_unit2: + members: [person2] + tax_unit3: + members: [person3] + tax_unit4: + members: [person4] + tax_unit5: + members: [person5] + tax_unit6: + members: [person6] + families: + family1: + members: [person1] + family2: + members: [person2] + family3: + members: [person3] + family4: + members: [person4] + family5: + members: [person5] + family6: + members: [person6] + marital_units: + marital_unit1: + members: [person1] + marital_unit2: + members: [person2] + marital_unit3: + members: [person3] + marital_unit4: + members: [person4] + marital_unit5: + members: [person5] + marital_unit6: + members: [person6] + households: + household1: + members: [person1, person2, person3] + state_code: WA + household2: + members: [person4, person5, person6] + state_code: WA + output: + snap_unit_size: [3, 3] + is_snap_excluded_member: [false, false, false, false, false, false] + is_tanf_non_cash_hheod: [false, false] + snap_gross_test_income: [4_441, 4_441] + meets_tanf_non_cash_gross_income_test: [true, true] + meets_tanf_non_cash_net_income_test: [true, true] + is_tanf_non_cash_eligible: [true, true] + meets_snap_categorical_eligibility: [true, true] + snap_max_allotment: [785, 785] + snap_allotment_before_eligibility: [1, 0] + ca_snap_meets_allotment_requirement: [true, true] + is_snap_eligible: [true, true] + snap_normal_allotment: [1, 0] + snap: [1, 0] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ca/cpuc/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ca/cpuc/integration.yaml index 105d8987278..a8235711b17 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ca/cpuc/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ca/cpuc/integration.yaml @@ -177,6 +177,9 @@ person1: age: 40 employment_income: 30_000 + # Establish the worker exemption independently of the YAML runner's + # treatment of employment_income versus employment_income_before_lsr. + weekly_hours_worked_before_lsr: 30 spm_units: unit: members: [person1] @@ -190,6 +193,10 @@ ca_care_categorically_eligible: false tenant_pays_utilities: false output: + # Countable income is $30,000 in annual wages. The three $23 SNAP + # minimum allotments in October, November, and December are excluded under + # 7 USC 2017(b): $30,000 + $0 counted SNAP = $30,000. + snap: 69 ca_cpuc_countable_income: 30_000 ca_care_income_eligible: true # The model's CARE gate treats a household with utilities included in diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/is_snap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/is_snap_eligible.yaml index ae8049266a2..da444bde668 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/is_snap_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/eligibility/is_snap_eligible.yaml @@ -223,3 +223,631 @@ snap_unit_size: 0 is_snap_eligible: false snap: 0 + +# California Modified Categorical Eligibility (MCE) in FY 2026. CDSS ACIN +# I-46-25, attachment I: net standard (100% of poverty) $1,305 for one person +# and $2,680 for four; MCE gross standard (200%) $2,610 and $5,360; regular +# gross standard (130%) $3,483 for four; maximum allotment $298 and $994; +# standard deduction $209 (1-3 people) and $223 (4); minimum allotment $24. +# The original cases have no housing costs, so their excess shelter deduction +# is zero at these incomes whichever utility allowance applies. +- name: Case 12, California MCE household of four above the net standard is eligible for the issuance-table allotment. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 35 + employment_income: 48_000 + weekly_hours_worked_before_lsr: 40 + person2: + age: 33 + person3: + age: 8 + person4: + age: 4 + spm_units: + spm_unit1: + members: [person1, person2, person3, person4] + housing_cost: 0 + tax_units: + tax_unit1: + members: [person1, person2, person3, person4] + households: + household1: + members: [person1, person2, person3, person4] + state_code: CA + output: + # Gross $4,000 is above the regular $3,483 but within the $5,360 MCE + # standard, so MCE is conferred. + meets_snap_gross_income_test: false + is_tanf_non_cash_eligible: true + # Net $4,000 - 20% earned income deduction ($800) - $223 = $2,977, above + # the $2,680 net standard. + snap_net_income: 2_977 + meets_snap_net_income_test: false + # MCE households of three or more get the issuance-table allotment "even + # if the household's net income exceeds the maximum amount allowable" + # (CDSS ACL 12-62, example 5; ACL 14-56; ACL 15-42). + meets_snap_categorical_eligibility: true + is_snap_eligible: true + # $994 - ceil(30% x $2,977 = $893.10) = $994 - $894. + snap: 100 + +- name: Case 13, California MCE elderly person above the net standard is eligible for the minimum allotment. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 65 + social_security: 24_000 + # The 2026 standard Medicare Part B premium, $202.90 a month. + health_insurance_premiums: 2_434.8 + spm_units: + spm_unit1: + members: [person1] + housing_cost: 0 + tax_units: + tax_unit1: + members: [person1] + households: + household1: + members: [person1] + state_code: CA + output: + # Gross $2,000 is within the $2,610 MCE standard, and elderly or + # disabled households at or below 200% of poverty are conferred MCE + # (CDSS ACL 13-32). + is_tanf_non_cash_eligible: true + # Net $2,000 - $209 - ($202.90 - $35 excess medical) = $1,623.10, + # rounded to $1,623, above the $1,305 net standard. + snap_net_income: 1_623 + meets_snap_net_income_test: false + # Actual medical deduction $202.90 - $35 = $167.90 exceeds the $150 + # standard medical deduction. With no rent, SUA $663 is below half of + # pre-shelter income ($811.55), so the shelter deduction is zero. + snap_excess_medical_expense_deduction: 167.90 + snap_excess_shelter_expense_deduction: 0 + # MCE households of one or two get the minimum allotment even above the + # net standard (CDSS ACL 13-32, note; ACL 12-62, example 4). + meets_snap_categorical_eligibility: true + is_snap_eligible: true + # $298 - ceil(30% x $1,623 = $486.90) = $298 - $487 = -$189, + # raised to the $24 minimum. + snap: 24 + +- name: Case 14, California elderly person above 200% of poverty is not MCE and fails the net standard. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 65 + social_security: 32_400 + # The 2026 standard Medicare Part B premium, $202.90 a month. + health_insurance_premiums: 2_434.8 + spm_units: + spm_unit1: + members: [person1] + housing_cost: 0 + tax_units: + tax_unit1: + members: [person1] + households: + household1: + members: [person1] + state_code: CA + output: + # Gross $2,700 exceeds the $2,610 MCE standard, so MCE is not conferred + # and the household must be net income eligible (CDSS ACL 13-32, + # example 2): net $2,700 - $209 - $167.90 = $2,323.10, rounded to + # $2,323, exceeds $1,305. + is_tanf_non_cash_eligible: false + snap_net_income: 2_323 + meets_snap_net_income_test: false + is_snap_eligible: false + snap: 0 + +- name: Case 15, California household of four above 200% of poverty is not MCE and fails the gross standard. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 35 + employment_income: 66_000 + weekly_hours_worked_before_lsr: 40 + person2: + age: 33 + person3: + age: 8 + person4: + age: 4 + spm_units: + spm_unit1: + members: [person1, person2, person3, person4] + housing_cost: 0 + tax_units: + tax_unit1: + members: [person1, person2, person3, person4] + households: + household1: + members: [person1, person2, person3, person4] + state_code: CA + output: + # Gross $5,500 exceeds the $5,360 MCE standard, so MCE is not conferred + # and the $3,483 regular gross standard applies (CDSS ACL 14-56, + # example 2). + is_tanf_non_cash_eligible: false + meets_snap_gross_income_test: false + is_snap_eligible: false + snap: 0 + +- name: Case 16, California MCE household of four with rent and no utility allowance receives SNAP above the net standard. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 45_000 + weekly_hours_worked_before_lsr: 40 + person2: + age: 33 + person3: + age: 8 + person4: + age: 4 + spm_units: + spm_unit1: + members: [person1, person2, person3, person4] + housing_cost: 10_200 + # Isolate MCE from the separate federal heat-and-eat change. The + # household has no utility costs and this case assumes no allowance. + snap_utility_allowance: 0 + tax_units: + tax_unit1: + members: [person1, person2, person3, person4] + households: + household1: + members: [person1, person2, person3, person4] + state_code: CA + output: + # Monthly wages $45,000 / 12 = $3,750 are within the $5,360 MCE ceiling. + snap_gross_income: 3_750 + is_tanf_non_cash_eligible: true + # Net before shelter: $3,750 - 20% x $3,750 - $223 = $2,777. + snap_earned_income_deduction: 750 + snap_standard_deduction: 223 + snap_net_income_pre_shelter: 2_777 + # Rent $10,200 / 12 = $850 is below half-net $1,388.50, with no SUA. + snap_excess_shelter_expense_deduction: 0 + snap_net_income: 2_777 + meets_snap_net_income_test: false + # CDSS June 30, 2014 MCE letter, page 3: households of three or more + # receive their issuance-table allotment even above the net standard. + meets_snap_categorical_eligibility: true + is_snap_eligible: true + # $994 - ceil(30% x $2,777 = $833.10) = $994 - $834 = $160. + snap: 160 + +# CPUC June 2026-May 2027 income tables: CARE $54,640 and FERA $68,300 +# for three people. https://www.cpuc.ca.gov/industries-and-topics/electrical-energy/electric-costs/care-fera-program +# CARE counts both earners: $40,000 + $20,000 = $60,000 > $54,640. +# SNAP excludes the under-18 K-12 student's wages (7 USC 2014(d)(7)): +# https://www.law.cornell.edu/uscode/text/7/2014#d_7 +# CDSS FY2026 table, attachment I: MCE gross $4,442, net standard $2,221, +# standard deduction $209, maximum allotment $785. +# https://www.cdss.ca.gov/Portals/9/Additional-Resources/Letters-and-Notices/ACINs/2025/I-46_25.pdf#page=7 +# SNAP gross $40,000 / 12 = $3,333.33 < $4,442; net rounds from +# $3,333.33 - $666.67 earned deduction - $209 = $2,457.67 to $2,458. +# $2,458 > $2,221, but MCE waives the net test; $785 - ceil($737.40) = $47. +# On main (static comparison), the required net test denies SNAP throughout +# 2026, so CARE categorical/overall eligibility are false and FERA is true. +# With this waiver, SNAP alone confers CARE, which excludes FERA. No rent +# also keeps main's default utility allowance from lowering the annual net +# income enough to confer CARE through SNAP in another month. +# Use calendar-year inputs for wages and CARE, and assert June SNAP explicitly. +- name: Case 17, California MCE SNAP receipt alone confers CARE above its income limit and excludes FERA. + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 40_000 + weekly_hours_worked_before_lsr: 40 + medicaid_enrolled: false + wic: 0 + receives_wic: false + ssi: 0 + receives_ssi: false + person2: + age: 16 + is_in_k12_school: true + employment_income: 20_000 + medicaid_enrolled: false + wic: 0 + receives_wic: false + ssi: 0 + receives_ssi: false + person3: + age: 14 + medicaid_enrolled: false + wic: 0 + receives_wic: false + ssi: 0 + receives_ssi: false + spm_units: + spm_unit1: + members: [person1, person2, person3] + housing_cost: 0 + snap_utility_allowance: 0 + receives_snap: false + tanf: 0 + receives_tanf: false + tax_units: + tax_unit1: + members: [person1, person2, person3] + households: + household1: + members: [person1, person2, person3] + state_code: CA + is_on_tribal_land: false + output: + snap_gross_income: + 2026-06: 3_333.33 + meets_snap_gross_income_test: + 2026-06: false + is_tanf_non_cash_eligible: + 2026-06: true + snap_net_income: + 2026-06: 2_458 + meets_snap_net_income_test: + 2026-06: false + meets_snap_categorical_eligibility: + 2026-06: true + is_snap_eligible: + 2026-06: true + snap: + 2026-06: 47 + ca_cpuc_countable_income: 60_000 + ca_care_income_eligible: false + ca_care_categorically_eligible: true + ca_care_eligible: true + ca_fera_eligible: false + +# ACL 14-56 p. 6 and ACL 14-63 p. 2: deny zero allotments for 3+; +# retain the minimum for 1-2. FY2026 CDSS maximums: $785 (3), $994 (4). +# Wages $42,330/12 x 80% minus $209 = $2,613; +# maximum minus ceil(30% x net) = $1. A $1 ongoing allotment is issued. +- name: Case 18, California MCE household of 3 with net income 2_613 has a 1 dollar allotment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 42_330 + weekly_hours_worked_before_lsr: 40 + person2: + age: 8 + person3: + age: 8 + spm_units: + spm_unit1: + members: + - person1 + - person2 + - person3 + housing_cost: 0 + snap_utility_allowance: 0 + tax_units: + tax_unit1: + members: + - person1 + - person2 + - person3 + households: + household1: + members: + - person1 + - person2 + - person3 + state_code: CA + output: + snap_net_income: 2_613 + meets_snap_net_income_test: false + is_tanf_non_cash_eligible: true + meets_snap_categorical_eligibility: true + snap_allotment_before_eligibility: 1 + ca_snap_meets_allotment_requirement: true + is_snap_eligible: true + snap: 1 + +# ACL 14-56 p. 6 and ACL 14-63 p. 2: deny zero allotments for 3+; +# retain the minimum for 1-2. FY2026 CDSS maximums: $785 (3), $994 (4). +# Wages $42,345/12 x 80% minus $209 = $2,614; +# maximum minus ceil(30% x net) = $0. The application is denied or participation discontinued. +- name: Case 19, California MCE household of 3 with net income 2_614 has a 0 dollar allotment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 42_345 + weekly_hours_worked_before_lsr: 40 + person2: + age: 8 + person3: + age: 8 + spm_units: + spm_unit1: + members: + - person1 + - person2 + - person3 + housing_cost: 0 + snap_utility_allowance: 0 + tax_units: + tax_unit1: + members: + - person1 + - person2 + - person3 + households: + household1: + members: + - person1 + - person2 + - person3 + state_code: CA + output: + snap_net_income: 2_614 + meets_snap_net_income_test: false + is_tanf_non_cash_eligible: true + meets_snap_categorical_eligibility: true + snap_allotment_before_eligibility: 0 + ca_snap_meets_allotment_requirement: false + is_snap_eligible: false + snap: 0 + +# ACL 14-56 p. 6 and ACL 14-63 p. 2: deny zero allotments for 3+; +# retain the minimum for 1-2. FY2026 CDSS maximums: $785 (3), $994 (4). +# Wages $52,995/12 x 80% minus $223 = $3,310; +# maximum minus ceil(30% x net) = $1. A $1 ongoing allotment is issued. +- name: Case 20, California MCE household of 4 with net income 3_310 has a 1 dollar allotment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 52_995 + weekly_hours_worked_before_lsr: 40 + person2: + age: 8 + person3: + age: 8 + person4: + age: 8 + spm_units: + spm_unit1: + members: + - person1 + - person2 + - person3 + - person4 + housing_cost: 0 + snap_utility_allowance: 0 + tax_units: + tax_unit1: + members: + - person1 + - person2 + - person3 + - person4 + households: + household1: + members: + - person1 + - person2 + - person3 + - person4 + state_code: CA + output: + snap_net_income: 3_310 + meets_snap_net_income_test: false + is_tanf_non_cash_eligible: true + meets_snap_categorical_eligibility: true + snap_allotment_before_eligibility: 1 + ca_snap_meets_allotment_requirement: true + is_snap_eligible: true + snap: 1 + +# ACL 14-56 p. 6 and ACL 14-63 p. 2: deny zero allotments for 3+; +# retain the minimum for 1-2. FY2026 CDSS maximums: $785 (3), $994 (4). +# Wages $53,010/12 x 80% minus $223 = $3,311; +# maximum minus ceil(30% x net) = $0. The application is denied or participation discontinued. +- name: Case 21, California MCE household of 4 with net income 3_311 has a 0 dollar allotment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 53_010 + weekly_hours_worked_before_lsr: 40 + person2: + age: 8 + person3: + age: 8 + person4: + age: 8 + spm_units: + spm_unit1: + members: + - person1 + - person2 + - person3 + - person4 + housing_cost: 0 + snap_utility_allowance: 0 + tax_units: + tax_unit1: + members: + - person1 + - person2 + - person3 + - person4 + households: + household1: + members: + - person1 + - person2 + - person3 + - person4 + state_code: CA + output: + snap_net_income: 3_311 + meets_snap_net_income_test: false + is_tanf_non_cash_eligible: true + meets_snap_categorical_eligibility: true + snap_allotment_before_eligibility: 0 + ca_snap_meets_allotment_requirement: false + is_snap_eligible: false + snap: 0 + +# ACL 14-56 p. 6 and ACL 14-63 p. 2: deny zero allotments for 3+; +# retain the minimum for 1-2. FY2026 CDSS maximums: $785 (3), $994 (4). +# Calculated benefit is below the $24 minimum; net exceeds the regular standard. +- name: Case 22, California MCE household of 1 with net income 1_791 has a 24 dollar allotment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 30_000 + weekly_hours_worked_before_lsr: 40 + spm_units: + spm_unit1: + members: + - person1 + housing_cost: 0 + snap_utility_allowance: 0 + tax_units: + tax_unit1: + members: + - person1 + households: + household1: + members: + - person1 + state_code: CA + output: + snap_net_income: 1_791 + meets_snap_net_income_test: false + is_tanf_non_cash_eligible: true + meets_snap_categorical_eligibility: true + snap_allotment_before_eligibility: 24 + ca_snap_meets_allotment_requirement: true + is_snap_eligible: true + snap: 24 + +# ACL 14-56 p. 6 and ACL 14-63 p. 2: deny zero allotments for 3+; +# retain the minimum for 1-2. FY2026 CDSS maximums: $785 (3), $994 (4). +# Calculated benefit is below the $24 minimum; net exceeds the regular standard. +- name: Case 23, California MCE household of 2 with net income 1_924 has a 24 dollar allotment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 32_000 + weekly_hours_worked_before_lsr: 40 + person2: + age: 8 + spm_units: + spm_unit1: + members: + - person1 + - person2 + housing_cost: 0 + snap_utility_allowance: 0 + tax_units: + tax_unit1: + members: + - person1 + - person2 + households: + household1: + members: + - person1 + - person2 + state_code: CA + output: + snap_net_income: 1_924 + meets_snap_net_income_test: false + is_tanf_non_cash_eligible: true + meets_snap_categorical_eligibility: true + snap_allotment_before_eligibility: 24 + ca_snap_meets_allotment_requirement: true + is_snap_eligible: true + snap: 24 + +# ACL 14-56 p. 6 and ACL 14-63 p. 2: deny zero allotments for 3+; +# retain the minimum for 1-2. FY2026 CDSS maximums: $785 (3), $994 (4). +# Review regression: $5,000 gross - $1,000 earned deduction - $223 = $3,777; +# $994 - ceil($1,133.10) is negative, so the allotment and participation are zero. +- name: Case 24, California MCE household of 4 with net income 3_777 has a 0 dollar allotment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 60_000 + weekly_hours_worked_before_lsr: 40 + person2: + age: 8 + person3: + age: 8 + person4: + age: 8 + spm_units: + spm_unit1: + members: + - person1 + - person2 + - person3 + - person4 + housing_cost: 0 + snap_utility_allowance: 0 + tax_units: + tax_unit1: + members: + - person1 + - person2 + - person3 + - person4 + households: + household1: + members: + - person1 + - person2 + - person3 + - person4 + state_code: CA + output: + snap_net_income: 3_777 + meets_snap_net_income_test: false + is_tanf_non_cash_eligible: true + meets_snap_categorical_eligibility: true + snap_allotment_before_eligibility: 0 + ca_snap_meets_allotment_requirement: false + is_snap_eligible: false + snap: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/usda/snap/snap_child_support_integration.yaml b/policyengine_us/tests/policy/baseline/gov/usda/snap/snap_child_support_integration.yaml index 1b8a19ece66..1c5622f5610 100644 --- a/policyengine_us/tests/policy/baseline/gov/usda/snap/snap_child_support_integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/usda/snap/snap_child_support_integration.yaml @@ -54,17 +54,23 @@ snap_child_support_gross_income_deduction: 433.33 snap_gross_income: 2_589.63 snap_child_support_deduction: 0 - # Without deemed SUA, net is $2,589.63 - $604.59 - $209 = $1,776.04. - # Rent $880 is below half-net $888.02, so there is no shelter deduction. - # Main's California net screen denies SNAP at $1,776 > $1,305. - # The independent California MCE correction is tracked in #10036. + # Without utility costs or heat-and-eat eligibility, no allowance is deemed. snap_utility_allowance: 0 + # The earned deduction uses full wages under 7 CFR 273.9(d)(2): + # $36,275.59 / 12 x 20% = $604.5931667, before excluding child support. + snap_earned_income_deduction: 604.59 + # Net before shelter: $2,589.6325 - $604.5931667 - $209 = $1,776.0393333. + snap_net_income_pre_shelter: 1_776.04 + # Rent $880 is below half-net $888.0196667, so shelter deduction is zero. snap_excess_shelter_expense_deduction: 0 snap_net_income: 1_776 - meets_tanf_non_cash_net_income_test: false - meets_snap_categorical_eligibility: false - is_snap_eligible: false - snap: 0 + meets_snap_net_income_test: false + meets_tanf_non_cash_net_income_test: true + meets_snap_categorical_eligibility: true + is_snap_eligible: true + # MCE retains the one-person minimum: $298 - ceil(30% x $1,776) + # = $298 - $533 = -$235, raised to $24 (CDSS MCE letter, page 3). + snap: 24 - name: New York excludes child support from gross income and does not deduct it again from net income. period: 2026-01 diff --git a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/nutrition/snap/ca.yaml b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/nutrition/snap/ca.yaml index da65546cf34..a7b1dd4aa89 100644 --- a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/nutrition/snap/ca.yaml +++ b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/edge_cases/federal/nutrition/snap/ca.yaml @@ -1,15 +1,15 @@ # California (CalFresh) cases that differ from the federal.yaml (TX) baseline # for state-policy reasons: -# - CA applies the BBCE NET income test (net_applies CA = true), so the binding -# eligibility boundary is net income at 100% of the poverty guideline, not -# the 200% BBCE gross limit. -# - CA is an always-SUA state (SUA $663 in FY2026, applied without utility -# expense inputs). +# - CA MCE waives the net income test and uses a 200% poverty gross limit. +# Units with three or more members also need a positive allotment. +# - CA's FY2026 SUA is $663, but after the federal heat-and-eat restriction +# it requires heating/cooling expenses or elderly/disabled deeming. +# The households below have no qualifying utility expenses. # - CA extends CalFresh to additional immigration statuses (CFAP) and delays # the OBBB refugee exclusion to 2026-04-01 (ACL 25-92). -# SNAP compares income to the poverty guideline in effect at the preceding -# Oct 1: Jan-Sep 2026 use the 2025 FPG (3-person $26,650, i.e. a monthly net -# limit of $2,220.83); Oct-Dec 2026 use the 2026 FPG ($27,320 -> $2,276.67). +# SNAP uses the poverty guideline in effect at the preceding Oct 1: +# Jan-Sep 2026 use the 2025 FPG (3-person $26,650); Oct-Dec use the 2026 FPG +# ($27,320). The MCE gross limits are twice those guidelines. - name: snap_ca_net_income_just_below_fy2026_net_limit (ca) period: 2026 absolute_error_margin: 0.1 @@ -71,9 +71,9 @@ spm_units: spm_unit: # Gross ratio 36,000/26,650 = 1.35 fails the federal 130% test, but CA - # BBCE (200% gross + net test) rescues: net = 36,000/12 x 0.8 - 209 = - # 2,191.00 (SUA 663 < half of pre-shelter net, so no shelter deduction) - # <= 2,220.83 Jan-Sep limit -> eligible all year. EC = ceil(2,191 x + # MCE's 200% gross limit and waived net test permit participation. + # Net = 36,000/12 x 0.8 - 209 = 2,191.00, with no utility allowance + # or shelter deduction. EC = ceil(2,191 x # 0.3) = 658 -> 785 - 658 = 127.00/month Jan-Sep; Oct-Dec (FY2027): net # 2,400 - 217 = 2,183 -> EC ceil(654.90) = 655 -> 808 - 655 = 153.00. # Annual = 9 x 127.00 + 3 x 153.00 = 1,602.00. @@ -139,8 +139,8 @@ output: spm_units: spm_unit: - # At the binding CA net limit: net = 36,447/12 x 0.8 - 209 = 2,220.80, - # just under the Jan-Sep limit of 26,650/12 = 2,220.83 -> eligible. + # At the former model net limit: 36,447/12 x 0.8 - 209 = 2,220.80. + # MCE waives that test; the gross limit and positive allotment apply. # EC = ceil(2,221 x 0.3) = 667 -> 785 - 667 = 118.00/month # Jan-Sep; Oct-Dec (FY2027): net 2,212.80 rounds to 2,213 -> EC 664 -> # 808 - 664 = 144.00. Annual = 9 x 118.00 + 3 x 144.00 = 1,494.00. @@ -206,14 +206,13 @@ output: spm_units: spm_unit: - # Deliberate ineligible-side pin of CA's net-test route: net = - # 38,000/12 x 0.8 - 209 = 2,324.33 exceeds the net limit in every - # month (Jan-Sep 2,220.83; Oct-Dec: 2,316.95 > 2,276.67), and the - # federal 130% gross test also fails (ratio 1.43), so the unit is - # ineligible all year. In a no-net-test 200% state this income would - # be eligible. - snap: 0.0 - is_snap_eligible: false + # MCE waives the net test: $38,000 is below the 200% gross limit. + # No utility or shelter deduction; net before rounding is + # $2,324.33/$2,316.33. Positive allotments permit participation. + # FY2026/FY2027 net $2,324/$2,316; contribution $698/$695. + # SNAP $87/$113/month; annual 9 x 87 + 3 x 113 = $1,122. + snap: 1122.0 + is_snap_eligible: true - name: snap_ca_head_immigration_refugee_cfap_transition (ca) period: 2026 absolute_error_margin: 0.1 diff --git a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/ca.yaml b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/ca.yaml index ba2c6a460ad..225d33e50a0 100644 --- a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/ca.yaml +++ b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/ca.yaml @@ -560,11 +560,13 @@ ca_tanf: 0.0 ca_tanf_eligible: false is_lifeline_eligible: true - is_snap_eligible: false + is_snap_eligible: true la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 0.0 + # FY2026/FY2027 net $2,977/$2,971; contribution $894/$892. + # SNAP $100/$131/month; annual 9 x 100 + 3 x 131 = $1,293. + snap: 1293.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -936,11 +938,13 @@ ca_tanf: 0.0 ca_tanf_eligible: false is_lifeline_eligible: true - is_snap_eligible: false + is_snap_eligible: true la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 0.0 + # FY2026/FY2027 net $2,977/$2,971; contribution $894/$892. + # SNAP $100/$131/month; annual 9 x 100 + 3 x 131 = $1,293. + snap: 1293.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -1903,11 +1907,15 @@ ca_tanf: 0.0 ca_tanf_eligible: false is_lifeline_eligible: true - is_snap_eligible: false + is_snap_eligible: true la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 0.0 + # Oct-Dec uses the model-uprated California phone allowance ($20 to + # $20.71), because FY2027 values are not in the model yet. + # FY2026/FY2027 net $2,946/$2,936; contribution $884/$881. + # SNAP $110/$142/month; annual 9 x 110 + 3 x 142 = $1,416. + snap: 1416.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -2291,11 +2299,13 @@ ca_tanf_eligible: false housing_assistance: 0.0 is_lifeline_eligible: true - is_snap_eligible: false + is_snap_eligible: true la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 0.0 + # FY2026/FY2027 net $2,977/$2,971; contribution $894/$892. + # SNAP $100/$131/month; annual 9 x 100 + 3 x 131 = $1,293. + snap: 1293.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -2674,11 +2684,15 @@ ca_tanf: 0.0 ca_tanf_eligible: false is_lifeline_eligible: true - is_snap_eligible: false + is_snap_eligible: true la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 0.0 + # Oct-Dec uses the model-uprated California phone allowance ($20 to + # $20.71), because FY2027 values are not in the model yet. + # FY2026/FY2027 net $2,946/$2,936; contribution $884/$881. + # SNAP $110/$142/month; annual 9 x 110 + 3 x 142 = $1,416. + snap: 1416.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -2874,11 +2888,15 @@ ca_tanf: 0.0 ca_tanf_eligible: false is_lifeline_eligible: true - is_snap_eligible: false + is_snap_eligible: true la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 0.0 + # Oct-Dec uses the model-uprated California phone allowance ($20 to + # $20.71), because FY2027 values are not in the model yet. + # FY2026/FY2027 net $2,946/$2,936; contribution $884/$881. + # SNAP $110/$142/month; annual 9 x 110 + 3 x 142 = $1,416. + snap: 1416.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -3258,11 +3276,13 @@ ca_tanf: 0.0 ca_tanf_eligible: false is_lifeline_eligible: true - is_snap_eligible: false + is_snap_eligible: true la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 0.0 + # FY2026/FY2027 net $2,977/$2,971; contribution $894/$892. + # SNAP $100/$131/month; annual 9 x 100 + 3 x 131 = $1,293. + snap: 1293.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -4599,11 +4619,13 @@ ca_tanf: 0.0 ca_tanf_eligible: false is_lifeline_eligible: true - is_snap_eligible: false + is_snap_eligible: true la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 0.0 + # FY2026/FY2027 net $2,977/$2,971; contribution $894/$892. + # SNAP $100/$131/month; annual 9 x 100 + 3 x 131 = $1,293. + snap: 1293.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -4795,11 +4817,15 @@ ca_tanf: 0.0 ca_tanf_eligible: false is_lifeline_eligible: true - is_snap_eligible: false + is_snap_eligible: true la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 0.0 + # Oct-Dec uses the model-uprated California phone allowance ($20 to + # $20.71), because FY2027 values are not in the model yet. + # FY2026/FY2027 net $2,946/$2,936; contribution $884/$881. + # SNAP $110/$142/month; annual 9 x 110 + 3 x 142 = $1,416. + snap: 1416.0 people: head: ca_ala_general_assistance_eligible_person: false @@ -4993,11 +5019,13 @@ ca_tanf: 0.0 ca_tanf_eligible: false is_lifeline_eligible: true - is_snap_eligible: false + is_snap_eligible: true la_general_relief: 0.0 la_general_relief_eligible: false lifeline: 228.0 - snap: 0.0 + # FY2026/FY2027 net $2,977/$2,971; contribution $894/$892. + # SNAP $100/$131/month; annual 9 x 100 + 3 x 131 = $1,293. + snap: 1293.0 people: head: ca_ala_general_assistance_eligible_person: false diff --git a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/federal.yaml b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/federal.yaml index eb5e62d1ebb..682637fef46 100644 --- a/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/federal.yaml +++ b/policyengine_us/tests/policy/baseline/partners/analytics_coverage/signatures/federal.yaml @@ -167,8 +167,10 @@ output: spm_units: spm_unit: - is_snap_eligible: false - snap: 0.0 + is_snap_eligible: true + # FY2026/FY2027 net $2,977/$2,971; contribution $894/$892. + # SNAP $100/$131/month; annual 9 x 100 + 3 x 131 = $1,293. + snap: 1293.0 people: head: is_wic_eligible: false @@ -352,8 +354,12 @@ output: spm_units: spm_unit: - is_snap_eligible: false - snap: 0.0 + is_snap_eligible: true + # Oct-Dec uses the model-uprated California limited utility allowance + # ($170 to $176), because FY2027 values are not in the model yet. + # FY2026/FY2027 net $2,796/$2,781; contribution $839/$835. + # SNAP $155/$188/month; annual 9 x 155 + 3 x 188 = $1,959. + snap: 1959.0 people: head: is_wic_eligible: false @@ -514,8 +520,10 @@ output: spm_units: spm_unit: - is_snap_eligible: false - snap: 0.0 + is_snap_eligible: true + # FY2026/FY2027 net $2,966/$2,957; contribution $890/$888. + # SNAP $104/$135/month; annual 9 x 104 + 3 x 135 = $1,341. + snap: 1341.0 people: head: is_wic_eligible: false @@ -617,8 +625,10 @@ output: spm_units: spm_unit: - is_snap_eligible: false - snap: 0.0 + is_snap_eligible: true + # FY2026/FY2027 net $2,966/$2,957; contribution $890/$888. + # SNAP $104/$135/month; annual 9 x 104 + 3 x 135 = $1,341. + snap: 1341.0 people: head: is_wic_eligible: false @@ -724,8 +734,10 @@ output: spm_units: spm_unit: - is_snap_eligible: false - snap: 0.0 + is_snap_eligible: true + # FY2026/FY2027 net $2,977/$2,971; contribution $894/$892. + # SNAP $100/$131/month; annual 9 x 100 + 3 x 131 = $1,293. + snap: 1293.0 people: head: is_wic_eligible: false @@ -1048,8 +1060,10 @@ output: spm_units: spm_unit: - is_snap_eligible: false - snap: 0.0 + is_snap_eligible: true + # FY2026/FY2027 net $2,977/$2,971; contribution $894/$892. + # SNAP $100/$131/month; annual 9 x 100 + 3 x 131 = $1,293. + snap: 1293.0 people: head: is_wic_eligible: false @@ -1148,8 +1162,12 @@ output: spm_units: spm_unit: - is_snap_eligible: false - snap: 0.0 + is_snap_eligible: true + # Oct-Dec uses the model-uprated California phone allowance ($20 to + # $20.71), because FY2027 values are not in the model yet. + # FY2026/FY2027 net $2,946/$2,936; contribution $884/$881. + # SNAP $110/$142/month; annual 9 x 110 + 3 x 142 = $1,416. + snap: 1416.0 people: head: is_wic_eligible: false @@ -1248,8 +1266,10 @@ output: spm_units: spm_unit: - is_snap_eligible: false - snap: 0.0 + is_snap_eligible: true + # FY2026/FY2027 net $2,977/$2,971; contribution $894/$892. + # SNAP $100/$131/month; annual 9 x 100 + 3 x 131 = $1,293. + snap: 1293.0 people: head: is_wic_eligible: false @@ -1348,8 +1368,10 @@ output: spm_units: spm_unit: - is_snap_eligible: false - snap: 0.0 + is_snap_eligible: true + # FY2026/FY2027 net $2,966/$2,957; contribution $890/$888. + # SNAP $104/$135/month; annual 9 x 104 + 3 x 135 = $1,341. + snap: 1341.0 people: head: is_wic_eligible: false @@ -1455,8 +1477,10 @@ output: spm_units: spm_unit: - is_snap_eligible: false - snap: 0.0 + is_snap_eligible: true + # FY2026/FY2027 net $2,977/$2,971; contribution $894/$892. + # SNAP $100/$131/month; annual 9 x 100 + 3 x 131 = $1,293. + snap: 1293.0 people: head: is_wic_eligible: false @@ -1550,8 +1574,10 @@ output: spm_units: spm_unit: - is_snap_eligible: false - snap: 0.0 + is_snap_eligible: true + # FY2026/FY2027 net $2,977/$2,971; contribution $894/$892. + # SNAP $100/$131/month; annual 9 x 100 + 3 x 131 = $1,293. + snap: 1293.0 people: head: is_wic_eligible: false @@ -1649,8 +1675,10 @@ output: spm_units: spm_unit: - is_snap_eligible: false - snap: 0.0 + is_snap_eligible: true + # FY2026/FY2027 net $2,966/$2,957; contribution $890/$888. + # SNAP $104/$135/month; annual 9 x 104 + 3 x 135 = $1,341. + snap: 1341.0 people: head: is_wic_eligible: false @@ -1760,8 +1788,12 @@ output: spm_units: spm_unit: - is_snap_eligible: false - snap: 0.0 + is_snap_eligible: true + # Oct-Dec uses the model-uprated California limited utility allowance + # ($170 to $176), because FY2027 values are not in the model yet. + # FY2026/FY2027 net $2,796/$2,781; contribution $839/$835. + # SNAP $155/$188/month; annual 9 x 155 + 3 x 188 = $1,959. + snap: 1959.0 people: head: is_wic_eligible: false diff --git a/policyengine_us/variables/gov/states/ca/cdss/snap/eligibility/ca_snap_meets_allotment_requirement.py b/policyengine_us/variables/gov/states/ca/cdss/snap/eligibility/ca_snap_meets_allotment_requirement.py new file mode 100644 index 00000000000..e08cd546c6d --- /dev/null +++ b/policyengine_us/variables/gov/states/ca/cdss/snap/eligibility/ca_snap_meets_allotment_requirement.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class ca_snap_meets_allotment_requirement(Variable): + value_type = bool + entity = SPMUnit + definition_period = MONTH + default_value = True + defined_for = StateCode.CA + label = "Meets California SNAP allotment requirement" + documentation = ( + "California denies or discontinues CE/MCE households of three or more " + "with zero calculated allotments. One- and two-person households retain " + "their minimum allotment. Applies from the model's October 2015 MCE " + "baseline; initial-month proration and issuance exceptions are not modeled." + ) + reference = ( + "https://www.cdss.ca.gov/lettersnotices/entres/getinfo/acl/2014/14-56.pdf#page=6", + "https://www.cdss.ca.gov/lettersnotices/entres/getinfo/acl/2014/14-63.pdf#page=2", + "https://www.law.cornell.edu/cfr/text/7/273.10#e_2_iii", + ) + + def formula_2015_10_01(spm_unit, period, parameters): + allotment = spm_unit("snap_allotment_before_eligibility", period) + # This is a participation screen, not the regular net-income test. + return allotment > 0 diff --git a/policyengine_us/variables/gov/usda/snap/eligibility/is_snap_eligible.py b/policyengine_us/variables/gov/usda/snap/eligibility/is_snap_eligible.py index b9c750f0bc1..67cbb06fb33 100644 --- a/policyengine_us/variables/gov/usda/snap/eligibility/is_snap_eligible.py +++ b/policyengine_us/variables/gov/usda/snap/eligibility/is_snap_eligible.py @@ -31,4 +31,11 @@ def formula(spm_unit, period, parameters): eligible_member_present = spm_unit.any( ~person("is_snap_excluded_member", period) ) - return (normal_eligibility | categorical_eligibility) & eligible_member_present + ca_allotment_requirement = spm_unit( + "ca_snap_meets_allotment_requirement", period + ) + return ( + (normal_eligibility | categorical_eligibility) + & eligible_member_present + & ca_allotment_requirement + ) diff --git a/policyengine_us/variables/gov/usda/snap/snap_allotment_before_eligibility.py b/policyengine_us/variables/gov/usda/snap/snap_allotment_before_eligibility.py new file mode 100644 index 00000000000..cd441016abb --- /dev/null +++ b/policyengine_us/variables/gov/usda/snap/snap_allotment_before_eligibility.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class snap_allotment_before_eligibility(Variable): + value_type = float + entity = SPMUnit + definition_period = MONTH + label = "SNAP allotment before eligibility screening" + documentation = ( + "Calculated SNAP allotment, including the minimum for one- and two-person " + "units, before eligibility screening. This allows zero-allotment " + "participation rules to use the benefit calculation without a cycle." + ) + reference = "https://www.law.cornell.edu/cfr/text/7/273.10#e_2_ii" + unit = USD + + def formula(spm_unit, period, parameters): + expected_contribution = spm_unit("snap_expected_contribution", period) + max_allotment = spm_unit("snap_max_allotment", period) + min_allotment = spm_unit("snap_min_allotment", period) + return max_(min_allotment, max_allotment - expected_contribution) diff --git a/policyengine_us/variables/gov/usda/snap/snap_normal_allotment.py b/policyengine_us/variables/gov/usda/snap/snap_normal_allotment.py index 49c8d33f261..972f42faf67 100644 --- a/policyengine_us/variables/gov/usda/snap/snap_normal_allotment.py +++ b/policyengine_us/variables/gov/usda/snap/snap_normal_allotment.py @@ -13,11 +13,4 @@ class snap_normal_allotment(Variable): unit = USD defined_for = "is_snap_eligible" - def formula(spm_unit, period, parameters): - # Federal SNAP rules are defined in U.S.C Title 7, Chapter 51, which - # also defines state powers to modify the rules. - expected_contribution = spm_unit("snap_expected_contribution", period) - max_allotment = spm_unit("snap_max_allotment", period) - normal_allotment = max_allotment - expected_contribution - min_allotment = spm_unit("snap_min_allotment", period) - return max_(min_allotment, normal_allotment) + adds = ["snap_allotment_before_eligibility"]