From ce572b2a0cabeba222924987376ed574a8a5b86c Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 20 May 2026 17:03:31 -0400 Subject: [PATCH 01/10] Initial commit for Santa Clara County General Assistance implementation Starting implementation of Santa Clara County General Assistance. Documentation and parallel development will follow. Refs #8357 From e8641cfd356e632b99a9d86df60a80987f5278fe Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 20 May 2026 17:47:32 -0400 Subject: [PATCH 02/10] Implement Santa Clara County General Assistance (ref #8357) Mirrors Alameda County GA structure with SCC-specific values: - MAP: $343 single, $460 married (effective 2016-04-01, frozen) - Personal property limit: $500 - 6 qualified immigration statuses Adds two deviations from the Alameda mirror: - Shared-housing tiers (15/20/25% reductions per GA 282) - Expanded countable income to 17 PE sources (Alameda has 6) Closes #8357 Co-Authored-By: Claude Opus 4.7 (1M context) --- .../scc/general_assistance/age_threshold.yaml | 10 + .../general_assistance/amount/married.yaml | 12 + .../scc/general_assistance/amount/single.yaml | 12 + .../countable_income/sources.yaml | 29 ++ .../personal_property/limit.yaml | 14 + .../qualified_immigration_status.yaml | 18 ++ .../shared_housing/reduction.yaml | 20 ++ .../ca/scc/ga/ca_scc_general_assistance.yaml | 215 +++++++++++++ ...a_scc_general_assistance_age_eligible.yaml | 55 ++++ ...ca_scc_general_assistance_base_amount.yaml | 220 +++++++++++++ ...c_general_assistance_countable_income.yaml | 56 ++++ ...al_assistance_countable_income_person.yaml | 70 +++++ ...cc_general_assistance_eligible_person.yaml | 95 ++++++ ...ssistance_immigration_status_eligible.yaml | 63 ++++ ...cc_general_assistance_income_eligible.yaml | 62 ++++ ...assistance_personal_property_eligible.yaml | 63 ++++ .../gov/local/ca/scc/ga/integration.yaml | 294 ++++++++++++++++++ .../ca/scc/ga/ca_scc_general_assistance.py | 16 + .../ca_scc_general_assistance_base_amount.py | 27 ++ ...eneral_assistance_shared_housing_status.py | 18 ++ .../ca_scc_general_assistance_age_eligible.py | 17 + ..._scc_general_assistance_eligible_person.py | 28 ++ ..._assistance_immigration_status_eligible.py | 18 ++ ..._scc_general_assistance_income_eligible.py | 15 + ...l_assistance_personal_property_eligible.py | 15 + ...scc_general_assistance_countable_income.py | 13 + ...eral_assistance_countable_income_person.py | 13 + .../variables/gov/local/ca/scc/in_scc.py | 12 + 28 files changed, 1500 insertions(+) create mode 100644 policyengine_us/parameters/gov/local/ca/scc/general_assistance/age_threshold.yaml create mode 100644 policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/married.yaml create mode 100644 policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/single.yaml create mode 100644 policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/sources.yaml create mode 100644 policyengine_us/parameters/gov/local/ca/scc/general_assistance/personal_property/limit.yaml create mode 100644 policyengine_us/parameters/gov/local/ca/scc/general_assistance/qualified_immigration_status.yaml create mode 100644 policyengine_us/parameters/gov/local/ca/scc/general_assistance/shared_housing/reduction.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_age_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible_person.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_immigration_status_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_income_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_personal_property_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml create mode 100644 policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance.py create mode 100644 policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.py create mode 100644 policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_shared_housing_status.py create mode 100644 policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_age_eligible.py create mode 100644 policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible_person.py create mode 100644 policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_immigration_status_eligible.py create mode 100644 policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_income_eligible.py create mode 100644 policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_personal_property_eligible.py create mode 100644 policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income.py create mode 100644 policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income_person.py create mode 100644 policyengine_us/variables/gov/local/ca/scc/in_scc.py diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/age_threshold.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/age_threshold.yaml new file mode 100644 index 00000000000..b972f82715b --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/age_threshold.yaml @@ -0,0 +1,10 @@ +description: Santa Clara County limits the General Assistance program to individuals of this age or older. +values: + 2016-04-01: 18 +metadata: + label: Santa Clara County General Assistance age eligibility threshold + unit: year + period: year + reference: + - title: Santa Clara County General Assistance Handbook, GA 112 (Unmarried Minor) + href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/01Policy/Policy.htm diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/married.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/married.yaml new file mode 100644 index 00000000000..cb2ae9338ea --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/married.yaml @@ -0,0 +1,12 @@ +description: Santa Clara County provides this amount as the cash grant for married filers under the General Assistance program. +values: + 2016-04-01: 460 +metadata: + label: Santa Clara County General Assistance married amount + period: month + unit: currency-USD + reference: + - title: Santa Clara County General Assistance Need Standards Chart (GA 280) + href: https://stgenssa.sccgov.org/debs/program_handbooks/charts/assets/4GA/NeedStnds.htm + - title: Santa Clara County GA-62 Program Information Sheet + href: https://stgenssa.sccgov.org/debs/Forms/GA_62_en.pdf#page=2 diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/single.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/single.yaml new file mode 100644 index 00000000000..5be01078ecf --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/single.yaml @@ -0,0 +1,12 @@ +description: Santa Clara County provides this amount as the cash grant for single filers under the General Assistance program. +values: + 2016-04-01: 343 +metadata: + label: Santa Clara County General Assistance single amount + period: month + unit: currency-USD + reference: + - title: Santa Clara County General Assistance Need Standards Chart (GA 280) + href: https://stgenssa.sccgov.org/debs/program_handbooks/charts/assets/4GA/NeedStnds.htm + - title: Santa Clara County GA-62 Program Information Sheet + href: https://stgenssa.sccgov.org/debs/Forms/GA_62_en.pdf#page=2 diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/sources.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/sources.yaml new file mode 100644 index 00000000000..be706d1fc9c --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/sources.yaml @@ -0,0 +1,29 @@ +description: Santa Clara County uses these income sources when determining eligibility for the General Assistance program. +values: + 2016-04-01: + - employment_income + - self_employment_income + - sstb_self_employment_income + - social_security + - unemployment_compensation + - veterans_benefits + - workers_compensation + - taxable_pension_income + - tax_exempt_pension_income + - taxable_interest_income + - tax_exempt_interest_income + - qualified_dividend_income + - non_qualified_dividend_income + - alimony_income + - child_support_received + - strike_benefits + - rental_income +metadata: + unit: list + period: year + label: Santa Clara County General Assistance income sources + reference: + - title: Santa Clara County General Assistance Handbook, GA 200-204 (Income Policies) + href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/09Income/GA_Policies.htm + - title: Santa Clara County General Assistance Handbook, Types of Income chapter + href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/09Income/Types_Income.htm diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/personal_property/limit.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/personal_property/limit.yaml new file mode 100644 index 00000000000..7730c6a1595 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/personal_property/limit.yaml @@ -0,0 +1,14 @@ +description: Santa Clara County limits the General Assistance program to households with up to this personal property amount. +values: + 2016-04-01: 500 +metadata: + label: Santa Clara County General Assistance personal property limit amount + unit: currency-USD + period: month + reference: + - title: Santa Clara County General Assistance Handbook, GA 180 (Personal Property) + href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/01Policy/Policy.htm + - title: Santa Clara County General Assistance Handbook, Personal Property chapter + href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/08Property/Personal_Property.htm + - title: Santa Clara County GA-62 Program Information Sheet + href: https://stgenssa.sccgov.org/debs/Forms/GA_62_en.pdf#page=2 diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/qualified_immigration_status.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/qualified_immigration_status.yaml new file mode 100644 index 00000000000..17d50be7078 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/qualified_immigration_status.yaml @@ -0,0 +1,18 @@ +description: Santa Clara County uses these immigration statuses as qualified non-citizens under the General Assistance program. +values: + 2016-04-01: + - CITIZEN + - LEGAL_PERMANENT_RESIDENT + - REFUGEE + - ASYLEE + - CUBAN_HAITIAN_ENTRANT + - PAROLED_ONE_YEAR +metadata: + label: Santa Clara County General Assistance qualified immigration statuses + period: year + unit: list + reference: + - title: Santa Clara County General Assistance Handbook, GA 141 (Residence of a Non-Citizen) + href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/01Policy/Policy.htm + - title: Santa Clara County General Assistance Handbook, Noncitizen Status chapter + href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/07Citizens_Noncitizens/Non_Citizen_Status.htm diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/shared_housing/reduction.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/shared_housing/reduction.yaml new file mode 100644 index 00000000000..a6da553c80b --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/shared_housing/reduction.yaml @@ -0,0 +1,20 @@ +description: Santa Clara County excludes this share of the maximum aid payment for shared housing recipients under the General Assistance program. +metadata: + unit: /1 + period: year + label: Santa Clara County General Assistance shared housing reduction rate + breakdown: + - ca_scc_general_assistance_shared_housing_status + reference: + - title: Santa Clara County General Assistance Handbook, GA 282 (Shared Housing) + href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/14Payment/Shared_Housing.htm + - title: Santa Clara County General Assistance Need Standards Chart (GA 282 footnote) + href: https://stgenssa.sccgov.org/debs/program_handbooks/charts/assets/4GA/NeedStnds.htm +NOT_SHARED: + 2016-04-01: 0 +SHARED_WITH_ONE: + 2016-04-01: 0.15 +SHARED_WITH_TWO: + 2016-04-01: 0.2 +SHARED_WITH_THREE_OR_MORE: + 2016-04-01: 0.25 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml new file mode 100644 index 00000000000..7ba3d9616e3 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml @@ -0,0 +1,215 @@ +- name: Case 1, single eligible adult with zero income, receives full single MAP. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance: 343 + +- name: Case 2, single eligible adult with partial earned income. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + employment_income: 1_200 + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance: 243 + +- name: Case 3, single eligible adult with income at MAP, zero benefit. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + employment_income: 4_116 + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance: 0 + +- name: Case 4, ineligible due to SSI receipt. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 100 + personal_property: 0 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance: 0 + +- name: Case 5, negative employment income does not inflate benefit beyond MAP. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + self_employment_income: -120_000 + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance: 343 + +- name: Case 6, extremely negative SE income — benefit must not exceed single MAP. + period: 2024-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + self_employment_income: -1_000_000 + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + # Benefit must be capped at the MAP ($343), not 343 - (-83_333) = 83_676. + ca_scc_general_assistance: 343 + +- name: Case 7, single eligible adult with countable income exactly at single MAP, zero benefit. + period: 2024-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + employment_income: 4_116 + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + # countable_income = 4_116 / 12 = 343 == MAP -> income_eligible is strict < so false -> benefit = 0 + ca_scc_general_assistance: 0 + +- name: Case 8, single eligible adult with countable income $1 below single MAP, $1 benefit. + period: 2024-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + employment_income: 4_104 + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + # countable = 4_104 / 12 = 342; benefit = 343 - 342 = 1 + ca_scc_general_assistance: 1 + +- name: Case 9, married couple with $200 combined countable income receives $260. + period: 2024-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + employment_income: 1_200 + person2: + age: 28 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + employment_income: 1_200 + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + # combined countable = (1_200 + 1_200) / 12 = 200; benefit = 460 - 200 = 260 + ca_scc_general_assistance: 260 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_age_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_age_eligible.yaml new file mode 100644 index 00000000000..8b08618a8c2 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_age_eligible.yaml @@ -0,0 +1,55 @@ +- name: Case 1, adult age 30 is eligible. + period: 2024 + input: + age: 30 + in_scc: true + output: + ca_scc_general_assistance_age_eligible: true + +- name: Case 2, minor age 17 is ineligible. + period: 2024 + input: + age: 17 + in_scc: true + output: + ca_scc_general_assistance_age_eligible: false + +- name: Case 3, age exactly 18 is eligible at boundary. + period: 2024 + input: + age: 18 + in_scc: true + output: + ca_scc_general_assistance_age_eligible: true + +- name: Case 4, age 25 is eligible. + period: 2024 + input: + age: 25 + in_scc: true + output: + ca_scc_general_assistance_age_eligible: true + +- name: Case 5, infant age 0 is ineligible. + period: 2024 + input: + age: 0 + in_scc: true + output: + ca_scc_general_assistance_age_eligible: false + +- name: Case 6, age 17.99 (float) is ineligible just below 18. + period: 2024 + input: + age: 17.99 + in_scc: true + output: + ca_scc_general_assistance_age_eligible: false + +- name: Case 7, age 100 is eligible. + period: 2024 + input: + age: 100 + in_scc: true + output: + ca_scc_general_assistance_age_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.yaml new file mode 100644 index 00000000000..71f6651121d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.yaml @@ -0,0 +1,220 @@ +- name: Case 1, single eligible adult, not shared housing, full single MAP. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance_base_amount: 343 + +- name: Case 2, married eligible couple, not shared housing, full married MAP. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + person2: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance_base_amount: 460 + +- name: Case 3, only one of two persons eligible, returns single MAP. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + person2: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: UNDOCUMENTED + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance_base_amount: 343 + +- name: Case 4, single eligible adult shared with one other (15 percent reduction). + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: SHARED_WITH_ONE + output: + ca_scc_general_assistance_base_amount: 291.55 + +- name: Case 5, single eligible adult shared with two others (20 percent reduction). + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: SHARED_WITH_TWO + output: + ca_scc_general_assistance_base_amount: 274.4 + +- name: Case 6, single eligible adult shared with three or more (25 percent reduction). + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: SHARED_WITH_THREE_OR_MORE + output: + ca_scc_general_assistance_base_amount: 257.25 + +- name: Case 7, married couple shared with one (15 percent reduction on married MAP). + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + person2: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + ca_scc_general_assistance_shared_housing_status: SHARED_WITH_ONE + output: + ca_scc_general_assistance_base_amount: 391 + +- name: Case 8, married couple shared with two (20 percent reduction on married MAP). + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + person2: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + ca_scc_general_assistance_shared_housing_status: SHARED_WITH_TWO + output: + # 460 * 0.80 = 368 + ca_scc_general_assistance_base_amount: 368 + +- name: Case 9, married couple shared with three or more (25 percent reduction on married MAP). + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + person2: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + ca_scc_general_assistance_shared_housing_status: SHARED_WITH_THREE_OR_MORE + output: + # 460 * 0.75 = 345 + ca_scc_general_assistance_base_amount: 345 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income.yaml new file mode 100644 index 00000000000..7e7cb5478af --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income.yaml @@ -0,0 +1,56 @@ +- name: Case 1, single head with employment income. + period: 2024-01 + input: + people: + person1: + is_tax_unit_head_or_spouse: true + employment_income: 1_200 + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + output: + ca_scc_general_assistance_countable_income: 100 + +- name: Case 2, head and spouse both have income, sums across SPMUnit. + period: 2024-01 + input: + people: + person1: + is_tax_unit_head_or_spouse: true + employment_income: 1_200 + person2: + is_tax_unit_head_or_spouse: true + social_security: 2_400 + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + output: + ca_scc_general_assistance_countable_income: 300 + +- name: Case 3, dependent child income excluded. + period: 2024-01 + input: + people: + person1: + is_tax_unit_head_or_spouse: true + employment_income: 1_200 + person2: + is_tax_unit_head_or_spouse: false + employment_income: 6_000 + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + output: + ca_scc_general_assistance_countable_income: 100 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml new file mode 100644 index 00000000000..1d3a4b31ead --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml @@ -0,0 +1,70 @@ +- name: Case 1, head with employment income only. + period: 2024-01 + input: + is_tax_unit_head_or_spouse: true + employment_income: 1_200 + in_scc: true + output: + ca_scc_general_assistance_countable_income_person: 100 + +- name: Case 2, head with multiple expanded sources sums correctly. + period: 2024-01 + input: + is_tax_unit_head_or_spouse: true + employment_income: 1_200 + social_security: 2_400 + workers_compensation: 600 + in_scc: true + output: + ca_scc_general_assistance_countable_income_person: 350 + +- name: Case 3, non head or spouse contributes zero. + period: 2024-01 + input: + is_tax_unit_head_or_spouse: false + employment_income: 12_000 + in_scc: true + output: + ca_scc_general_assistance_countable_income_person: 0 + +- name: Case 4, head with zero income. + period: 2024-01 + input: + is_tax_unit_head_or_spouse: true + employment_income: 0 + in_scc: true + output: + ca_scc_general_assistance_countable_income_person: 0 + +- name: Case 5, head with negative self-employment income passes through (no flooring). + period: 2024-01 + input: + is_tax_unit_head_or_spouse: true + self_employment_income: -12_000 + in_scc: true + output: + # Formula uses pure adds across sources; negative SE income flows through as -1_000/month. + ca_scc_general_assistance_countable_income_person: -1_000 + +- name: Case 6, head with employment plus workers_comp plus taxable_pension summed. + period: 2024-01 + input: + is_tax_unit_head_or_spouse: true + employment_income: 1_200 + workers_compensation: 600 + taxable_pension_income: 2_400 + in_scc: true + output: + # (1_200 + 600 + 2_400) / 12 = 350 + ca_scc_general_assistance_countable_income_person: 350 + +- name: Case 7, head with truly zero income across all sources. + period: 2024-01 + input: + is_tax_unit_head_or_spouse: true + employment_income: 0 + self_employment_income: 0 + social_security: 0 + in_scc: true + output: + ca_scc_general_assistance_countable_income_person: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible_person.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible_person.yaml new file mode 100644 index 00000000000..38ed65e8418 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible_person.yaml @@ -0,0 +1,95 @@ +- name: Case 1, single adult citizen with low income, eligible. + period: 2024-01 + input: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + in_scc: true + output: + ca_scc_general_assistance_eligible_person: true + +- name: Case 2, ineligible due to SSI receipt. + period: 2024-01 + input: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 100 + personal_property: 100 + immigration_status: CITIZEN + in_scc: true + output: + ca_scc_general_assistance_eligible_person: false + +- name: Case 3, ineligible because not head or spouse. + period: 2024-01 + input: + age: 30 + is_tax_unit_head_or_spouse: false + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + in_scc: true + output: + ca_scc_general_assistance_eligible_person: false + +- name: Case 4, ineligible due to undocumented status. + period: 2024-01 + input: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: UNDOCUMENTED + in_scc: true + output: + ca_scc_general_assistance_eligible_person: false + +- name: Case 5, ineligible due to age under 18 (blocker short-circuits). + period: 2024-01 + input: + age: 17 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + in_scc: true + output: + ca_scc_general_assistance_eligible_person: false + +- name: Case 6, ineligible due to personal property over $500 (blocker short-circuits). + period: 2024-01 + input: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 501 + immigration_status: CITIZEN + in_scc: true + output: + ca_scc_general_assistance_eligible_person: false + +- name: Case 7, ineligible due to DACA status (blocker short-circuits). + period: 2024-01 + input: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: DACA + in_scc: true + output: + ca_scc_general_assistance_eligible_person: false + +- name: Case 8, eligible with legal permanent resident status (qualified immigration path). + period: 2024-01 + input: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: LEGAL_PERMANENT_RESIDENT + in_scc: true + output: + ca_scc_general_assistance_eligible_person: true diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_immigration_status_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_immigration_status_eligible.yaml new file mode 100644 index 00000000000..48910d63953 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_immigration_status_eligible.yaml @@ -0,0 +1,63 @@ +- name: Case 1, citizen is eligible. + period: 2024 + input: + in_scc: true + immigration_status: CITIZEN + output: + ca_scc_general_assistance_immigration_status_eligible: true + +- name: Case 2, legal permanent resident is eligible. + period: 2024 + input: + in_scc: true + immigration_status: LEGAL_PERMANENT_RESIDENT + output: + ca_scc_general_assistance_immigration_status_eligible: true + +- name: Case 3, refugee is eligible. + period: 2024 + input: + in_scc: true + immigration_status: REFUGEE + output: + ca_scc_general_assistance_immigration_status_eligible: true + +- name: Case 4, asylee is eligible. + period: 2024 + input: + in_scc: true + immigration_status: ASYLEE + output: + ca_scc_general_assistance_immigration_status_eligible: true + +- name: Case 5, Cuban/Haitian entrant is eligible. + period: 2024 + input: + in_scc: true + immigration_status: CUBAN_HAITIAN_ENTRANT + output: + ca_scc_general_assistance_immigration_status_eligible: true + +- name: Case 6, paroled one year is eligible. + period: 2024 + input: + in_scc: true + immigration_status: PAROLED_ONE_YEAR + output: + ca_scc_general_assistance_immigration_status_eligible: true + +- name: Case 7, undocumented is ineligible. + period: 2024 + input: + in_scc: true + immigration_status: UNDOCUMENTED + output: + ca_scc_general_assistance_immigration_status_eligible: false + +- name: Case 8, DACA is ineligible. + period: 2024 + input: + in_scc: true + immigration_status: DACA + output: + ca_scc_general_assistance_immigration_status_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_income_eligible.yaml new file mode 100644 index 00000000000..dabbb65e679 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_income_eligible.yaml @@ -0,0 +1,62 @@ +- name: Case 1, countable income below single MAP, eligible. + period: 2024-01 + input: + ca_scc_general_assistance_countable_income: 342 + ca_scc_general_assistance_base_amount: 343 + in_scc: true + output: + ca_scc_general_assistance_income_eligible: true + +- name: Case 2, countable income equal to single MAP, ineligible (strict less-than per GA 200). + period: 2024-01 + input: + ca_scc_general_assistance_countable_income: 343 + ca_scc_general_assistance_base_amount: 343 + in_scc: true + output: + ca_scc_general_assistance_income_eligible: false + +- name: Case 3, countable income above single MAP, ineligible. + period: 2024-01 + input: + ca_scc_general_assistance_countable_income: 344 + ca_scc_general_assistance_base_amount: 343 + in_scc: true + output: + ca_scc_general_assistance_income_eligible: false + +- name: Case 4, countable income below married MAP, eligible. + period: 2024-01 + input: + ca_scc_general_assistance_countable_income: 459 + ca_scc_general_assistance_base_amount: 460 + in_scc: true + output: + ca_scc_general_assistance_income_eligible: true + +- name: Case 5, zero countable income with single MAP, eligible. + period: 2024-01 + input: + ca_scc_general_assistance_countable_income: 0 + ca_scc_general_assistance_base_amount: 343 + in_scc: true + output: + ca_scc_general_assistance_income_eligible: true + +- name: Case 6, married MAP one cent above threshold, ineligible. + period: 2024-01 + input: + ca_scc_general_assistance_countable_income: 460.01 + ca_scc_general_assistance_base_amount: 460 + in_scc: true + output: + ca_scc_general_assistance_income_eligible: false + +- name: Case 7, income far above threshold, ineligible. + period: 2024-01 + input: + ca_scc_general_assistance_countable_income: 10_000 + ca_scc_general_assistance_base_amount: 343 + in_scc: true + output: + ca_scc_general_assistance_income_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_personal_property_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_personal_property_eligible.yaml new file mode 100644 index 00000000000..acbf47c414c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_personal_property_eligible.yaml @@ -0,0 +1,63 @@ +- name: Case 1, personal property below $500 limit, eligible. + period: 2024-01 + input: + personal_property: 499 + in_scc: true + output: + ca_scc_general_assistance_personal_property_eligible: true + +- name: Case 2, personal property at $500 limit, eligible (at-or-below). + period: 2024-01 + input: + personal_property: 500 + in_scc: true + output: + ca_scc_general_assistance_personal_property_eligible: true + +- name: Case 3, personal property above $500 limit, ineligible. + period: 2024-01 + input: + personal_property: 501 + in_scc: true + output: + ca_scc_general_assistance_personal_property_eligible: false + +- name: Case 4, personal property well above $500 limit, ineligible. + period: 2024-01 + input: + personal_property: 1_000 + in_scc: true + output: + ca_scc_general_assistance_personal_property_eligible: false + +- name: Case 5, zero personal property, eligible. + period: 2024-01 + input: + personal_property: 0 + in_scc: true + output: + ca_scc_general_assistance_personal_property_eligible: true + +- name: Case 6, personal property exactly $500.00, eligible at boundary (at-or-below). + period: 2024-01 + input: + personal_property: 500.00 + in_scc: true + output: + ca_scc_general_assistance_personal_property_eligible: true + +- name: Case 7, personal property $500.01 (one cent over), ineligible. + period: 2024-01 + input: + personal_property: 500.01 + in_scc: true + output: + ca_scc_general_assistance_personal_property_eligible: false + +- name: Case 8, very large personal property, ineligible. + period: 2024-01 + input: + personal_property: 1_000_000 + in_scc: true + output: + ca_scc_general_assistance_personal_property_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml new file mode 100644 index 00000000000..a1a5ab181f0 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml @@ -0,0 +1,294 @@ +- name: Case 1, eligible single adult with zero income receives full single MAP. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance_base_amount: 343 + ca_scc_general_assistance_countable_income: 0 + ca_scc_general_assistance: 343 + +- name: Case 2, eligible single adult with $100/month employment income, fill-the-gap benefit. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + employment_income: 1_200 + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance_base_amount: 343 + ca_scc_general_assistance_countable_income: 100 + ca_scc_general_assistance: 243 + +- name: Case 3, eligible married couple with zero income receives full married MAP. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + person2: + age: 28 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance_base_amount: 460 + ca_scc_general_assistance_countable_income: 0 + ca_scc_general_assistance: 460 + +- name: Case 4, ineligible due to SSI receipt. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 100 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance: 0 + +- name: Case 5, ineligible due to personal property over $500 limit. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 501 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance: 0 + +- name: Case 6, ineligible due to undocumented immigration status. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: UNDOCUMENTED + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance: 0 + +- name: Case 7, single eligible adult sharing housing with one other, MAP reduced 15 percent. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: SHARED_WITH_ONE + output: + ca_scc_general_assistance_base_amount: 291.55 + ca_scc_general_assistance_countable_income: 0 + ca_scc_general_assistance: 291.55 + +- name: Case 8, expanded income source workers_compensation counted in countable income. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + workers_compensation: 2_400 + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + ca_scc_general_assistance_base_amount: 343 + ca_scc_general_assistance_countable_income: 200 + ca_scc_general_assistance: 143 + +- name: Case 9, married couple plus minor child — child does not affect base amount. + period: 2024-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 35 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 50 + immigration_status: CITIZEN + person2: + age: 32 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 50 + immigration_status: CITIZEN + person3: + age: 5 + is_tax_unit_head_or_spouse: false + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + households: + household: + members: [person1, person2, person3] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2, person3] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + # Child fails age_eligible and head-or-spouse — only person1 and person2 count. + # num_eligible == 2 -> married MAP $460; countable income = 0; benefit = 460. + ca_scc_general_assistance_base_amount: 460 + ca_scc_general_assistance_countable_income: 0 + ca_scc_general_assistance: 460 + +- name: Case 10, two-adult SPMUnit with one undocumented spouse — only eligible person counted. + period: 2024-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 50 + immigration_status: CITIZEN + person2: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 50 + immigration_status: UNDOCUMENTED + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + ca_scc_general_assistance_shared_housing_status: NOT_SHARED + output: + # Only person1 is eligible; num_eligible == 1 -> single MAP $343. + ca_scc_general_assistance_base_amount: 343 + ca_scc_general_assistance_countable_income: 0 + ca_scc_general_assistance: 343 + +- name: Case 11, SPMUnit-level shared housing reduction applies once across all members. + period: 2024-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 40 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + person2: + age: 38 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + # Shared with two other persons -> 20% reduction on married MAP. + ca_scc_general_assistance_shared_housing_status: SHARED_WITH_TWO + output: + # 460 * 0.80 = 368; countable income = 0; benefit = 368. + ca_scc_general_assistance_base_amount: 368 + ca_scc_general_assistance_countable_income: 0 + ca_scc_general_assistance: 368 diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance.py b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance.py new file mode 100644 index 00000000000..71319898ebb --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class ca_scc_general_assistance(Variable): + value_type = float + entity = SPMUnit + unit = USD + definition_period = MONTH + label = "Santa Clara County General Assistance" + defined_for = "ca_scc_general_assistance_income_eligible" + reference = "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/01Policy/Policy.htm" + + def formula(spm_unit, period, parameters): + base = spm_unit("ca_scc_general_assistance_base_amount", period) + countable = spm_unit("ca_scc_general_assistance_countable_income", period) + return base - max_(countable, 0) diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.py b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.py new file mode 100644 index 00000000000..7e6483ff4fa --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class ca_scc_general_assistance_base_amount(Variable): + value_type = float + entity = SPMUnit + unit = USD + definition_period = MONTH + label = "Santa Clara County General Assistance base amount" + defined_for = "ca_scc_general_assistance_eligible_person" + reference = ( + "https://stgenssa.sccgov.org/debs/program_handbooks/charts/assets/4GA/NeedStnds.htm", + "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/14Payment/Shared_Housing.htm", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.local.ca.scc.general_assistance + eligible_persons = spm_unit.members( + "ca_scc_general_assistance_eligible_person", period + ) + num_eligible = spm_unit.sum(eligible_persons) + unshared = where(num_eligible == 2, p.amount.married, p.amount.single) + shared_status = spm_unit( + "ca_scc_general_assistance_shared_housing_status", period + ) + reduction = p.shared_housing.reduction[shared_status] + return unshared * (1 - reduction) diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_shared_housing_status.py b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_shared_housing_status.py new file mode 100644 index 00000000000..fab97fcf20f --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_shared_housing_status.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class CaSccGeneralAssistanceSharedHousingStatus(Enum): + SHARED_WITH_ONE = "Shared with one other person" + SHARED_WITH_TWO = "Shared with two other persons" + SHARED_WITH_THREE_OR_MORE = "Shared with three or more other persons" + NOT_SHARED = "Not shared" + + +class ca_scc_general_assistance_shared_housing_status(Variable): + value_type = Enum + entity = SPMUnit + possible_values = CaSccGeneralAssistanceSharedHousingStatus + default_value = CaSccGeneralAssistanceSharedHousingStatus.NOT_SHARED + definition_period = MONTH + label = "Santa Clara County General Assistance shared housing status" + reference = "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/14Payment/Shared_Housing.htm" diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_age_eligible.py b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_age_eligible.py new file mode 100644 index 00000000000..f50388bcb8a --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_age_eligible.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class ca_scc_general_assistance_age_eligible(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = ( + "Eligible for Santa Clara County General Assistance based on age requirements" + ) + defined_for = "in_scc" + reference = "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/01Policy/Policy.htm" + + def formula(person, period, parameters): + p = parameters(period).gov.local.ca.scc.general_assistance + age = person("monthly_age", period) + return age >= p.age_threshold diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible_person.py b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible_person.py new file mode 100644 index 00000000000..5de3b377aec --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible_person.py @@ -0,0 +1,28 @@ +from policyengine_us.model_api import * + + +class ca_scc_general_assistance_eligible_person(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = "Eligible person for Santa Clara County General Assistance" + defined_for = "in_scc" + reference = "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/01Policy/Policy.htm" + + def formula(person, period, parameters): + age_eligible = person("ca_scc_general_assistance_age_eligible", period) + personal_property_eligible = person.spm_unit( + "ca_scc_general_assistance_personal_property_eligible", period + ) + immigration_status_eligible = person( + "ca_scc_general_assistance_immigration_status_eligible", period + ) + receives_ssi = person("ssi", period) > 0 + is_head_or_spouse = person("is_tax_unit_head_or_spouse", period) + return ( + age_eligible + & personal_property_eligible + & immigration_status_eligible + & ~receives_ssi + & is_head_or_spouse + ) diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_immigration_status_eligible.py b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_immigration_status_eligible.py new file mode 100644 index 00000000000..920a22dc630 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_immigration_status_eligible.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class ca_scc_general_assistance_immigration_status_eligible(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = ( + "Eligible for Santa Clara County General Assistance based on immigration status" + ) + defined_for = "in_scc" + reference = "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/07Citizens_Noncitizens/Non_Citizen_Status.htm" + + def formula(person, period, parameters): + p = parameters(period).gov.local.ca.scc.general_assistance + immigration_status = person("immigration_status", period.this_year) + immigration_status_str = immigration_status.decode_to_str() + return np.isin(immigration_status_str, p.qualified_immigration_status) diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_income_eligible.py b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_income_eligible.py new file mode 100644 index 00000000000..db55a802203 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_income_eligible.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class ca_scc_general_assistance_income_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = MONTH + label = "Eligible for Santa Clara County General Assistance based on income requirements" + defined_for = "in_scc" + reference = "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/01Policy/Policy.htm" + + def formula(spm_unit, period, parameters): + income = spm_unit("ca_scc_general_assistance_countable_income", period) + limit = spm_unit("ca_scc_general_assistance_base_amount", period) + return income < limit diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_personal_property_eligible.py b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_personal_property_eligible.py new file mode 100644 index 00000000000..a163abe91a3 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_personal_property_eligible.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class ca_scc_general_assistance_personal_property_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = MONTH + label = "Meets property limit for Santa Clara County General Assistance" + defined_for = "in_scc" + reference = "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/08Property/Personal_Property.htm" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.local.ca.scc.general_assistance.personal_property + personal_property = add(spm_unit, period.this_year, ["personal_property"]) + return personal_property <= p.limit diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income.py b/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income.py new file mode 100644 index 00000000000..b5fff7fd44d --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class ca_scc_general_assistance_countable_income(Variable): + value_type = float + entity = SPMUnit + unit = USD + definition_period = MONTH + label = "Santa Clara County General Assistance countable income" + defined_for = "in_scc" + reference = "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/09Income/GA_Policies.htm" + + adds = ["ca_scc_general_assistance_countable_income_person"] diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income_person.py b/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income_person.py new file mode 100644 index 00000000000..a955af96125 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income_person.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class ca_scc_general_assistance_countable_income_person(Variable): + value_type = float + entity = Person + unit = USD + definition_period = MONTH + label = "Santa Clara County General Assistance countable income for each person" + defined_for = "is_tax_unit_head_or_spouse" + reference = "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/09Income/Types_Income.htm" + + adds = "gov.local.ca.scc.general_assistance.countable_income.sources" diff --git a/policyengine_us/variables/gov/local/ca/scc/in_scc.py b/policyengine_us/variables/gov/local/ca/scc/in_scc.py new file mode 100644 index 00000000000..bbb99bfec88 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/scc/in_scc.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class in_scc(Variable): + value_type = bool + entity = Household + definition_period = YEAR + label = "Is in Santa Clara County" + + def formula(household, period, parameters): + county = household("county_str", period) + return county == "SANTA_CLARA_COUNTY_CA" From 8d9fc570c03fa9c1e10e0f9e8a8ca90a1d9394f9 Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 20 May 2026 17:48:29 -0400 Subject: [PATCH 03/10] Add changelog fragment for Santa Clara County GA --- changelog.d/added/8358.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/added/8358.md diff --git a/changelog.d/added/8358.md b/changelog.d/added/8358.md new file mode 100644 index 00000000000..37fab43f2a5 --- /dev/null +++ b/changelog.d/added/8358.md @@ -0,0 +1 @@ +Add Santa Clara County General Assistance program. From ff78f6784652bbc82e8db88bbd3658be3d9eb3bd Mon Sep 17 00:00:00 2001 From: Ziming Date: Wed, 20 May 2026 19:17:18 -0400 Subject: [PATCH 04/10] Apply review quick-win fixes for Santa Clara County GA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - personal_property/limit.yaml: period month -> year (asset stock not flow); cleaner template description - age_threshold.yaml: add Cal. Family Code § 6500 reference (statutory source for age-of-majority "18") - shared_housing/reduction.yaml: add GA-62 PDF as corroborating reference for derived percentage tiers - Currency unit tests: add absolute_error_margin: 0.1 to base_amount, countable_income, countable_income_person All 77 tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../local/ca/scc/general_assistance/age_threshold.yaml | 2 ++ .../scc/general_assistance/personal_property/limit.yaml | 4 ++-- .../scc/general_assistance/shared_housing/reduction.yaml | 2 ++ .../ca/scc/ga/ca_scc_general_assistance_base_amount.yaml | 9 +++++++++ .../ga/ca_scc_general_assistance_countable_income.yaml | 3 +++ ...a_scc_general_assistance_countable_income_person.yaml | 7 +++++++ 6 files changed, 25 insertions(+), 2 deletions(-) diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/age_threshold.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/age_threshold.yaml index b972f82715b..e7d6390a5c5 100644 --- a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/age_threshold.yaml +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/age_threshold.yaml @@ -8,3 +8,5 @@ metadata: reference: - title: Santa Clara County General Assistance Handbook, GA 112 (Unmarried Minor) href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/01Policy/Policy.htm + - title: California Family Code Section 6500 (Age of majority) + href: https://california.public.law/codes/ca_fam_code_section_6500 diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/personal_property/limit.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/personal_property/limit.yaml index 7730c6a1595..39a23e0918e 100644 --- a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/personal_property/limit.yaml +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/personal_property/limit.yaml @@ -1,10 +1,10 @@ -description: Santa Clara County limits the General Assistance program to households with up to this personal property amount. +description: Santa Clara County limits personal property to this amount under the General Assistance program. values: 2016-04-01: 500 metadata: label: Santa Clara County General Assistance personal property limit amount unit: currency-USD - period: month + period: year reference: - title: Santa Clara County General Assistance Handbook, GA 180 (Personal Property) href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/01Policy/Policy.htm diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/shared_housing/reduction.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/shared_housing/reduction.yaml index a6da553c80b..4d0e8dd0cf9 100644 --- a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/shared_housing/reduction.yaml +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/shared_housing/reduction.yaml @@ -10,6 +10,8 @@ metadata: href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/14Payment/Shared_Housing.htm - title: Santa Clara County General Assistance Need Standards Chart (GA 282 footnote) href: https://stgenssa.sccgov.org/debs/program_handbooks/charts/assets/4GA/NeedStnds.htm + - title: Santa Clara County General Assistance Program Information Sheet (GA-62), Maximum Aid Payment table + href: https://stgenssa.sccgov.org/debs/Forms/GA_62_en.pdf#page=2 NOT_SHARED: 2016-04-01: 0 SHARED_WITH_ONE: diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.yaml index 71f6651121d..4e50a602b70 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.yaml @@ -16,6 +16,7 @@ spm_unit: members: [person1] ca_scc_general_assistance_shared_housing_status: NOT_SHARED + absolute_error_margin: 0.1 output: ca_scc_general_assistance_base_amount: 343 @@ -43,6 +44,7 @@ spm_unit: members: [person1, person2] ca_scc_general_assistance_shared_housing_status: NOT_SHARED + absolute_error_margin: 0.1 output: ca_scc_general_assistance_base_amount: 460 @@ -70,6 +72,7 @@ spm_unit: members: [person1, person2] ca_scc_general_assistance_shared_housing_status: NOT_SHARED + absolute_error_margin: 0.1 output: ca_scc_general_assistance_base_amount: 343 @@ -91,6 +94,7 @@ spm_unit: members: [person1] ca_scc_general_assistance_shared_housing_status: SHARED_WITH_ONE + absolute_error_margin: 0.1 output: ca_scc_general_assistance_base_amount: 291.55 @@ -112,6 +116,7 @@ spm_unit: members: [person1] ca_scc_general_assistance_shared_housing_status: SHARED_WITH_TWO + absolute_error_margin: 0.1 output: ca_scc_general_assistance_base_amount: 274.4 @@ -133,6 +138,7 @@ spm_unit: members: [person1] ca_scc_general_assistance_shared_housing_status: SHARED_WITH_THREE_OR_MORE + absolute_error_margin: 0.1 output: ca_scc_general_assistance_base_amount: 257.25 @@ -160,6 +166,7 @@ spm_unit: members: [person1, person2] ca_scc_general_assistance_shared_housing_status: SHARED_WITH_ONE + absolute_error_margin: 0.1 output: ca_scc_general_assistance_base_amount: 391 @@ -187,6 +194,7 @@ spm_unit: members: [person1, person2] ca_scc_general_assistance_shared_housing_status: SHARED_WITH_TWO + absolute_error_margin: 0.1 output: # 460 * 0.80 = 368 ca_scc_general_assistance_base_amount: 368 @@ -215,6 +223,7 @@ spm_unit: members: [person1, person2] ca_scc_general_assistance_shared_housing_status: SHARED_WITH_THREE_OR_MORE + absolute_error_margin: 0.1 output: # 460 * 0.75 = 345 ca_scc_general_assistance_base_amount: 345 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income.yaml index 7e7cb5478af..0fb1e29e64f 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income.yaml @@ -12,6 +12,7 @@ spm_units: spm_unit: members: [person1] + absolute_error_margin: 0.1 output: ca_scc_general_assistance_countable_income: 100 @@ -32,6 +33,7 @@ spm_units: spm_unit: members: [person1, person2] + absolute_error_margin: 0.1 output: ca_scc_general_assistance_countable_income: 300 @@ -52,5 +54,6 @@ spm_units: spm_unit: members: [person1, person2] + absolute_error_margin: 0.1 output: ca_scc_general_assistance_countable_income: 100 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml index 1d3a4b31ead..c37e6a10864 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml @@ -4,6 +4,7 @@ is_tax_unit_head_or_spouse: true employment_income: 1_200 in_scc: true + absolute_error_margin: 0.1 output: ca_scc_general_assistance_countable_income_person: 100 @@ -15,6 +16,7 @@ social_security: 2_400 workers_compensation: 600 in_scc: true + absolute_error_margin: 0.1 output: ca_scc_general_assistance_countable_income_person: 350 @@ -24,6 +26,7 @@ is_tax_unit_head_or_spouse: false employment_income: 12_000 in_scc: true + absolute_error_margin: 0.1 output: ca_scc_general_assistance_countable_income_person: 0 @@ -33,6 +36,7 @@ is_tax_unit_head_or_spouse: true employment_income: 0 in_scc: true + absolute_error_margin: 0.1 output: ca_scc_general_assistance_countable_income_person: 0 @@ -42,6 +46,7 @@ is_tax_unit_head_or_spouse: true self_employment_income: -12_000 in_scc: true + absolute_error_margin: 0.1 output: # Formula uses pure adds across sources; negative SE income flows through as -1_000/month. ca_scc_general_assistance_countable_income_person: -1_000 @@ -54,6 +59,7 @@ workers_compensation: 600 taxable_pension_income: 2_400 in_scc: true + absolute_error_margin: 0.1 output: # (1_200 + 600 + 2_400) / 12 = 350 ca_scc_general_assistance_countable_income_person: 350 @@ -66,5 +72,6 @@ self_employment_income: 0 social_security: 0 in_scc: true + absolute_error_margin: 0.1 output: ca_scc_general_assistance_countable_income_person: 0 From 95f2afa0e44b3e5bd79e17047f2fef87a1bf7b92 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 26 May 2026 13:52:43 -0400 Subject: [PATCH 05/10] Add Board and Care and Medical Institution living-arrangement overrides Extends the SCC GA living-arrangement enum with BOARD_AND_CARE ($929/month) and MEDICAL_INSTITUTION ($11/month) absolute-amount categories per the Need Standards chart and GA-62. The base-amount formula returns the absolute amount for these two categories instead of applying the single/married + shared-housing reduction formula. Renames the enum variable from shared_housing_status to living_arrangement to reflect the broader scope. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../amount/board_and_care.yaml | 12 ++++ .../amount/medical_institution.yaml | 10 +++ .../shared_housing/reduction.yaml | 6 +- .../ca/scc/ga/ca_scc_general_assistance.yaml | 18 +++--- ...ca_scc_general_assistance_base_amount.yaml | 64 ++++++++++++++++--- .../gov/local/ca/scc/ga/integration.yaml | 47 ++++++++++---- .../ca_scc_general_assistance_base_amount.py | 23 +++++-- ...c_general_assistance_living_arrangement.py | 23 +++++++ ...eneral_assistance_shared_housing_status.py | 18 ------ 9 files changed, 168 insertions(+), 53 deletions(-) create mode 100644 policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/board_and_care.yaml create mode 100644 policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/medical_institution.yaml create mode 100644 policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_living_arrangement.py delete mode 100644 policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_shared_housing_status.py diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/board_and_care.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/board_and_care.yaml new file mode 100644 index 00000000000..8d2f00b3c90 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/board_and_care.yaml @@ -0,0 +1,12 @@ +description: Santa Clara County provides this amount to recipients residing in a State-licensed Board and Care or Residential Care Home under the General Assistance program. +values: + 2016-04-01: 929 +metadata: + label: Santa Clara County General Assistance Board and Care amount + period: month + unit: currency-USD + reference: + - title: Santa Clara County General Assistance Need Standards Chart (state-licensed RCH) + href: https://stgenssa.sccgov.org/debs/program_handbooks/charts/assets/4GA/NeedStnds.htm + - title: Santa Clara County GA-62 Program Information Sheet, State-Licensed Board and Care row + href: https://stgenssa.sccgov.org/debs/Forms/GA_62_en.pdf#page=2 diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/medical_institution.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/medical_institution.yaml new file mode 100644 index 00000000000..1dbe77a17d8 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/amount/medical_institution.yaml @@ -0,0 +1,10 @@ +description: Santa Clara County provides this amount to recipients residing in a medical institution under the General Assistance program. +values: + 2016-04-01: 11 +metadata: + label: Santa Clara County General Assistance medical institution amount + period: month + unit: currency-USD + reference: + - title: Santa Clara County General Assistance Need Standards Chart (one person in medical institution) + href: https://stgenssa.sccgov.org/debs/program_handbooks/charts/assets/4GA/NeedStnds.htm diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/shared_housing/reduction.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/shared_housing/reduction.yaml index 4d0e8dd0cf9..e059b5e46d1 100644 --- a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/shared_housing/reduction.yaml +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/shared_housing/reduction.yaml @@ -4,7 +4,7 @@ metadata: period: year label: Santa Clara County General Assistance shared housing reduction rate breakdown: - - ca_scc_general_assistance_shared_housing_status + - ca_scc_general_assistance_living_arrangement reference: - title: Santa Clara County General Assistance Handbook, GA 282 (Shared Housing) href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/14Payment/Shared_Housing.htm @@ -20,3 +20,7 @@ SHARED_WITH_TWO: 2016-04-01: 0.2 SHARED_WITH_THREE_OR_MORE: 2016-04-01: 0.25 +BOARD_AND_CARE: + 2016-04-01: 0 +MEDICAL_INSTITUTION: + 2016-04-01: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml index 7ba3d9616e3..f5c22f8dc24 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml @@ -16,7 +16,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: ca_scc_general_assistance: 343 @@ -39,7 +39,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: ca_scc_general_assistance: 243 @@ -62,7 +62,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: ca_scc_general_assistance: 0 @@ -84,7 +84,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: ca_scc_general_assistance: 0 @@ -107,7 +107,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: ca_scc_general_assistance: 343 @@ -130,7 +130,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: # Benefit must be capped at the MAP ($343), not 343 - (-83_333) = 83_676. ca_scc_general_assistance: 343 @@ -154,7 +154,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: # countable_income = 4_116 / 12 = 343 == MAP -> income_eligible is strict < so false -> benefit = 0 ca_scc_general_assistance: 0 @@ -178,7 +178,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: # countable = 4_104 / 12 = 342; benefit = 343 - 342 = 1 ca_scc_general_assistance: 1 @@ -209,7 +209,7 @@ spm_units: spm_unit: members: [person1, person2] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: # combined countable = (1_200 + 1_200) / 12 = 200; benefit = 460 - 200 = 260 ca_scc_general_assistance: 260 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.yaml index 4e50a602b70..f5401b9d1c2 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.yaml @@ -15,7 +15,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED absolute_error_margin: 0.1 output: ca_scc_general_assistance_base_amount: 343 @@ -43,7 +43,7 @@ spm_units: spm_unit: members: [person1, person2] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED absolute_error_margin: 0.1 output: ca_scc_general_assistance_base_amount: 460 @@ -71,7 +71,7 @@ spm_units: spm_unit: members: [person1, person2] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED absolute_error_margin: 0.1 output: ca_scc_general_assistance_base_amount: 343 @@ -93,7 +93,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: SHARED_WITH_ONE + ca_scc_general_assistance_living_arrangement: SHARED_WITH_ONE absolute_error_margin: 0.1 output: ca_scc_general_assistance_base_amount: 291.55 @@ -115,7 +115,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: SHARED_WITH_TWO + ca_scc_general_assistance_living_arrangement: SHARED_WITH_TWO absolute_error_margin: 0.1 output: ca_scc_general_assistance_base_amount: 274.4 @@ -137,7 +137,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: SHARED_WITH_THREE_OR_MORE + ca_scc_general_assistance_living_arrangement: SHARED_WITH_THREE_OR_MORE absolute_error_margin: 0.1 output: ca_scc_general_assistance_base_amount: 257.25 @@ -165,7 +165,7 @@ spm_units: spm_unit: members: [person1, person2] - ca_scc_general_assistance_shared_housing_status: SHARED_WITH_ONE + ca_scc_general_assistance_living_arrangement: SHARED_WITH_ONE absolute_error_margin: 0.1 output: ca_scc_general_assistance_base_amount: 391 @@ -193,7 +193,7 @@ spm_units: spm_unit: members: [person1, person2] - ca_scc_general_assistance_shared_housing_status: SHARED_WITH_TWO + ca_scc_general_assistance_living_arrangement: SHARED_WITH_TWO absolute_error_margin: 0.1 output: # 460 * 0.80 = 368 @@ -222,8 +222,54 @@ spm_units: spm_unit: members: [person1, person2] - ca_scc_general_assistance_shared_housing_status: SHARED_WITH_THREE_OR_MORE + ca_scc_general_assistance_living_arrangement: SHARED_WITH_THREE_OR_MORE absolute_error_margin: 0.1 output: # 460 * 0.75 = 345 ca_scc_general_assistance_base_amount: 345 + +- name: Case 10, single eligible adult in State-licensed Board and Care. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_living_arrangement: BOARD_AND_CARE + absolute_error_margin: 0.1 + output: + # $901 vendor payment + $28 personal needs = $929 total. + ca_scc_general_assistance_base_amount: 929 + +- name: Case 11, single eligible adult in medical institution. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_living_arrangement: MEDICAL_INSTITUTION + absolute_error_margin: 0.1 + output: + # Personal needs only; rest of support covered by Medi-Cal. + ca_scc_general_assistance_base_amount: 11 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml index a1a5ab181f0..2bacf7081c8 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml @@ -16,7 +16,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: ca_scc_general_assistance_base_amount: 343 ca_scc_general_assistance_countable_income: 0 @@ -41,7 +41,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: ca_scc_general_assistance_base_amount: 343 ca_scc_general_assistance_countable_income: 100 @@ -71,7 +71,7 @@ spm_units: spm_unit: members: [person1, person2] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: ca_scc_general_assistance_base_amount: 460 ca_scc_general_assistance_countable_income: 0 @@ -95,7 +95,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: ca_scc_general_assistance: 0 @@ -117,7 +117,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: ca_scc_general_assistance: 0 @@ -139,7 +139,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: ca_scc_general_assistance: 0 @@ -161,7 +161,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: SHARED_WITH_ONE + ca_scc_general_assistance_living_arrangement: SHARED_WITH_ONE output: ca_scc_general_assistance_base_amount: 291.55 ca_scc_general_assistance_countable_income: 0 @@ -186,7 +186,7 @@ spm_units: spm_unit: members: [person1] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: ca_scc_general_assistance_base_amount: 343 ca_scc_general_assistance_countable_income: 200 @@ -222,7 +222,7 @@ spm_units: spm_unit: members: [person1, person2, person3] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: # Child fails age_eligible and head-or-spouse — only person1 and person2 count. # num_eligible == 2 -> married MAP $460; countable income = 0; benefit = 460. @@ -254,7 +254,7 @@ spm_units: spm_unit: members: [person1, person2] - ca_scc_general_assistance_shared_housing_status: NOT_SHARED + ca_scc_general_assistance_living_arrangement: NOT_SHARED output: # Only person1 is eligible; num_eligible == 1 -> single MAP $343. ca_scc_general_assistance_base_amount: 343 @@ -286,9 +286,34 @@ spm_unit: members: [person1, person2] # Shared with two other persons -> 20% reduction on married MAP. - ca_scc_general_assistance_shared_housing_status: SHARED_WITH_TWO + ca_scc_general_assistance_living_arrangement: SHARED_WITH_TWO output: # 460 * 0.80 = 368; countable income = 0; benefit = 368. ca_scc_general_assistance_base_amount: 368 ca_scc_general_assistance_countable_income: 0 ca_scc_general_assistance: 368 + +- name: Case 12, Board and Care recipient — absolute amount overrides standard formula. + period: 2024-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 50 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_living_arrangement: BOARD_AND_CARE + output: + # Override skips the single/married + shared housing formula. + ca_scc_general_assistance_base_amount: 929 + ca_scc_general_assistance_countable_income: 0 + ca_scc_general_assistance: 929 diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.py b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.py index 7e6483ff4fa..e239eddb31b 100644 --- a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.py +++ b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.py @@ -1,4 +1,7 @@ from policyengine_us.model_api import * +from policyengine_us.variables.gov.local.ca.scc.ga.ca_scc_general_assistance_living_arrangement import ( + CaSccGeneralAssistanceLivingArrangement, +) class ca_scc_general_assistance_base_amount(Variable): @@ -10,7 +13,7 @@ class ca_scc_general_assistance_base_amount(Variable): defined_for = "ca_scc_general_assistance_eligible_person" reference = ( "https://stgenssa.sccgov.org/debs/program_handbooks/charts/assets/4GA/NeedStnds.htm", - "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/14Payment/Shared_Housing.htm", + "https://stgenssa.sccgov.org/debs/Forms/GA_62_en.pdf#page=2", ) def formula(spm_unit, period, parameters): @@ -20,8 +23,18 @@ def formula(spm_unit, period, parameters): ) num_eligible = spm_unit.sum(eligible_persons) unshared = where(num_eligible == 2, p.amount.married, p.amount.single) - shared_status = spm_unit( - "ca_scc_general_assistance_shared_housing_status", period + arrangement = spm_unit("ca_scc_general_assistance_living_arrangement", period) + reduction = p.shared_housing.reduction[arrangement] + standard = unshared * (1 - reduction) + return select( + [ + arrangement == CaSccGeneralAssistanceLivingArrangement.BOARD_AND_CARE, + arrangement + == CaSccGeneralAssistanceLivingArrangement.MEDICAL_INSTITUTION, + ], + [ + p.amount.board_and_care, + p.amount.medical_institution, + ], + default=standard, ) - reduction = p.shared_housing.reduction[shared_status] - return unshared * (1 - reduction) diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_living_arrangement.py b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_living_arrangement.py new file mode 100644 index 00000000000..f9d1fe62dbc --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_living_arrangement.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class CaSccGeneralAssistanceLivingArrangement(Enum): + NOT_SHARED = "Not shared" + SHARED_WITH_ONE = "Shared with one other person" + SHARED_WITH_TWO = "Shared with two other persons" + SHARED_WITH_THREE_OR_MORE = "Shared with three or more other persons" + BOARD_AND_CARE = "State-licensed Board and Care or Residential Care Home" + MEDICAL_INSTITUTION = "Medical institution" + + +class ca_scc_general_assistance_living_arrangement(Variable): + value_type = Enum + entity = SPMUnit + possible_values = CaSccGeneralAssistanceLivingArrangement + default_value = CaSccGeneralAssistanceLivingArrangement.NOT_SHARED + definition_period = MONTH + label = "Santa Clara County General Assistance living arrangement" + reference = ( + "https://stgenssa.sccgov.org/debs/program_handbooks/charts/assets/4GA/NeedStnds.htm", + "https://stgenssa.sccgov.org/debs/Forms/GA_62_en.pdf#page=2", + ) diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_shared_housing_status.py b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_shared_housing_status.py deleted file mode 100644 index fab97fcf20f..00000000000 --- a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_shared_housing_status.py +++ /dev/null @@ -1,18 +0,0 @@ -from policyengine_us.model_api import * - - -class CaSccGeneralAssistanceSharedHousingStatus(Enum): - SHARED_WITH_ONE = "Shared with one other person" - SHARED_WITH_TWO = "Shared with two other persons" - SHARED_WITH_THREE_OR_MORE = "Shared with three or more other persons" - NOT_SHARED = "Not shared" - - -class ca_scc_general_assistance_shared_housing_status(Variable): - value_type = Enum - entity = SPMUnit - possible_values = CaSccGeneralAssistanceSharedHousingStatus - default_value = CaSccGeneralAssistanceSharedHousingStatus.NOT_SHARED - definition_period = MONTH - label = "Santa Clara County General Assistance shared housing status" - reference = "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/14Payment/Shared_Housing.htm" From 9323be213a7c80792ee3275f57a17c6bd628eaf7 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 26 May 2026 15:47:20 -0400 Subject: [PATCH 06/10] Fix income-eligibility boundary, cap budget unit size, register program - Income eligibility: GA 200 says ineligible only when income "exceeds" MAP, so switch strict < to <= at the threshold. - Base amount: when num_eligible > 2 (an uncommon edge case since GA is for single adults or married couples), fall back to the married rate instead of silently returning the single rate. - Register ca_scc_general_assistance in programs.yaml alongside Alameda. Co-Authored-By: Claude Opus 4.7 (1M context) --- policyengine_us/programs.yaml | 10 ++++++++++ .../gov/local/ca/scc/ga/ca_scc_general_assistance.yaml | 2 +- .../ga/ca_scc_general_assistance_income_eligible.yaml | 4 ++-- .../ca/scc/ga/ca_scc_general_assistance_base_amount.py | 2 +- .../ca_scc_general_assistance_income_eligible.py | 2 +- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index be23800f5a4..73589f30ff6 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1279,6 +1279,16 @@ programs: variable: ca_ala_general_assistance parameter_prefix: gov.local.ca.ala.ga + - id: ca_scc_general_assistance + name: Santa Clara County General Assistance + full_name: Santa Clara County General Assistance + category: Benefits + agency: Local + status: complete + coverage: Santa Clara County + variable: ca_scc_general_assistance + parameter_prefix: gov.local.ca.scc.general_assistance + - id: nyc_income_tax name: NYC income tax full_name: New York City Income Tax diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml index f5c22f8dc24..7742af7f441 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml @@ -156,7 +156,7 @@ members: [person1] ca_scc_general_assistance_living_arrangement: NOT_SHARED output: - # countable_income = 4_116 / 12 = 343 == MAP -> income_eligible is strict < so false -> benefit = 0 + # countable_income = 4_116 / 12 = 343 == MAP -> income_eligible true but fill-the-gap = 343 - 343 = 0 ca_scc_general_assistance: 0 - name: Case 8, single eligible adult with countable income $1 below single MAP, $1 benefit. diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_income_eligible.yaml index dabbb65e679..3747df14375 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_income_eligible.yaml @@ -7,14 +7,14 @@ output: ca_scc_general_assistance_income_eligible: true -- name: Case 2, countable income equal to single MAP, ineligible (strict less-than per GA 200). +- name: Case 2, countable income equal to single MAP, eligible (GA 200 ineligible only when income exceeds MAP). period: 2024-01 input: ca_scc_general_assistance_countable_income: 343 ca_scc_general_assistance_base_amount: 343 in_scc: true output: - ca_scc_general_assistance_income_eligible: false + ca_scc_general_assistance_income_eligible: true - name: Case 3, countable income above single MAP, ineligible. period: 2024-01 diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.py b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.py index e239eddb31b..bf3fb2ecdfc 100644 --- a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.py +++ b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_base_amount.py @@ -22,7 +22,7 @@ def formula(spm_unit, period, parameters): "ca_scc_general_assistance_eligible_person", period ) num_eligible = spm_unit.sum(eligible_persons) - unshared = where(num_eligible == 2, p.amount.married, p.amount.single) + unshared = where(num_eligible >= 2, p.amount.married, p.amount.single) arrangement = spm_unit("ca_scc_general_assistance_living_arrangement", period) reduction = p.shared_housing.reduction[arrangement] standard = unshared * (1 - reduction) diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_income_eligible.py b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_income_eligible.py index db55a802203..d381f558d7f 100644 --- a/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_income_eligible.py +++ b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_income_eligible.py @@ -12,4 +12,4 @@ class ca_scc_general_assistance_income_eligible(Variable): def formula(spm_unit, period, parameters): income = spm_unit("ca_scc_general_assistance_countable_income", period) limit = spm_unit("ca_scc_general_assistance_base_amount", period) - return income < limit + return income <= limit From bec26054141401f0528f308c5b3b4066a031e8d5 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 26 May 2026 18:00:32 -0400 Subject: [PATCH 07/10] Apply handbook-driven fixes from Chapters 2, 7, 8, 9 - Exclude SSI/SSP spouse income (Responsible Relatives, Ch. 2): countable_income_person now zeros out for SSI recipients, matching the rule that an SSI-receiving spouse's income shall not be considered. - Auto-derive institutional living arrangements (Ch. 14 chart rows): living_arrangement now derives MEDICAL_INSTITUTION from ssi_federal_living_arrangement and BOARD_AND_CARE from is_in_residential_care_facility. Shared housing tiers remain user input. - Add DEPORTATION_WITHHELD as a qualified immigration status (GA 141): noncitizens "entitled to remain indefinitely" include withholding of removal recipients, which were previously missing. - Add integration tests for the boundary case, undocumented-spouse income inclusion, SSI-spouse income exclusion, and RCF auto-derivation. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../qualified_immigration_status.yaml | 1 + .../gov/local/ca/scc/ga/integration.yaml | 124 ++++++++++++++++++ ...c_general_assistance_living_arrangement.py | 18 +++ ...eral_assistance_countable_income_person.py | 12 +- 4 files changed, 153 insertions(+), 2 deletions(-) diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/qualified_immigration_status.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/qualified_immigration_status.yaml index 17d50be7078..048b0fe8c7c 100644 --- a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/qualified_immigration_status.yaml +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/qualified_immigration_status.yaml @@ -5,6 +5,7 @@ values: - LEGAL_PERMANENT_RESIDENT - REFUGEE - ASYLEE + - DEPORTATION_WITHHELD # "entitled to remain indefinitely" per GA 141 - CUBAN_HAITIAN_ENTRANT - PAROLED_ONE_YEAR metadata: diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml index 2bacf7081c8..609d9072bc5 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml @@ -317,3 +317,127 @@ ca_scc_general_assistance_base_amount: 929 ca_scc_general_assistance_countable_income: 0 ca_scc_general_assistance: 929 + +- name: Case 13, single adult with income exactly at MAP — eligible with zero fill-the-gap. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + # 343 * 12 = 4116 annual → 343/month + employment_income: 4_116 + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_living_arrangement: NOT_SHARED + output: + # Income exactly equals MAP; per GA 200 "exceeds" is the bar (income > MAP). + ca_scc_general_assistance_income_eligible: true + ca_scc_general_assistance_base_amount: 343 + ca_scc_general_assistance_countable_income: 343 + ca_scc_general_assistance: 0 + +- name: Case 14, undocumented spouse income IS included in GA applicant's budget. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 50 + immigration_status: CITIZEN + person2: + # Per Responsible Relatives "Undocumented Non-citizen Spouse": + # immigration status does not affect spouse-for-spouse responsibility. + # Spouse is not personally eligible, but their income still counts. + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 50 + immigration_status: UNDOCUMENTED + employment_income: 1_200 # 100/month + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + ca_scc_general_assistance_living_arrangement: NOT_SHARED + output: + # Only person1 is eligible → single MAP $343. + # Undocumented spouse's $100/month employment_income still flows into budget. + ca_scc_general_assistance_base_amount: 343 + ca_scc_general_assistance_countable_income: 100 + ca_scc_general_assistance: 243 + +- name: Case 15, SSI-receiving spouse income excluded from GA applicant's budget. + period: 2024-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + person2: + # SSI-receiving spouse — per Responsible Relatives chapter, their income + # and property are excluded from the GA applicant's eligibility budget. + age: 67 + is_tax_unit_head_or_spouse: true + ssi: 900 + personal_property: 100 + immigration_status: CITIZEN + social_security: 12_000 # 1_000/month — would otherwise count + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + ca_scc_general_assistance_living_arrangement: NOT_SHARED + output: + # Only person1 (non-SSI spouse) is GA-eligible → single MAP. + # Person2's $1,000/month social_security is excluded → countable_income = 0. + ca_scc_general_assistance_base_amount: 343 + ca_scc_general_assistance_countable_income: 0 + ca_scc_general_assistance: 343 + +- name: Case 16, residential care facility auto-derives BOARD_AND_CARE. + period: 2024-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 50 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + is_in_residential_care_facility: true + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + # No explicit living_arrangement — formula derives from is_in_residential_care_facility. + output: + ca_scc_general_assistance_living_arrangement: BOARD_AND_CARE + ca_scc_general_assistance_base_amount: 929 + ca_scc_general_assistance: 929 diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_living_arrangement.py b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_living_arrangement.py index f9d1fe62dbc..6741ac4dbfa 100644 --- a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_living_arrangement.py +++ b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_living_arrangement.py @@ -21,3 +21,21 @@ class ca_scc_general_assistance_living_arrangement(Variable): "https://stgenssa.sccgov.org/debs/program_handbooks/charts/assets/4GA/NeedStnds.htm", "https://stgenssa.sccgov.org/debs/Forms/GA_62_en.pdf#page=2", ) + + def formula(spm_unit, period, parameters): + federal_arrangement = spm_unit.members("ssi_federal_living_arrangement", period) + in_medical = ( + federal_arrangement + == federal_arrangement.possible_values.MEDICAL_TREATMENT_FACILITY + ) + any_in_medical = spm_unit.any(in_medical) + any_in_rcf = add(spm_unit, period, ["is_in_residential_care_facility"]) > 0 + + return select( + [any_in_medical, any_in_rcf], + [ + CaSccGeneralAssistanceLivingArrangement.MEDICAL_INSTITUTION, + CaSccGeneralAssistanceLivingArrangement.BOARD_AND_CARE, + ], + default=CaSccGeneralAssistanceLivingArrangement.NOT_SHARED, + ) diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income_person.py b/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income_person.py index a955af96125..7cbd32f295f 100644 --- a/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income_person.py +++ b/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income_person.py @@ -8,6 +8,14 @@ class ca_scc_general_assistance_countable_income_person(Variable): definition_period = MONTH label = "Santa Clara County General Assistance countable income for each person" defined_for = "is_tax_unit_head_or_spouse" - reference = "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/09Income/Types_Income.htm" + reference = ( + "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/09Income/Types_Income.htm", + "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/02Application/Responsible_Relatives.htm", + ) - adds = "gov.local.ca.scc.general_assistance.countable_income.sources" + def formula(person, period, parameters): + sources = parameters( + period + ).gov.local.ca.scc.general_assistance.countable_income.sources + receives_ssi = person("ssi", period) > 0 + return add(person, period, sources) * ~receives_ssi From d9c133aaf7ecd73f4c7697ab394f503655aa23a4 Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 26 May 2026 21:56:07 -0400 Subject: [PATCH 08/10] Apply GA 204 involuntary earned income deductions; clean source list Per Santa Clara County GA 204, involuntary payroll deductions (federal/ state income tax, FICA, CA SDI) are exempt from countable income. Split the countable income source list into earned and unearned, apply person-level deductions (SS, Medicare, SDI) and tax-unit-level federal/ state income tax projected to each spouse by their share of tax-unit earned income. Remove strike_benefits from countable sources per handbook (strikers are considered fully employed and ineligible for GA). Document the PAROLED_ONE_YEAR inclusion in the immigration formula given the handbook's "specific-period parolee" exclusion. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../earned_deductions/person_sources.yaml | 15 ++++++++ .../countable_income/earned_sources.yaml | 15 ++++++++ .../{sources.yaml => unearned_sources.yaml} | 10 ++---- .../ca/scc/ga/ca_scc_general_assistance.yaml | 20 ++++++----- ...c_general_assistance_countable_income.yaml | 15 ++++---- ...al_assistance_countable_income_person.yaml | 36 +++++++++++++------ ...l_assistance_earned_income_deductions.yaml | 32 +++++++++++++++++ .../gov/local/ca/scc/ga/integration.yaml | 10 +++--- ..._assistance_immigration_status_eligible.py | 7 ++++ ...eral_assistance_countable_income_person.py | 12 ++++--- ...ral_assistance_earned_income_deductions.py | 27 ++++++++++++++ uv.lock | 2 +- 12 files changed, 157 insertions(+), 44 deletions(-) create mode 100644 policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/earned_deductions/person_sources.yaml create mode 100644 policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/earned_sources.yaml rename policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/{sources.yaml => unearned_sources.yaml} (72%) create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_earned_income_deductions.yaml create mode 100644 policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_earned_income_deductions.py diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/earned_deductions/person_sources.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/earned_deductions/person_sources.yaml new file mode 100644 index 00000000000..886489a15ba --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/earned_deductions/person_sources.yaml @@ -0,0 +1,15 @@ +description: Santa Clara County deducts these person-level involuntary withholdings from gross earned income under the General Assistance program. +values: + 2016-04-01: + - employee_social_security_tax + - employee_medicare_tax + - ca_employee_state_disability_insurance_contribution +metadata: + unit: list + period: year + label: Santa Clara County General Assistance person-level earned income deductions + reference: + - title: Santa Clara County General Assistance Handbook, GA 204 (Exempt Income) + href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/01Policy/Policy.htm + - title: Santa Clara County General Assistance Handbook, Verification of Income — Earned Income Deductions + href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/09Income/Verification_Income.htm diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/earned_sources.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/earned_sources.yaml new file mode 100644 index 00000000000..6778ddbc595 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/earned_sources.yaml @@ -0,0 +1,15 @@ +description: Santa Clara County uses these earned income sources when determining eligibility for the General Assistance program. +values: + 2016-04-01: + - employment_income + - self_employment_income + - sstb_self_employment_income +metadata: + unit: list + period: year + label: Santa Clara County General Assistance earned income sources + reference: + - title: Santa Clara County General Assistance Handbook, GA 200-204 (Income Policies) + href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/09Income/GA_Policies.htm + - title: Santa Clara County General Assistance Handbook, Types of Income chapter (Earned Income) + href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/09Income/Types_Income.htm diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/sources.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/unearned_sources.yaml similarity index 72% rename from policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/sources.yaml rename to policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/unearned_sources.yaml index be706d1fc9c..74cc5676e8a 100644 --- a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/sources.yaml +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/unearned_sources.yaml @@ -1,9 +1,6 @@ -description: Santa Clara County uses these income sources when determining eligibility for the General Assistance program. +description: Santa Clara County uses these unearned income sources when determining eligibility for the General Assistance program. values: 2016-04-01: - - employment_income - - self_employment_income - - sstb_self_employment_income - social_security - unemployment_compensation - veterans_benefits @@ -16,14 +13,13 @@ values: - non_qualified_dividend_income - alimony_income - child_support_received - - strike_benefits - rental_income metadata: unit: list period: year - label: Santa Clara County General Assistance income sources + label: Santa Clara County General Assistance unearned income sources reference: - title: Santa Clara County General Assistance Handbook, GA 200-204 (Income Policies) href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/09Income/GA_Policies.htm - - title: Santa Clara County General Assistance Handbook, Types of Income chapter + - title: Santa Clara County General Assistance Handbook, Types of Income chapter (Unearned Income) href: https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/09Income/Types_Income.htm diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml index 7742af7f441..f54b93ae793 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance.yaml @@ -20,7 +20,7 @@ output: ca_scc_general_assistance: 343 -- name: Case 2, single eligible adult with partial earned income. +- name: Case 2, single eligible adult with partial unearned income. period: 2024-01 absolute_error_margin: 0.01 input: @@ -31,7 +31,7 @@ ssi: 0 personal_property: 0 immigration_status: CITIZEN - employment_income: 1_200 + social_security: 1_200 households: household: members: [person1] @@ -41,9 +41,10 @@ members: [person1] ca_scc_general_assistance_living_arrangement: NOT_SHARED output: + # countable = 1_200/12 = 100; benefit = 343 - 100 = 243. ca_scc_general_assistance: 243 -- name: Case 3, single eligible adult with income at MAP, zero benefit. +- name: Case 3, single eligible adult with unearned income at MAP, zero benefit. period: 2024-01 absolute_error_margin: 0.01 input: @@ -54,7 +55,7 @@ ssi: 0 personal_property: 0 immigration_status: CITIZEN - employment_income: 4_116 + social_security: 4_116 households: household: members: [person1] @@ -64,6 +65,7 @@ members: [person1] ca_scc_general_assistance_living_arrangement: NOT_SHARED output: + # countable = 4_116/12 = 343 == MAP; benefit = 0. ca_scc_general_assistance: 0 - name: Case 4, ineligible due to SSI receipt. @@ -146,7 +148,7 @@ ssi: 0 personal_property: 0 immigration_status: CITIZEN - employment_income: 4_116 + social_security: 4_116 households: household: members: [person1] @@ -170,7 +172,7 @@ ssi: 0 personal_property: 0 immigration_status: CITIZEN - employment_income: 4_104 + social_security: 4_104 households: household: members: [person1] @@ -183,7 +185,7 @@ # countable = 4_104 / 12 = 342; benefit = 343 - 342 = 1 ca_scc_general_assistance: 1 -- name: Case 9, married couple with $200 combined countable income receives $260. +- name: Case 9, married couple with $200 combined unearned countable income receives $260. period: 2024-01 absolute_error_margin: 0.1 input: @@ -194,14 +196,14 @@ ssi: 0 personal_property: 100 immigration_status: CITIZEN - employment_income: 1_200 + social_security: 1_200 person2: age: 28 is_tax_unit_head_or_spouse: true ssi: 0 personal_property: 100 immigration_status: CITIZEN - employment_income: 1_200 + social_security: 1_200 households: household: members: [person1, person2] diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income.yaml index 0fb1e29e64f..49d9d73f2f7 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income.yaml @@ -1,10 +1,10 @@ -- name: Case 1, single head with employment income. +- name: Case 1, single head with unearned income. period: 2024-01 input: people: person1: is_tax_unit_head_or_spouse: true - employment_income: 1_200 + social_security: 1_200 households: household: members: [person1] @@ -16,16 +16,16 @@ output: ca_scc_general_assistance_countable_income: 100 -- name: Case 2, head and spouse both have income, sums across SPMUnit. +- name: Case 2, head and spouse both have unearned income, sums across SPMUnit. period: 2024-01 input: people: person1: is_tax_unit_head_or_spouse: true - employment_income: 1_200 + social_security: 1_200 person2: is_tax_unit_head_or_spouse: true - social_security: 2_400 + workers_compensation: 2_400 households: household: members: [person1, person2] @@ -35,6 +35,7 @@ members: [person1, person2] absolute_error_margin: 0.1 output: + # (1_200 + 2_400) / 12 = 300. ca_scc_general_assistance_countable_income: 300 - name: Case 3, dependent child income excluded. @@ -43,10 +44,10 @@ people: person1: is_tax_unit_head_or_spouse: true - employment_income: 1_200 + social_security: 1_200 person2: is_tax_unit_head_or_spouse: false - employment_income: 6_000 + social_security: 6_000 households: household: members: [person1, person2] diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml index c37e6a10864..3f8443c9f08 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml @@ -1,24 +1,25 @@ -- name: Case 1, head with employment income only. +- name: Case 1, head with unearned income only, no deductions applied. period: 2024-01 input: is_tax_unit_head_or_spouse: true - employment_income: 1_200 + social_security: 1_200 in_scc: true absolute_error_margin: 0.1 output: + # Unearned income flows through unchanged; 1_200 / 12 = 100. ca_scc_general_assistance_countable_income_person: 100 -- name: Case 2, head with multiple expanded sources sums correctly. +- name: Case 2, head with multiple unearned sources sums correctly. period: 2024-01 input: is_tax_unit_head_or_spouse: true - employment_income: 1_200 social_security: 2_400 workers_compensation: 600 in_scc: true absolute_error_margin: 0.1 output: - ca_scc_general_assistance_countable_income_person: 350 + # (2_400 + 600) / 12 = 250. + ca_scc_general_assistance_countable_income_person: 250 - name: Case 3, non head or spouse contributes zero. period: 2024-01 @@ -40,7 +41,7 @@ output: ca_scc_general_assistance_countable_income_person: 0 -- name: Case 5, head with negative self-employment income passes through (no flooring). +- name: Case 5, head with negative self-employment income floors at zero earned, no unearned. period: 2024-01 input: is_tax_unit_head_or_spouse: true @@ -48,20 +49,20 @@ in_scc: true absolute_error_margin: 0.1 output: - # Formula uses pure adds across sources; negative SE income flows through as -1_000/month. - ca_scc_general_assistance_countable_income_person: -1_000 + # max_(earned - deductions, 0) floors negative earned at 0; no unearned -> 0. + ca_scc_general_assistance_countable_income_person: 0 -- name: Case 6, head with employment plus workers_comp plus taxable_pension summed. +- name: Case 6, head with multiple unearned sources including pension. period: 2024-01 input: is_tax_unit_head_or_spouse: true - employment_income: 1_200 + social_security: 1_200 workers_compensation: 600 taxable_pension_income: 2_400 in_scc: true absolute_error_margin: 0.1 output: - # (1_200 + 600 + 2_400) / 12 = 350 + # (1_200 + 600 + 2_400) / 12 = 350. ca_scc_general_assistance_countable_income_person: 350 - name: Case 7, head with truly zero income across all sources. @@ -75,3 +76,16 @@ absolute_error_margin: 0.1 output: ca_scc_general_assistance_countable_income_person: 0 + +- name: Case 8, head with SSI receipt zeroes out all countable income. + period: 2024-01 + input: + is_tax_unit_head_or_spouse: true + ssi: 500 + social_security: 12_000 + workers_compensation: 6_000 + in_scc: true + absolute_error_margin: 0.1 + output: + # SSI recipient — all income excluded per Responsible Relatives chapter. + ca_scc_general_assistance_countable_income_person: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_earned_income_deductions.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_earned_income_deductions.yaml new file mode 100644 index 00000000000..ecd9b0d27ca --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_earned_income_deductions.yaml @@ -0,0 +1,32 @@ +- name: Case 1, no earned income produces zero deductions. + period: 2024-01 + input: + is_tax_unit_head_or_spouse: true + employment_income: 0 + self_employment_income: 0 + in_scc: true + absolute_error_margin: 0.1 + output: + ca_scc_general_assistance_earned_income_deductions: 0 + +- name: Case 2, non head or spouse contributes zero deductions. + period: 2024-01 + input: + is_tax_unit_head_or_spouse: false + employment_income: 24_000 + in_scc: true + absolute_error_margin: 0.1 + output: + ca_scc_general_assistance_earned_income_deductions: 0 + +- name: Case 3, unearned income alone does not trigger deductions. + period: 2024-01 + input: + is_tax_unit_head_or_spouse: true + social_security: 12_000 + workers_compensation: 6_000 + in_scc: true + absolute_error_margin: 0.1 + output: + # Deductions only apply to earned income; pure unearned income generates none. + ca_scc_general_assistance_earned_income_deductions: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml index 609d9072bc5..cdfdd25d955 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml @@ -22,7 +22,7 @@ ca_scc_general_assistance_countable_income: 0 ca_scc_general_assistance: 343 -- name: Case 2, eligible single adult with $100/month employment income, fill-the-gap benefit. +- name: Case 2, eligible single adult with $100/month unearned income, fill-the-gap benefit. period: 2024-01 absolute_error_margin: 0.01 input: @@ -33,7 +33,7 @@ ssi: 0 personal_property: 100 immigration_status: CITIZEN - employment_income: 1_200 + social_security: 1_200 households: household: members: [person1] @@ -330,7 +330,7 @@ personal_property: 100 immigration_status: CITIZEN # 343 * 12 = 4116 annual → 343/month - employment_income: 4_116 + social_security: 4_116 households: household: members: [person1] @@ -366,7 +366,7 @@ ssi: 0 personal_property: 50 immigration_status: UNDOCUMENTED - employment_income: 1_200 # 100/month + social_security: 1_200 # 100/month households: household: members: [person1, person2] @@ -377,7 +377,7 @@ ca_scc_general_assistance_living_arrangement: NOT_SHARED output: # Only person1 is eligible → single MAP $343. - # Undocumented spouse's $100/month employment_income still flows into budget. + # Undocumented spouse's $100/month social_security still flows into budget. ca_scc_general_assistance_base_amount: 343 ca_scc_general_assistance_countable_income: 100 ca_scc_general_assistance: 243 diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_immigration_status_eligible.py b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_immigration_status_eligible.py index 920a22dc630..f321dbe9a4e 100644 --- a/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_immigration_status_eligible.py +++ b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_immigration_status_eligible.py @@ -12,6 +12,13 @@ class ca_scc_general_assistance_immigration_status_eligible(Variable): reference = "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/07Citizens_Noncitizens/Non_Citizen_Status.htm" def formula(person, period, parameters): + # GA 141 limits eligibility to noncitizens with the right to remain + # permanently or indefinitely. The handbook excludes parolees admitted + # "for a specific period of time" — only indefinite-period parolees + # qualify. PAROLED_ONE_YEAR is kept in the qualified list because the + # PolicyEngine enum represents "Paroled for at Least One Year," which + # is typically renewed indefinitely in practice; partners should treat + # short fixed-term parolees as UNDOCUMENTED for SCC GA purposes. p = parameters(period).gov.local.ca.scc.general_assistance immigration_status = person("immigration_status", period.this_year) immigration_status_str = immigration_status.decode_to_str() diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income_person.py b/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income_person.py index 7cbd32f295f..b9536e34b89 100644 --- a/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income_person.py +++ b/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_countable_income_person.py @@ -14,8 +14,12 @@ class ca_scc_general_assistance_countable_income_person(Variable): ) def formula(person, period, parameters): - sources = parameters( - period - ).gov.local.ca.scc.general_assistance.countable_income.sources + p = parameters(period).gov.local.ca.scc.general_assistance.countable_income + earned = add(person, period, p.earned_sources) + deductions = person( + "ca_scc_general_assistance_earned_income_deductions", period + ) + unearned = add(person, period, p.unearned_sources) + net_earned = max_(earned - deductions, 0) receives_ssi = person("ssi", period) > 0 - return add(person, period, sources) * ~receives_ssi + return (net_earned + unearned) * ~receives_ssi diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_earned_income_deductions.py b/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_earned_income_deductions.py new file mode 100644 index 00000000000..c16d977f25c --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_earned_income_deductions.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class ca_scc_general_assistance_earned_income_deductions(Variable): + value_type = float + entity = Person + unit = USD + definition_period = MONTH + label = "Santa Clara County General Assistance earned income deductions" + defined_for = "is_tax_unit_head_or_spouse" + reference = ( + "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/01Policy/Policy.htm", + "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/09Income/Verification_Income.htm", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.local.ca.scc.general_assistance.countable_income + person_level = add(person, period, p.earned_deductions.person_sources) + # Apportion tax-unit-level federal and state income tax across spouses + # by each person's share of tax-unit earned income, so both spouses' + # earnings are reduced proportionally by their involuntary withholding. + person_earned = add(person, period, p.earned_sources) + tax_unit_earned = person.tax_unit("tax_unit_earned_income", period) + share = where(tax_unit_earned > 0, person_earned / tax_unit_earned, 0) + federal_tax = person.tax_unit("income_tax_before_credits", period) * share + state_tax = person.tax_unit("state_income_tax", period) * share + return person_level + federal_tax + state_tax diff --git a/uv.lock b/uv.lock index 3469ec5e071..55e5a5cd8e4 100644 --- a/uv.lock +++ b/uv.lock @@ -2974,7 +2974,7 @@ wheels = [ [[package]] name = "policyengine-us" -version = "1.702.1" +version = "1.707.1" source = { editable = "." } dependencies = [ { name = "microdf-python" }, From 1ef0228c288b05ea9c1ef1588bb2f249c1bc69ff Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 26 May 2026 22:56:19 -0400 Subject: [PATCH 09/10] Add CalWORKs, CAPI gates; make living arrangement pure input - New ca_scc_general_assistance_eligible (SPMUnit, MONTH): uses ~ca_tanf_eligible as the CalWORKs referral gate, covering minor children and pregnant adults via demographic TANF eligibility. Households whose CalWORKs application would be denied (income, resources, vehicle, immigration) can fall back to GA. - ca_scc_general_assistance_eligible_person: add ~ca_capi_eligible to exclude aged/blind/disabled noncitizens steered to CAPI. - ca_scc_general_assistance: defined_for now chains to ca_scc_general_assistance_eligible (income + categorical + state). - ca_scc_general_assistance_living_arrangement: drop auto-derivation formula; treat as pure input per API partner contract. - Tests: new eligible.yaml (6 cases), new in_scc.yaml, integration.yaml extended with realistic 2026-01 family combinations. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ca_scc_general_assistance_eligible.yaml | 139 ++++++++++ ...cc_general_assistance_eligible_person.yaml | 16 ++ .../gov/local/ca/scc/ga/integration.yaml | 245 +++++++++++++++++- .../baseline/gov/local/ca/scc/in_scc.yaml | 13 + .../ca/scc/ga/ca_scc_general_assistance.py | 2 +- ...c_general_assistance_living_arrangement.py | 18 -- .../ca_scc_general_assistance_eligible.py | 26 ++ ..._scc_general_assistance_eligible_person.py | 5 + 8 files changed, 432 insertions(+), 32 deletions(-) create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/scc/in_scc.yaml create mode 100644 policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible.py diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible.yaml new file mode 100644 index 00000000000..ecb47f0d3f5 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible.yaml @@ -0,0 +1,139 @@ +- name: Case 1, single eligible adult with zero income. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + output: + ca_scc_general_assistance_eligible: true + +- name: Case 2, household with minor child — referred to CalWORKs. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + person2: + age: 5 + is_tax_unit_head_or_spouse: false + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + output: + # Single mom with a 5-year-old child must apply for CalWORKs per + # Chapter 2 (Eligibility for Other Programs — CalWORKs) and Chapter 9 + # (Potential Income and Resources). + ca_scc_general_assistance_eligible: false + +- name: Case 3, no eligible person in unit (all SSI). + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 100 + personal_property: 0 + immigration_status: CITIZEN + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + output: + ca_scc_general_assistance_eligible: false + +- name: Case 4, income above payment standard — ineligible. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + social_security: 12_000 + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_living_arrangement: NOT_SHARED + output: + # $12,000/12 = $1,000 > $343 single MAP -> income-ineligible. + ca_scc_general_assistance_eligible: false + +- name: Case 5, married couple, both eligible. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + person2: + age: 28 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + output: + ca_scc_general_assistance_eligible: true + +- name: Case 6, pregnant adult — referred to CalWORKs. + period: 2024-01 + input: + people: + person1: + age: 26 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + is_pregnant: true + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + output: + # Pregnant women age 19+ must apply for CalWORKs per Chapter 2 — no GA. + ca_scc_general_assistance_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible_person.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible_person.yaml index 38ed65e8418..42c21cf61e0 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible_person.yaml @@ -93,3 +93,19 @@ in_scc: true output: ca_scc_general_assistance_eligible_person: true + +- name: Case 9, ineligible because eligible for CAPI (parallel cash aid program). + period: 2024-01 + input: + age: 68 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: LEGAL_PERMANENT_RESIDENT + ssi_qualifying_quarters_earnings: 0 # forces CAPI path for aged LPR + in_scc: true + output: + # Aged LPR without 40 SSI-qualifying quarters is CAPI-eligible. + # Per GA 202, eligibility for another federal/state cash aid program + # disqualifies them from GA. + ca_scc_general_assistance_eligible_person: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml index cdfdd25d955..2eaba136180 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/integration.yaml @@ -192,7 +192,7 @@ ca_scc_general_assistance_countable_income: 200 ca_scc_general_assistance: 143 -- name: Case 9, married couple plus minor child — child does not affect base amount. +- name: Case 9, household with minor child — referred to CalWORKs, ineligible for GA. period: 2024-01 absolute_error_margin: 0.1 input: @@ -224,11 +224,11 @@ members: [person1, person2, person3] ca_scc_general_assistance_living_arrangement: NOT_SHARED output: - # Child fails age_eligible and head-or-spouse — only person1 and person2 count. - # num_eligible == 2 -> married MAP $460; countable income = 0; benefit = 460. - ca_scc_general_assistance_base_amount: 460 - ca_scc_general_assistance_countable_income: 0 - ca_scc_general_assistance: 460 + # Per Chapter 2 (Eligibility for Other Programs — CalWORKs) and Chapter 9 + # (Potential Income and Resources), households with physical custody of a + # minor child must apply for CalWORKs and are not eligible for GA. + ca_scc_general_assistance_eligible: false + ca_scc_general_assistance: 0 - name: Case 10, two-adult SPMUnit with one undocumented spouse — only eligible person counted. period: 2024-01 @@ -417,8 +417,125 @@ ca_scc_general_assistance_countable_income: 0 ca_scc_general_assistance: 343 -- name: Case 16, residential care facility auto-derives BOARD_AND_CARE. - period: 2024-01 +- name: Case 16, single mother with 5-year-old child — referred to CalWORKs. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + person2: + age: 5 + is_tax_unit_head_or_spouse: false + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + ca_scc_general_assistance_living_arrangement: NOT_SHARED + output: + # Per Chapter 2 and Chapter 9, single parent with custody of a minor child + # must apply for CalWORKs and is structurally not eligible for GA. + ca_scc_general_assistance_eligible: false + ca_scc_general_assistance: 0 + +- name: Case 17, pregnant single woman — referred to CalWORKs. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 24 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + is_pregnant: true + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_living_arrangement: NOT_SHARED + output: + # Pregnant women age 19+ must apply for CalWORKs per Chapter 2. + ca_scc_general_assistance_eligible: false + ca_scc_general_assistance: 0 + +- name: Case 18, aged LPR without 40 SSI quarters — CAPI-eligible, ineligible for GA. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 68 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: LEGAL_PERMANENT_RESIDENT + ssi_qualifying_quarters_earnings: 0 + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_living_arrangement: NOT_SHARED + output: + # Per GA 202, eligibility for another federal/state cash aid program + # (CAPI for aged/blind/disabled noncitizens without 40 SSI quarters) + # disqualifies the person from GA. + ca_scc_general_assistance_eligible: false + ca_scc_general_assistance: 0 + +- name: Case 19, single adult living with elderly SSI parent — applicant gets single MAP. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 42 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + person2: + age: 78 + is_tax_unit_head_or_spouse: true + ssi: 900 + personal_property: 0 + immigration_status: CITIZEN + social_security: 12_000 + households: + household: + members: [person1, person2] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2] + ca_scc_general_assistance_living_arrangement: NOT_SHARED + output: + # Elderly parent receives SSI -> fails SSI gate, excluded from num_eligible. + # Parent's $1,000/month Social Security is excluded from countable income + # (SSI recipient rule). Only person1 is eligible -> single MAP $343. + ca_scc_general_assistance_base_amount: 343 + ca_scc_general_assistance_countable_income: 0 + ca_scc_general_assistance: 343 + +- name: Case 20, married couple plus adult college-aged child — couple gets married MAP. + period: 2026-01 absolute_error_margin: 0.1 input: people: @@ -426,9 +543,46 @@ age: 50 is_tax_unit_head_or_spouse: true ssi: 0 + personal_property: 50 + immigration_status: CITIZEN + person2: + age: 48 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 50 + immigration_status: CITIZEN + person3: + age: 22 + is_tax_unit_head_or_spouse: false + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + households: + household: + members: [person1, person2, person3] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2, person3] + ca_scc_general_assistance_living_arrangement: NOT_SHARED + output: + # Adult child (22) is not a minor and not head/spouse -> doesn't trigger + # CalWORKs gate and doesn't add to num_eligible. Couple gets married MAP. + ca_scc_general_assistance_eligible: true + ca_scc_general_assistance_base_amount: 460 + ca_scc_general_assistance: 460 + +- name: Case 21, single adult sharing housing with three roommates — 25 percent reduction. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 32 + is_tax_unit_head_or_spouse: true + ssi: 0 personal_property: 100 immigration_status: CITIZEN - is_in_residential_care_facility: true households: household: members: [person1] @@ -436,8 +590,73 @@ spm_units: spm_unit: members: [person1] - # No explicit living_arrangement — formula derives from is_in_residential_care_facility. + ca_scc_general_assistance_living_arrangement: SHARED_WITH_THREE_OR_MORE output: - ca_scc_general_assistance_living_arrangement: BOARD_AND_CARE - ca_scc_general_assistance_base_amount: 929 - ca_scc_general_assistance: 929 + # 343 * 0.75 = 257.25 + ca_scc_general_assistance_base_amount: 257.25 + ca_scc_general_assistance: 257.25 + +- name: Case 22, three-generation household with minor grandchild — ineligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 60 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 50 + immigration_status: CITIZEN + person2: + age: 35 + is_tax_unit_head_or_spouse: false + ssi: 0 + personal_property: 50 + immigration_status: CITIZEN + person3: + age: 8 + is_tax_unit_head_or_spouse: false + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + households: + household: + members: [person1, person2, person3] + in_scc: true + spm_units: + spm_unit: + members: [person1, person2, person3] + ca_scc_general_assistance_living_arrangement: NOT_SHARED + output: + # Minor grandchild in SPM unit triggers the CalWORKs referral rule. + # Whole unit is ineligible, even though the grandparent applicant is + # not the child's parent. + ca_scc_general_assistance_eligible: false + ca_scc_general_assistance: 0 + +- name: Case 23, older single citizen with $250/month Social Security — partial benefit. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 63 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 0 + immigration_status: CITIZEN + social_security: 3_000 + households: + household: + members: [person1] + in_scc: true + spm_units: + spm_unit: + members: [person1] + ca_scc_general_assistance_living_arrangement: NOT_SHARED + output: + # 3_000 / 12 = 250 monthly unearned (no deductions on unearned). + # benefit = 343 - 250 = 93. + ca_scc_general_assistance_base_amount: 343 + ca_scc_general_assistance_countable_income: 250 + ca_scc_general_assistance: 93 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/in_scc.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/in_scc.yaml new file mode 100644 index 00000000000..e0cc5d3033d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/in_scc.yaml @@ -0,0 +1,13 @@ +- name: Santa Clara County is True + period: 2026 + input: + county_str: SANTA_CLARA_COUNTY_CA + output: + in_scc: true + +- name: Not Santa Clara County is False + period: 2026 + input: + county_str: LOS_ANGELES_COUNTY_CA + output: + in_scc: false diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance.py b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance.py index 71319898ebb..490791d89b5 100644 --- a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance.py +++ b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance.py @@ -7,7 +7,7 @@ class ca_scc_general_assistance(Variable): unit = USD definition_period = MONTH label = "Santa Clara County General Assistance" - defined_for = "ca_scc_general_assistance_income_eligible" + defined_for = "ca_scc_general_assistance_eligible" reference = "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/01Policy/Policy.htm" def formula(spm_unit, period, parameters): diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_living_arrangement.py b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_living_arrangement.py index 6741ac4dbfa..f9d1fe62dbc 100644 --- a/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_living_arrangement.py +++ b/policyengine_us/variables/gov/local/ca/scc/ga/ca_scc_general_assistance_living_arrangement.py @@ -21,21 +21,3 @@ class ca_scc_general_assistance_living_arrangement(Variable): "https://stgenssa.sccgov.org/debs/program_handbooks/charts/assets/4GA/NeedStnds.htm", "https://stgenssa.sccgov.org/debs/Forms/GA_62_en.pdf#page=2", ) - - def formula(spm_unit, period, parameters): - federal_arrangement = spm_unit.members("ssi_federal_living_arrangement", period) - in_medical = ( - federal_arrangement - == federal_arrangement.possible_values.MEDICAL_TREATMENT_FACILITY - ) - any_in_medical = spm_unit.any(in_medical) - any_in_rcf = add(spm_unit, period, ["is_in_residential_care_facility"]) > 0 - - return select( - [any_in_medical, any_in_rcf], - [ - CaSccGeneralAssistanceLivingArrangement.MEDICAL_INSTITUTION, - CaSccGeneralAssistanceLivingArrangement.BOARD_AND_CARE, - ], - default=CaSccGeneralAssistanceLivingArrangement.NOT_SHARED, - ) diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible.py b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible.py new file mode 100644 index 00000000000..2ba9e92ec99 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class ca_scc_general_assistance_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = MONTH + label = "Eligible for Santa Clara County General Assistance" + defined_for = "in_scc" + reference = ( + "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/02Application/Application_Process.htm", + "https://stgenssa.sccgov.org/debs/program_handbooks/general_assistance/assets/09Income/Potential_Inc_Res.htm", + ) + + def formula(spm_unit, period, parameters): + # Per Chapter 2 (Eligibility for Other Programs — CalWORKs) and + # Chapter 9 (Potential Income and Resources), households with a + # minor child or pregnant adult must first apply for CalWORKs. + # Only households that would not qualify for CalWORKs can fall + # back to General Assistance. + ca_tanf_eligible = spm_unit("ca_tanf_eligible", period.this_year) + has_eligible_person = ( + add(spm_unit, period, ["ca_scc_general_assistance_eligible_person"]) > 0 + ) + income_eligible = spm_unit("ca_scc_general_assistance_income_eligible", period) + return ~ca_tanf_eligible & has_eligible_person & income_eligible diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible_person.py b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible_person.py index 5de3b377aec..ac24ef7b5eb 100644 --- a/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible_person.py +++ b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible_person.py @@ -18,11 +18,16 @@ def formula(person, period, parameters): "ca_scc_general_assistance_immigration_status_eligible", period ) receives_ssi = person("ssi", period) > 0 + # Per GA 202, persons eligible for another federal or state cash aid + # program (here: CAPI for aged/blind/disabled noncitizens) are not + # eligible for General Assistance. + capi_eligible = person("ca_capi_eligible_person", period) is_head_or_spouse = person("is_tax_unit_head_or_spouse", period) return ( age_eligible & personal_property_eligible & immigration_status_eligible & ~receives_ssi + & ~capi_eligible & is_head_or_spouse ) From 8797227e80d978f49672e2c2f3e424f1585c9daf Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 26 May 2026 23:40:25 -0400 Subject: [PATCH 10/10] Fix Santa Clara GA review findings --- .../countable_income/unearned_sources.yaml | 3 +++ .../qualified_immigration_status.yaml | 1 - ...al_assistance_countable_income_person.yaml | 13 ++++++++++ ...l_assistance_earned_income_deductions.yaml | 24 +++++++++++++++++++ ...cc_general_assistance_eligible_person.yaml | 13 ++++++++++ ...ssistance_immigration_status_eligible.yaml | 4 ++-- ..._scc_general_assistance_eligible_person.py | 2 ++ ...ral_assistance_earned_income_deductions.py | 2 +- 8 files changed, 58 insertions(+), 4 deletions(-) diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/unearned_sources.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/unearned_sources.yaml index 74cc5676e8a..eee5cbcc950 100644 --- a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/unearned_sources.yaml +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/countable_income/unearned_sources.yaml @@ -2,6 +2,9 @@ description: Santa Clara County uses these unearned income sources when determin values: 2016-04-01: - social_security + - ca_state_disability_insurance + - disability_benefits + - railroad_benefits - unemployment_compensation - veterans_benefits - workers_compensation diff --git a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/qualified_immigration_status.yaml b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/qualified_immigration_status.yaml index 048b0fe8c7c..e1c2843d5ec 100644 --- a/policyengine_us/parameters/gov/local/ca/scc/general_assistance/qualified_immigration_status.yaml +++ b/policyengine_us/parameters/gov/local/ca/scc/general_assistance/qualified_immigration_status.yaml @@ -7,7 +7,6 @@ values: - ASYLEE - DEPORTATION_WITHHELD # "entitled to remain indefinitely" per GA 141 - CUBAN_HAITIAN_ENTRANT - - PAROLED_ONE_YEAR metadata: label: Santa Clara County General Assistance qualified immigration statuses period: year diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml index 3f8443c9f08..412a9d316f4 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_countable_income_person.yaml @@ -89,3 +89,16 @@ output: # SSI recipient — all income excluded per Responsible Relatives chapter. ca_scc_general_assistance_countable_income_person: 0 + +- name: Case 9, head with disability benefits, railroad benefits, and CA SDI. + period: 2024-01 + input: + is_tax_unit_head_or_spouse: true + disability_benefits: 1_200 + railroad_benefits: 2_400 + ca_state_disability_insurance: 600 + in_scc: true + absolute_error_margin: 0.1 + output: + # (1_200 + 2_400 + 600) / 12 = 350. + ca_scc_general_assistance_countable_income_person: 350 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_earned_income_deductions.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_earned_income_deductions.yaml index ecd9b0d27ca..395231e097d 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_earned_income_deductions.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_earned_income_deductions.yaml @@ -30,3 +30,27 @@ output: # Deductions only apply to earned income; pure unearned income generates none. ca_scc_general_assistance_earned_income_deductions: 0 + +- name: Case 4, state withheld income tax is deducted from earned income. + period: 2024-01 + input: + people: + person1: + is_tax_unit_head_or_spouse: true + employment_income: 12_000 + employee_social_security_tax: 0 + employee_medicare_tax: 0 + ca_employee_state_disability_insurance_contribution: 0 + tax_units: + tax_unit: + members: [person1] + income_tax_before_credits: 0 + state_withheld_income_tax: 120 + state_income_tax: 0 + households: + household: + members: [person1] + in_scc: true + absolute_error_margin: 0.1 + output: + ca_scc_general_assistance_earned_income_deductions: 10 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible_person.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible_person.yaml index 42c21cf61e0..4765177da49 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible_person.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_eligible_person.yaml @@ -109,3 +109,16 @@ # Per GA 202, eligibility for another federal/state cash aid program # disqualifies them from GA. ca_scc_general_assistance_eligible_person: false + +- name: Case 10, ineligible while actively self-employed. + period: 2024-01 + input: + age: 30 + is_tax_unit_head_or_spouse: true + ssi: 0 + personal_property: 100 + immigration_status: CITIZEN + is_self_employed: true + in_scc: true + output: + ca_scc_general_assistance_eligible_person: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_immigration_status_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_immigration_status_eligible.yaml index 48910d63953..541560c42e6 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_immigration_status_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/scc/ga/ca_scc_general_assistance_immigration_status_eligible.yaml @@ -38,13 +38,13 @@ output: ca_scc_general_assistance_immigration_status_eligible: true -- name: Case 6, paroled one year is eligible. +- name: Case 6, paroled one year is ineligible because SCC requires indefinite parole. period: 2024 input: in_scc: true immigration_status: PAROLED_ONE_YEAR output: - ca_scc_general_assistance_immigration_status_eligible: true + ca_scc_general_assistance_immigration_status_eligible: false - name: Case 7, undocumented is ineligible. period: 2024 diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible_person.py b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible_person.py index ac24ef7b5eb..ac54bf6e061 100644 --- a/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible_person.py +++ b/policyengine_us/variables/gov/local/ca/scc/ga/eligibility/ca_scc_general_assistance_eligible_person.py @@ -22,6 +22,7 @@ def formula(person, period, parameters): # program (here: CAPI for aged/blind/disabled noncitizens) are not # eligible for General Assistance. capi_eligible = person("ca_capi_eligible_person", period) + is_self_employed = person("is_self_employed", period.this_year) is_head_or_spouse = person("is_tax_unit_head_or_spouse", period) return ( age_eligible @@ -29,5 +30,6 @@ def formula(person, period, parameters): & immigration_status_eligible & ~receives_ssi & ~capi_eligible + & ~is_self_employed & is_head_or_spouse ) diff --git a/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_earned_income_deductions.py b/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_earned_income_deductions.py index c16d977f25c..ddb5f41771c 100644 --- a/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_earned_income_deductions.py +++ b/policyengine_us/variables/gov/local/ca/scc/ga/income/ca_scc_general_assistance_earned_income_deductions.py @@ -23,5 +23,5 @@ def formula(person, period, parameters): tax_unit_earned = person.tax_unit("tax_unit_earned_income", period) share = where(tax_unit_earned > 0, person_earned / tax_unit_earned, 0) federal_tax = person.tax_unit("income_tax_before_credits", period) * share - state_tax = person.tax_unit("state_income_tax", period) * share + state_tax = person.tax_unit("state_withheld_income_tax", period) * share return person_level + federal_tax + state_tax