From 1457524e372be01175ac0361ed314cee7060e674 Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 5 Jun 2026 10:19:11 -0400 Subject: [PATCH 1/5] Add changelog fragment for Contra Costa County GA Co-Authored-By: Claude Opus 4.8 (1M context) --- changelog.d/ca-contra-costa-ga.added.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/ca-contra-costa-ga.added.md diff --git a/changelog.d/ca-contra-costa-ga.added.md b/changelog.d/ca-contra-costa-ga.added.md new file mode 100644 index 00000000000..75bd2623147 --- /dev/null +++ b/changelog.d/ca-contra-costa-ga.added.md @@ -0,0 +1 @@ +Added Contra Costa County, CA General Assistance program. From 2e8349d66a9db53acfff2fcc2c6fcf6cf53d68b2 Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 5 Jun 2026 11:54:23 -0400 Subject: [PATCH 2/5] Implement Contra Costa County, CA General Assistance Add the county-administered General Assistance (GA) cash-relief program (CA Welfare & Institutions Code section 17000 et seq.): - Fill-the-gap benefit: max_(grant standard - max_(countable income, 0), 0), with the inner floor guarding against negative-income inflation. - Grant standards: single $336/month (stable since 2011 per WCLP), couple $454/month (current EHSD). - Eligibility: age >= 18; $500 personal-property limit; qualified immigration status; no dependent children (families -> CalWORKs); not receiving SSI/SSDI/UIB/SDI; Contra Costa County residence. - Register the program in programs.yaml. - 46 unit/integration tests, all passing. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../cc/general_assistance/age_threshold.yaml | 12 + .../cc/general_assistance/amount/married.yaml | 10 + .../cc/general_assistance/amount/single.yaml | 12 + .../countable_income/sources.yaml | 17 + .../personal_property/limit.yaml | 12 + .../qualified_immigration_status.yaml | 17 + policyengine_us/programs.yaml | 10 + .../ca/cc/ga/ca_cc_general_assistance.yaml | 320 ++++++++++++++++++ .../ca_cc_general_assistance_base_amount.yaml | 67 ++++ ...ca_cc_general_assistance_age_eligible.yaml | 23 ++ ...cc_general_assistance_eligible_person.yaml | 181 ++++++++++ ...ssistance_immigration_status_eligible.yaml | 31 ++ ...cc_general_assistance_income_eligible.yaml | 65 ++++ ...assistance_personal_property_eligible.yaml | 49 +++ .../baseline/gov/local/ca/cc/ga/in_cc.yaml | 13 + ...c_general_assistance_countable_income.yaml | 40 +++ ...al_assistance_countable_income_person.yaml | 32 ++ .../ca/cc/ga/ca_cc_general_assistance.py | 22 ++ .../ca_cc_general_assistance_base_amount.py | 22 ++ .../ca_cc_general_assistance_age_eligible.py | 17 + ...a_cc_general_assistance_eligible_person.py | 36 ++ ..._assistance_immigration_status_eligible.py | 16 + ...a_cc_general_assistance_income_eligible.py | 23 ++ ...l_assistance_personal_property_eligible.py | 21 ++ ..._cc_general_assistance_countable_income.py | 13 + ...eral_assistance_countable_income_person.py | 13 + .../variables/gov/local/ca/cc/in_cc.py | 12 + 27 files changed, 1106 insertions(+) create mode 100644 policyengine_us/parameters/gov/local/ca/cc/general_assistance/age_threshold.yaml create mode 100644 policyengine_us/parameters/gov/local/ca/cc/general_assistance/amount/married.yaml create mode 100644 policyengine_us/parameters/gov/local/ca/cc/general_assistance/amount/single.yaml create mode 100644 policyengine_us/parameters/gov/local/ca/cc/general_assistance/countable_income/sources.yaml create mode 100644 policyengine_us/parameters/gov/local/ca/cc/general_assistance/personal_property/limit.yaml create mode 100644 policyengine_us/parameters/gov/local/ca/cc/general_assistance/qualified_immigration_status.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_age_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible_person.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_personal_property_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/in_cc.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income_person.yaml create mode 100644 policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance.py create mode 100644 policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.py create mode 100644 policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_age_eligible.py create mode 100644 policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible_person.py create mode 100644 policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.py create mode 100644 policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.py create mode 100644 policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_personal_property_eligible.py create mode 100644 policyengine_us/variables/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income.py create mode 100644 policyengine_us/variables/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income_person.py create mode 100644 policyengine_us/variables/gov/local/ca/cc/in_cc.py diff --git a/policyengine_us/parameters/gov/local/ca/cc/general_assistance/age_threshold.yaml b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/age_threshold.yaml new file mode 100644 index 00000000000..d984925a775 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/age_threshold.yaml @@ -0,0 +1,12 @@ +description: Contra Costa County limits the General Assistance program to individuals of this age or older. +metadata: + label: Contra Costa County General Assistance age eligibility threshold + unit: year + period: year + reference: + - title: Contra Costa County EHSD - General Assistance + href: https://ehsd.org/aging-and-adult-services/general-assistance/ + - title: Legal Services of Northern California - General Assistance + href: https://lsnc.net/self-help/general-assistance-county-aid +values: + 2011-01-01: 18 diff --git a/policyengine_us/parameters/gov/local/ca/cc/general_assistance/amount/married.yaml b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/amount/married.yaml new file mode 100644 index 00000000000..6a9b072a58d --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/amount/married.yaml @@ -0,0 +1,10 @@ +description: Contra Costa County provides a cash grant of this amount to married filers under the General Assistance program. +metadata: + label: Contra Costa County General Assistance married amount + period: month + unit: currency-USD + reference: + - title: Contra Costa County EHSD - General Assistance + href: https://ehsd.org/aging-and-adult-services/general-assistance/ +values: + 2024-01-01: 454 diff --git a/policyengine_us/parameters/gov/local/ca/cc/general_assistance/amount/single.yaml b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/amount/single.yaml new file mode 100644 index 00000000000..8c56d7d2fe4 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/amount/single.yaml @@ -0,0 +1,12 @@ +description: Contra Costa County provides a cash grant of this amount to single filers under the General Assistance program. +metadata: + label: Contra Costa County General Assistance single amount + period: month + unit: currency-USD + reference: + - title: Western Center on Law & Poverty - General Relief Grant Levels 2011 ($178 housing + $158 food/needs = $336) + href: https://wclp.org/wp-content/uploads/2015/06/gr_grantlevels_2011.pdf#page=1 + - title: Contra Costa County EHSD - General Assistance + href: https://ehsd.org/aging-and-adult-services/general-assistance/ +values: + 2011-01-01: 336 diff --git a/policyengine_us/parameters/gov/local/ca/cc/general_assistance/countable_income/sources.yaml b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/countable_income/sources.yaml new file mode 100644 index 00000000000..8f185220190 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/countable_income/sources.yaml @@ -0,0 +1,17 @@ +description: Contra Costa County accounts for these income sources when determining eligibility for the General Assistance program. +values: + 2011-01-01: + - employment_income + - self_employment_income + - sstb_self_employment_income + - social_security + - unemployment_compensation + - veterans_benefits + +metadata: + unit: list + period: year + label: Contra Costa County General Assistance income sources + reference: + - title: Contra Costa County EHSD - General Assistance + href: https://ehsd.org/aging-and-adult-services/general-assistance/ diff --git a/policyengine_us/parameters/gov/local/ca/cc/general_assistance/personal_property/limit.yaml b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/personal_property/limit.yaml new file mode 100644 index 00000000000..ab6b9551683 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/personal_property/limit.yaml @@ -0,0 +1,12 @@ +description: Contra Costa County limits the General Assistance program to households with up to this personal property amount. +metadata: + label: Contra Costa County General Assistance personal property limit amount + unit: currency-USD + period: year + reference: + - title: Contra Costa County EHSD - General Assistance + href: https://ehsd.org/aging-and-adult-services/general-assistance/ + - title: Contra Costa County EHSD - General Assistance Brochure (GA-80, Rev. 7/2024) + href: https://ehsd.org/wp-content/uploads/2024/08/GA-Brochure_ENGLISH_July2024_FA_Digital.pdf#page=2 +values: + 2011-01-01: 500 diff --git a/policyengine_us/parameters/gov/local/ca/cc/general_assistance/qualified_immigration_status.yaml b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/qualified_immigration_status.yaml new file mode 100644 index 00000000000..3558f389e3c --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/qualified_immigration_status.yaml @@ -0,0 +1,17 @@ +description: Contra Costa County considers these statuses as qualified immigrants under the General Assistance program. +values: + 2011-01-01: + - CITIZEN + - REFUGEE + - ASYLEE + - CUBAN_HAITIAN_ENTRANT + - PAROLED_ONE_YEAR + - LEGAL_PERMANENT_RESIDENT + +metadata: + label: Contra Costa County General Assistance qualified immigration statuses + period: year + unit: list + reference: + - title: Contra Costa County EHSD - General Assistance + href: https://ehsd.org/aging-and-adult-services/general-assistance/ diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index ade1f4b04ab..1d1ccb965b3 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1332,6 +1332,16 @@ programs: variable: ca_ala_general_assistance parameter_prefix: gov.local.ca.ala.ga + - id: ca_cc_general_assistance + name: Contra Costa County General Assistance + full_name: Contra Costa County General Assistance + category: Benefits + agency: Local + status: complete + coverage: Contra Costa County + variable: ca_cc_general_assistance + parameter_prefix: gov.local.ca.cc.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/cc/ga/ca_cc_general_assistance.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance.yaml new file mode 100644 index 00000000000..a3b1b3fa65c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance.yaml @@ -0,0 +1,320 @@ +# Contra Costa County General Assistance (GA) — top-level fill-the-gap benefit. +# Benefit = max_(grant standard - max_(countable income, 0), 0). +# Single MAP = $336/month, couple MAP = $454/month. +# Zero-benefit cases assert both the amount and the eligibility boolean; positive +# cases assert eligibility == true. + +- name: Single eligible adult with low income receives a positive fill-the-gap grant. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 300 * 12 # $300/month countable + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + # 336 single MAP - 300 countable = 36 + ca_cc_general_assistance_income_eligible: true + ca_cc_general_assistance: 36 + +- name: Couple of two eligible adults receives a positive fill-the-gap grant. + period: 2024-01 + input: + people: + person1: + age: 35 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 100 * 12 # $100/month countable + person2: + age: 33 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + households: + household: + members: [person1, person2] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1, person2] + output: + # 454 couple MAP - 100 countable = 354 + ca_cc_general_assistance_income_eligible: true + ca_cc_general_assistance: 354 + +- name: Negative self-employment income caps the grant at the MAP, not above it. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + self_employment_income: -6_000 * 12 # -$6,000/month business loss, no other income + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + # Countable income = -6,000. The explicit formula floors income at zero: + # max_(336 - max_(-6000, 0), 0) = 336. An adds/subtracts framework would + # instead give 336 - (-6000) = 6,336 (inflated) -- this is the regression guard. + ca_cc_general_assistance_income_eligible: true + ca_cc_general_assistance: 336 + +- name: Asset limit boundary - $499 personal property is eligible. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 499 + employment_income: 300 * 12 # $300/month countable + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + # 336 single MAP - 300 countable = 36 + ca_cc_general_assistance_income_eligible: true + ca_cc_general_assistance: 36 + +- name: Asset limit boundary - $501 personal property is ineligible. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 501 # exceeds the $500 limit + employment_income: 300 * 12 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_income_eligible: false + ca_cc_general_assistance: 0 + +- name: Categorical exclusion - receiving SSI makes the unit ineligible. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 100 * 12 + ssi: 100 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_income_eligible: false + ca_cc_general_assistance: 0 + +- name: Categorical exclusion - receiving SSDI makes the unit ineligible. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 100 * 12 + social_security_disability: 1_200 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_income_eligible: false + ca_cc_general_assistance: 0 + +- name: Categorical exclusion - receiving unemployment compensation makes the unit ineligible. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 100 * 12 + unemployment_compensation: 1_200 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_income_eligible: false + ca_cc_general_assistance: 0 + +- name: Categorical exclusion - receiving CA state disability insurance makes the unit ineligible. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 100 * 12 + ca_state_disability_insurance: 1_200 + households: + household: + members: [person1] + state_code: CA + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_income_eligible: false + ca_cc_general_assistance: 0 + +- name: No-children gate - adult with a dependent child is ineligible. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 100 * 12 # income below MAP, but the no-children gate fails + child1: + age: 5 + is_tax_unit_head_or_spouse: false + households: + household: + members: [person1, child1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1, child1] + output: + spm_unit_count_children: 1 + ca_cc_general_assistance_income_eligible: false + ca_cc_general_assistance: 0 + +- name: Immigration - a qualified refugee adult is eligible. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: REFUGEE + personal_property: 0 + employment_income: 300 * 12 # $300/month countable + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + # 336 single MAP - 300 countable = 36 + ca_cc_general_assistance_income_eligible: true + ca_cc_general_assistance: 36 + +- name: Immigration - a non-qualified (undocumented) adult is ineligible. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: UNDOCUMENTED + personal_property: 0 + employment_income: 300 * 12 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_income_eligible: false + ca_cc_general_assistance: 0 + +- name: Age - an applicant under 18 is ineligible. + period: 2024-01 + input: + people: + person1: + age: 17 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 100 * 12 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_income_eligible: false + ca_cc_general_assistance: 0 + +- name: Out of jurisdiction - an otherwise-eligible unit in another county gets nothing (defined_for gate). + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 300 * 12 # would yield $36 in Contra Costa + households: + household: + members: [person1] + county: ALAMEDA_COUNTY_CA # not Contra Costa -> in_cc is false + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_income_eligible: false + ca_cc_general_assistance: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.yaml new file mode 100644 index 00000000000..4e4b4054715 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.yaml @@ -0,0 +1,67 @@ +# Grant standard (MAP): single (1 eligible person) = $336/month; +# couple (2 eligible persons) = $454/month (unit total). +- name: One eligible adult receives the single grant standard of $336. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + ssi: 0 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_base_amount: 336 + +- name: Two eligible adults receive the couple grant standard of $454. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + ssi: 0 + person2: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + ssi: 0 + households: + household: + members: [person1, person2] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1, person2] + output: + ca_cc_general_assistance_base_amount: 454 + +- name: No eligible persons yields a base amount of zero. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + ssi: 100 # receiving SSI makes the person ineligible + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_base_amount: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_age_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_age_eligible.yaml new file mode 100644 index 00000000000..23293f63e4f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_age_eligible.yaml @@ -0,0 +1,23 @@ +- name: Adult aged 18 meets the age threshold. + period: 2024-01 + input: + age: 18 + county: CONTRA_COSTA_COUNTY_CA + output: + ca_cc_general_assistance_age_eligible: true + +- name: Adult aged 30 meets the age threshold. + period: 2024-01 + input: + age: 30 + county: CONTRA_COSTA_COUNTY_CA + output: + ca_cc_general_assistance_age_eligible: true + +- name: Minor aged 17 does not meet the age threshold. + period: 2024-01 + input: + age: 17 + county: CONTRA_COSTA_COUNTY_CA + output: + ca_cc_general_assistance_age_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible_person.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible_person.yaml new file mode 100644 index 00000000000..ff711f7922b --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible_person.yaml @@ -0,0 +1,181 @@ +# Per-person eligibility: age >= 18 AND personal property <= $500 AND qualified +# immigration status AND NOT receiving SSI/SSDI/UIB/SDI AND tax-unit head or spouse. +- name: Fully eligible adult. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 400 + ssi: 0 + social_security_disability: 0 + unemployment_compensation: 0 + ca_state_disability_insurance: 0 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_eligible_person: true + +- name: Ineligible because under age 18. + period: 2024-01 + input: + people: + person1: + age: 17 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 400 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_eligible_person: false + +- name: Ineligible because personal property exceeds the $500 limit. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 600 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_eligible_person: false + +- name: Ineligible because of a non-qualified immigration status. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: UNDOCUMENTED + personal_property: 400 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_eligible_person: false + +- name: Ineligible because not a tax-unit head or spouse. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: false + immigration_status: CITIZEN + personal_property: 400 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_eligible_person: false + +- name: Ineligible because receiving SSI. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 400 + ssi: 100 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_eligible_person: false + +- name: Ineligible because receiving SSDI. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 400 + social_security_disability: 1_200 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_eligible_person: false + +- name: Ineligible because receiving unemployment compensation. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 400 + unemployment_compensation: 1_200 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_eligible_person: false + +- name: Ineligible because receiving CA state disability insurance. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 400 + ca_state_disability_insurance: 1_200 + households: + household: + members: [person1] + state_code: CA + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_eligible_person: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.yaml new file mode 100644 index 00000000000..37659ac30c5 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.yaml @@ -0,0 +1,31 @@ +- name: US citizen is a qualified immigration status. + period: 2024-01 + input: + immigration_status: CITIZEN + county: CONTRA_COSTA_COUNTY_CA + output: + ca_cc_general_assistance_immigration_status_eligible: true + +- name: Refugee is a qualified immigration status. + period: 2024-01 + input: + immigration_status: REFUGEE + county: CONTRA_COSTA_COUNTY_CA + output: + ca_cc_general_assistance_immigration_status_eligible: true + +- name: Legal permanent resident is a qualified immigration status. + period: 2024-01 + input: + immigration_status: LEGAL_PERMANENT_RESIDENT + county: CONTRA_COSTA_COUNTY_CA + output: + ca_cc_general_assistance_immigration_status_eligible: true + +- name: Undocumented is not a qualified immigration status. + period: 2024-01 + input: + immigration_status: UNDOCUMENTED + county: CONTRA_COSTA_COUNTY_CA + output: + ca_cc_general_assistance_immigration_status_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.yaml new file mode 100644 index 00000000000..2d02f492cad --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.yaml @@ -0,0 +1,65 @@ +# Income eligible when countable income < grant standard (MAP) AND the unit has no +# dependent children (strict no-children gate). Single MAP = $336/month. +- name: Eligible single adult with income below the $336 single MAP and no children. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 300 * 12 # $300/month countable < $336 MAP + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_income_eligible: true + +- name: Ineligible single adult with income above the $336 single MAP. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 400 * 12 # $400/month countable > $336 MAP + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_income_eligible: false + +- name: Ineligible adult with income below MAP but a dependent child (strict gate). + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 300 * 12 # below MAP, but the no-children gate fails + child1: + age: 5 + is_tax_unit_head_or_spouse: false + households: + household: + members: [person1, child1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1, child1] + output: + spm_unit_count_children: 1 + ca_cc_general_assistance_income_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_personal_property_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_personal_property_eligible.yaml new file mode 100644 index 00000000000..ef4e0ff8d6f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_personal_property_eligible.yaml @@ -0,0 +1,49 @@ +# Asset limit is $500. Formula is personal_property <= limit, +# so $500 exactly is eligible. +- name: Personal property of $499 is below the $500 limit. + period: 2024-01 + input: + people: + person1: + personal_property: 499 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_personal_property_eligible: true + +- name: Personal property of exactly $500 is at the limit and eligible. + period: 2024-01 + input: + people: + person1: + personal_property: 500 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_personal_property_eligible: true + +- name: Personal property of $501 exceeds the $500 limit. + period: 2024-01 + input: + people: + person1: + personal_property: 501 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_personal_property_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/in_cc.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/in_cc.yaml new file mode 100644 index 00000000000..a521b268d5e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/in_cc.yaml @@ -0,0 +1,13 @@ +- name: Contra Costa County is True + period: 2024 + input: + county: CONTRA_COSTA_COUNTY_CA + output: + in_cc: true + +- name: Not Contra Costa County is False + period: 2024 + input: + county: ALAMEDA_COUNTY_CA + output: + in_cc: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income.yaml new file mode 100644 index 00000000000..3fcf00f4473 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income.yaml @@ -0,0 +1,40 @@ +# SPMUnit countable income sums each head/spouse member's countable income. +- name: Single adult with employment income. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + employment_income: 500 * 12 # $500/month + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_countable_income: 500 + +- name: Two head/spouse members' income sums to the unit total. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + employment_income: 500 * 12 # $500/month + person2: + age: 30 + is_tax_unit_head_or_spouse: true + social_security: 200 * 12 # $200/month + households: + household: + members: [person1, person2] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1, person2] + output: + ca_cc_general_assistance_countable_income: 700 # 500 + 200 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income_person.yaml new file mode 100644 index 00000000000..5e56bcdc49c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income_person.yaml @@ -0,0 +1,32 @@ +# Per-person countable income sums the income sources in countable_income/sources.yaml, +# only for tax-unit heads or spouses. Sources are annual; the monthly variable +# auto-divides by 12. +- name: Head/spouse employment income counts at the monthly level. + period: 2024-01 + input: + age: 30 + is_tax_unit_head_or_spouse: true + employment_income: 1_200 * 12 # $1,200/month + county: CONTRA_COSTA_COUNTY_CA + output: + ca_cc_general_assistance_countable_income_person: 1_200 + +- name: Non-head/spouse income is excluded. + period: 2024-01 + input: + age: 30 + is_tax_unit_head_or_spouse: false + employment_income: 1_200 * 12 + county: CONTRA_COSTA_COUNTY_CA + output: + ca_cc_general_assistance_countable_income_person: 0 + +- name: Negative self-employment income produces negative countable income. + period: 2024-01 + input: + age: 30 + is_tax_unit_head_or_spouse: true + self_employment_income: -6_000 * 12 # -$6,000/month business loss + county: CONTRA_COSTA_COUNTY_CA + output: + ca_cc_general_assistance_countable_income_person: -6_000 diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance.py b/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance.py new file mode 100644 index 00000000000..1ec24ce4f21 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class ca_cc_general_assistance(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "Contra Costa County General Assistance" + definition_period = MONTH + defined_for = "ca_cc_general_assistance_income_eligible" + reference = ( + "https://ehsd.org/aging-and-adult-services/general-assistance/", + # Fill-the-gap: the grant standard minus net countable income. + "https://ehsd.org/wp-content/uploads/2024/08/GA-Brochure_ENGLISH_July2024_FA_Digital.pdf#page=2", + ) + + def formula(spm_unit, period, parameters): + base_amount = spm_unit("ca_cc_general_assistance_base_amount", period) + countable_income = spm_unit("ca_cc_general_assistance_countable_income", period) + # Floor countable income at zero so net-negative flows (e.g. self- + # employment losses) cannot inflate the grant above the standard. + return max_(base_amount - max_(countable_income, 0), 0) diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.py b/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.py new file mode 100644 index 00000000000..dea5d8f029c --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class ca_cc_general_assistance_base_amount(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "Contra Costa County General Assistance base amount" + definition_period = MONTH + defined_for = "ca_cc_general_assistance_eligible_person" + reference = "https://ehsd.org/aging-and-adult-services/general-assistance/" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.local.ca.cc.general_assistance.amount + eligible_persons = spm_unit.members( + "ca_cc_general_assistance_eligible_person", period + ) + num_eligible = spm_unit.sum(eligible_persons) + # When two adults in the unit are eligible we apply the couple grant. We + # do not verify that the two eligible adults are married to each other; + # we don't track marital pairing within the SPM unit at the moment. + return where(num_eligible == 2, p.married, p.single) diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_age_eligible.py b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_age_eligible.py new file mode 100644 index 00000000000..3263df880b2 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_age_eligible.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class ca_cc_general_assistance_age_eligible(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = ( + "Eligible for Contra Costa County General Assistance based on age requirements" + ) + defined_for = "in_cc" + reference = "https://ehsd.org/aging-and-adult-services/general-assistance/" + + def formula(person, period, parameters): + p = parameters(period).gov.local.ca.cc.general_assistance + age = person("monthly_age", period) + return age >= p.age_threshold diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible_person.py b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible_person.py new file mode 100644 index 00000000000..a2caa92f236 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible_person.py @@ -0,0 +1,36 @@ +from policyengine_us.model_api import * + + +class ca_cc_general_assistance_eligible_person(Variable): + value_type = bool + entity = Person + label = "Eligible person for Contra Costa County General Assistance" + definition_period = MONTH + defined_for = "in_cc" + reference = "https://ehsd.org/aging-and-adult-services/general-assistance/" + + def formula(person, period, parameters): + age_eligible = person("ca_cc_general_assistance_age_eligible", period) + personal_property_eligible = person.spm_unit( + "ca_cc_general_assistance_personal_property_eligible", period + ) + immigration_status_eligible = person( + "ca_cc_general_assistance_immigration_status_eligible", period + ) + # Ineligible if receiving SSI, SSDI, unemployment (UIB), or California + # State Disability Insurance (SDI). SSDI, UIB, and SDI are YEAR-defined; + # we read the full annual value with period.this_year and test receipt (> 0). + receives_categorical = ( + (person("ssi", period) > 0) + | (person("social_security_disability", period.this_year) > 0) + | (person("unemployment_compensation", period.this_year) > 0) + | (person("ca_state_disability_insurance", period.this_year) > 0) + ) + is_head_or_spouse = person("is_tax_unit_head_or_spouse", period) + return ( + age_eligible + & personal_property_eligible + & immigration_status_eligible + & ~receives_categorical + & is_head_or_spouse + ) diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.py b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.py new file mode 100644 index 00000000000..c38a8af91be --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class ca_cc_general_assistance_immigration_status_eligible(Variable): + value_type = bool + entity = Person + label = "Eligible for the Contra Costa County General Assistance due to immigration status" + definition_period = MONTH + defined_for = "in_cc" + reference = "https://ehsd.org/aging-and-adult-services/general-assistance/" + + def formula(person, period, parameters): + p = parameters(period).gov.local.ca.cc.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/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.py b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.py new file mode 100644 index 00000000000..8bcc3dcfafd --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class ca_cc_general_assistance_income_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Contra Costa County General Assistance based on income requirements" + definition_period = MONTH + defined_for = "in_cc" + reference = ( + "https://ehsd.org/aging-and-adult-services/general-assistance/", + # Adults with dependent children apply for CalWORKs instead, so the unit + # must have no children (GA-80 brochure, "adult without dependent children"). + "https://ehsd.org/wp-content/uploads/2024/08/GA-Brochure_ENGLISH_July2024_FA_Digital.pdf#page=2", + ) + + def formula(spm_unit, period, parameters): + income = spm_unit("ca_cc_general_assistance_countable_income", period) + base_amount = spm_unit("ca_cc_general_assistance_base_amount", period) + # General Assistance serves adults without dependent children; families + # with children are directed to CalWORKs. + no_children = spm_unit("spm_unit_count_children", period.this_year) == 0 + return (income < base_amount) & no_children diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_personal_property_eligible.py b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_personal_property_eligible.py new file mode 100644 index 00000000000..2932d0201b0 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_personal_property_eligible.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class ca_cc_general_assistance_personal_property_eligible(Variable): + value_type = bool + entity = SPMUnit + definition_period = MONTH + label = "Meets property limit for Contra Costa County General Assistance" + defined_for = "in_cc" + reference = ( + "https://ehsd.org/aging-and-adult-services/general-assistance/", + # Resource exclusions (home, one vehicle <= $4,500, jewelry, property-tax + # escrow, cash < $50) are listed in the GA-80 brochure but are not modeled + # separately; we treat `personal_property` as the net countable-asset figure. + "https://ehsd.org/wp-content/uploads/2024/08/GA-Brochure_ENGLISH_July2024_FA_Digital.pdf#page=2", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.local.ca.cc.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/cc/ga/income/ca_cc_general_assistance_countable_income.py b/policyengine_us/variables/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income.py new file mode 100644 index 00000000000..a1e0d8d95bd --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class ca_cc_general_assistance_countable_income(Variable): + value_type = float + entity = SPMUnit + unit = USD + definition_period = MONTH + label = "Contra Costa County General Assistance countable income" + defined_for = "in_cc" + reference = "https://ehsd.org/aging-and-adult-services/general-assistance/" + + adds = ["ca_cc_general_assistance_countable_income_person"] diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income_person.py b/policyengine_us/variables/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income_person.py new file mode 100644 index 00000000000..bb22ca9a536 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/cc/ga/income/ca_cc_general_assistance_countable_income_person.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class ca_cc_general_assistance_countable_income_person(Variable): + value_type = float + entity = Person + unit = USD + definition_period = MONTH + label = "Contra Costa County General Assistance countable income for each person" + defined_for = "is_tax_unit_head_or_spouse" + reference = "https://ehsd.org/aging-and-adult-services/general-assistance/" + + adds = "gov.local.ca.cc.general_assistance.countable_income.sources" diff --git a/policyengine_us/variables/gov/local/ca/cc/in_cc.py b/policyengine_us/variables/gov/local/ca/cc/in_cc.py new file mode 100644 index 00000000000..6d062adebfa --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/cc/in_cc.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class in_cc(Variable): + value_type = bool + entity = Household + definition_period = YEAR + label = "Is in Contra Costa County" + + def formula(household, period, parameters): + county = household("county_str", period) + return county == "CONTRA_COSTA_COUNTY_CA" From c8e353d77aa20bc4fb756012b2603e462b6528e9 Mon Sep 17 00:00:00 2001 From: Ziming Date: Sun, 7 Jun 2026 00:16:14 -0400 Subject: [PATCH 3/5] Address PR review for Contra Costa County GA - Date couple grant ($454) at 2011-01-01 to match the stable single rate; document the frozen-standards rationale (single $336 unchanged since 2011). - Drop PAROLED_ONE_YEAR from qualified immigration statuses (time-limited parole conflicts with EHSD's 'no limitation on stay'); aligns with Santa Clara (#8358) and San Mateo (#8360) County GA. Add comment + test. - Re-anchor personal-property limit, fill-the-gap, and no-children references from the GA-80 brochure (which lacks those figures) to the EHSD program page. - Note only SSDI bars eligibility; OASDI retirement/survivors count as income. - Add tests: income=0 -> full $336, income==$336 -> ineligible/$0, three eligible adults -> single $336, personal property summed across members. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../cc/general_assistance/amount/married.yaml | 6 ++- .../personal_property/limit.yaml | 2 - .../qualified_immigration_status.yaml | 1 - .../ca/cc/ga/ca_cc_general_assistance.yaml | 42 +++++++++++++++++++ .../ca_cc_general_assistance_base_amount.yaml | 33 +++++++++++++++ ...ssistance_immigration_status_eligible.yaml | 8 ++++ ...cc_general_assistance_income_eligible.yaml | 20 +++++++++ ...assistance_personal_property_eligible.yaml | 20 +++++++++ .../ca/cc/ga/ca_cc_general_assistance.py | 11 ++--- ...a_cc_general_assistance_eligible_person.py | 4 ++ ..._assistance_immigration_status_eligible.py | 5 +++ ...a_cc_general_assistance_income_eligible.py | 9 ++-- 12 files changed, 144 insertions(+), 17 deletions(-) diff --git a/policyengine_us/parameters/gov/local/ca/cc/general_assistance/amount/married.yaml b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/amount/married.yaml index 6a9b072a58d..a5feba65b0e 100644 --- a/policyengine_us/parameters/gov/local/ca/cc/general_assistance/amount/married.yaml +++ b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/amount/married.yaml @@ -7,4 +7,8 @@ metadata: - title: Contra Costa County EHSD - General Assistance href: https://ehsd.org/aging-and-adult-services/general-assistance/ values: - 2024-01-01: 454 + # The single rate ($336) is unchanged from the 2011 WCLP grant table to the + # current EHSD page, so the GA grant standards appear frozen. We apply the + # current $454 couple rate back to 2011-01-01 on that same stability basis + # (the EHSD page lists $336 single and $454 couple together, undated). + 2011-01-01: 454 diff --git a/policyengine_us/parameters/gov/local/ca/cc/general_assistance/personal_property/limit.yaml b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/personal_property/limit.yaml index ab6b9551683..e2e307ac0f9 100644 --- a/policyengine_us/parameters/gov/local/ca/cc/general_assistance/personal_property/limit.yaml +++ b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/personal_property/limit.yaml @@ -6,7 +6,5 @@ metadata: reference: - title: Contra Costa County EHSD - General Assistance href: https://ehsd.org/aging-and-adult-services/general-assistance/ - - title: Contra Costa County EHSD - General Assistance Brochure (GA-80, Rev. 7/2024) - href: https://ehsd.org/wp-content/uploads/2024/08/GA-Brochure_ENGLISH_July2024_FA_Digital.pdf#page=2 values: 2011-01-01: 500 diff --git a/policyengine_us/parameters/gov/local/ca/cc/general_assistance/qualified_immigration_status.yaml b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/qualified_immigration_status.yaml index 3558f389e3c..843ce4f4108 100644 --- a/policyengine_us/parameters/gov/local/ca/cc/general_assistance/qualified_immigration_status.yaml +++ b/policyengine_us/parameters/gov/local/ca/cc/general_assistance/qualified_immigration_status.yaml @@ -5,7 +5,6 @@ values: - REFUGEE - ASYLEE - CUBAN_HAITIAN_ENTRANT - - PAROLED_ONE_YEAR - LEGAL_PERMANENT_RESIDENT metadata: diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance.yaml index a3b1b3fa65c..d35868d8412 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance.yaml @@ -318,3 +318,45 @@ output: ca_cc_general_assistance_income_eligible: false ca_cc_general_assistance: 0 + +- name: Single eligible adult with no income receives the full $336 grant. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + # 336 single MAP - 0 countable = 336 (full fill-the-gap grant) + ca_cc_general_assistance_income_eligible: true + ca_cc_general_assistance: 336 + +- name: Boundary - income exactly at the $336 single MAP yields no grant (strict gate). + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 336 * 12 # $336/month countable == MAP + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_income_eligible: false + ca_cc_general_assistance: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.yaml index 4e4b4054715..4b1231aab9e 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.yaml @@ -65,3 +65,36 @@ members: [person1] output: ca_cc_general_assistance_base_amount: 0 + +- name: Three eligible adults fall through to the single grant standard of $336. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + ssi: 0 + person2: + age: 32 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + ssi: 0 + person3: + age: 34 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + ssi: 0 + households: + household: + members: [person1, person2, person3] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1, person2, person3] + output: + # num_eligible == 3 -> where(num_eligible == 2, ...) is false -> single $336 + ca_cc_general_assistance_base_amount: 336 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.yaml index 37659ac30c5..a958de31401 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.yaml @@ -29,3 +29,11 @@ county: CONTRA_COSTA_COUNTY_CA output: ca_cc_general_assistance_immigration_status_eligible: false + +- name: Paroled for one year is not a qualified status (time-limited parole). + period: 2024-01 + input: + immigration_status: PAROLED_ONE_YEAR + county: CONTRA_COSTA_COUNTY_CA + output: + ca_cc_general_assistance_immigration_status_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.yaml index 2d02f492cad..b935206a218 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.yaml @@ -63,3 +63,23 @@ output: spm_unit_count_children: 1 ca_cc_general_assistance_income_eligible: false + +- name: Boundary - income exactly at the $336 single MAP is ineligible (strict < gate). + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 336 * 12 # $336/month countable == MAP, not strictly below + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_income_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_personal_property_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_personal_property_eligible.yaml index ef4e0ff8d6f..e3f988b8c99 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_personal_property_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_personal_property_eligible.yaml @@ -47,3 +47,23 @@ members: [person1] output: ca_cc_general_assistance_personal_property_eligible: false + +# Personal property is summed across all SPM-unit members, so two members each +# holding $300 ($600 total) exceed the $500 limit. +- name: Two members with $300 each ($600 total) exceed the $500 limit. + period: 2024-01 + input: + people: + person1: + personal_property: 300 + person2: + personal_property: 300 + households: + household: + members: [person1, person2] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1, person2] + output: + ca_cc_general_assistance_personal_property_eligible: false diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance.py b/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance.py index 1ec24ce4f21..10f734bee1b 100644 --- a/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance.py +++ b/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance.py @@ -8,15 +8,12 @@ class ca_cc_general_assistance(Variable): label = "Contra Costa County General Assistance" definition_period = MONTH defined_for = "ca_cc_general_assistance_income_eligible" - reference = ( - "https://ehsd.org/aging-and-adult-services/general-assistance/", - # Fill-the-gap: the grant standard minus net countable income. - "https://ehsd.org/wp-content/uploads/2024/08/GA-Brochure_ENGLISH_July2024_FA_Digital.pdf#page=2", - ) + reference = "https://ehsd.org/aging-and-adult-services/general-assistance/" def formula(spm_unit, period, parameters): base_amount = spm_unit("ca_cc_general_assistance_base_amount", period) countable_income = spm_unit("ca_cc_general_assistance_countable_income", period) - # Floor countable income at zero so net-negative flows (e.g. self- - # employment losses) cannot inflate the grant above the standard. + # Fill-the-gap: the grant standard minus net countable income. Floor + # countable income at zero so net-negative flows (e.g. self-employment + # losses) cannot inflate the grant above the standard. return max_(base_amount - max_(countable_income, 0), 0) diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible_person.py b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible_person.py index a2caa92f236..de72b985d9f 100644 --- a/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible_person.py +++ b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible_person.py @@ -20,6 +20,10 @@ def formula(person, period, parameters): # Ineligible if receiving SSI, SSDI, unemployment (UIB), or California # State Disability Insurance (SDI). SSDI, UIB, and SDI are YEAR-defined; # we read the full annual value with period.this_year and test receipt (> 0). + # Only SSDI bars eligibility here; Social Security retirement/survivors + # benefits (the broader `social_security` aggregate) are not a categorical + # bar -- they instead count toward the gap via the + # general_assistance.countable_income.sources list. receives_categorical = ( (person("ssi", period) > 0) | (person("social_security_disability", period.this_year) > 0) diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.py b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.py index c38a8af91be..b768029109b 100644 --- a/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.py +++ b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_immigration_status_eligible.py @@ -10,6 +10,11 @@ class ca_cc_general_assistance_immigration_status_eligible(Variable): reference = "https://ehsd.org/aging-and-adult-services/general-assistance/" def formula(person, period, parameters): + # The EHSD criterion is being "legally in the country with no limitation + # on your stay," so time-limited statuses do not qualify. PAROLED_ONE_YEAR + # is excluded because parole is granted for a fixed period and confers no + # indefinite right to remain -- matching the Santa Clara (SCC) and San + # Mateo (SMC) County GA implementations, which also exclude it. p = parameters(period).gov.local.ca.cc.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/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.py b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.py index 8bcc3dcfafd..83f71b315d4 100644 --- a/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.py +++ b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.py @@ -7,12 +7,9 @@ class ca_cc_general_assistance_income_eligible(Variable): label = "Eligible for Contra Costa County General Assistance based on income requirements" definition_period = MONTH defined_for = "in_cc" - reference = ( - "https://ehsd.org/aging-and-adult-services/general-assistance/", - # Adults with dependent children apply for CalWORKs instead, so the unit - # must have no children (GA-80 brochure, "adult without dependent children"). - "https://ehsd.org/wp-content/uploads/2024/08/GA-Brochure_ENGLISH_July2024_FA_Digital.pdf#page=2", - ) + # The EHSD program page states GA serves "an adult without dependent + # children"; families with children are directed to CalWORKs. + reference = "https://ehsd.org/aging-and-adult-services/general-assistance/" def formula(spm_unit, period, parameters): income = spm_unit("ca_cc_general_assistance_countable_income", period) From 2426b08e0ea5b243e4a4ece95921b2a40ce4b0e5 Mon Sep 17 00:00:00 2001 From: Ziming Date: Sun, 7 Jun 2026 00:57:41 -0400 Subject: [PATCH 4/5] Refactor Contra Costa County GA eligibility structure - Rename ca_cc_general_assistance_base_amount -> _maximum_grant (it is the full grant standard, not a base that gets supplemented). - Split eligibility: ca_cc_general_assistance_income_eligible is now purely the income test (income < maximum_grant); a new composite ca_cc_general_assistance_eligible ANDs has-eligible-person, no-dependent-children, and income eligibility. The benefit now gates on the composite. - Model 'dependent children' as is_child & is_tax_unit_dependent (explicit; equivalent to minor children in the current model). - Add an endogenous SSI integration test: an aged adult who qualifies for SSI (computed, not input) is excluded from GA. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../ca/cc/ga/ca_cc_general_assistance.yaml | 32 ++++++- ..._cc_general_assistance_maximum_grant.yaml} | 10 +-- .../ca_cc_general_assistance_eligible.yaml | 85 +++++++++++++++++++ ...cc_general_assistance_income_eligible.yaml | 29 +------ .../ca/cc/ga/ca_cc_general_assistance.py | 10 +-- ...ca_cc_general_assistance_maximum_grant.py} | 4 +- .../ca_cc_general_assistance_eligible.py | 27 ++++++ ...a_cc_general_assistance_income_eligible.py | 11 +-- 8 files changed, 161 insertions(+), 47 deletions(-) rename policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/{ca_cc_general_assistance_base_amount.yaml => ca_cc_general_assistance_maximum_grant.yaml} (90%) create mode 100644 policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible.yaml rename policyengine_us/variables/gov/local/ca/cc/ga/{ca_cc_general_assistance_base_amount.py => ca_cc_general_assistance_maximum_grant.py} (87%) create mode 100644 policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible.py diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance.yaml index d35868d8412..ce3aa40e6e7 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance.yaml @@ -230,8 +230,10 @@ spm_unit: members: [person1, child1] output: - spm_unit_count_children: 1 - ca_cc_general_assistance_income_eligible: false + # Income alone passes ($100 < $336 MAP), but the dependent child fails the + # composite eligibility gate (ca_cc_general_assistance_eligible), so no benefit. + ca_cc_general_assistance_income_eligible: true + ca_cc_general_assistance_eligible: false ca_cc_general_assistance: 0 - name: Immigration - a qualified refugee adult is eligible. @@ -360,3 +362,29 @@ output: ca_cc_general_assistance_income_eligible: false ca_cc_general_assistance: 0 + +- name: Endogenous SSI - an aged adult who qualifies for SSI (computed, not input) is excluded. + period: 2024-01 + input: + people: + person1: + age: 67 # aged -> categorically SSI-eligible + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 # under the SSI resource limit + # No earned income and no ssi input: the model computes ssi > 0 (takeup + # defaults to True), which bars GA via the categorical exclusion. + households: + household: + members: [person1] + state_code: CA + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + # Absent SSI this adult would be income-eligible ($0 < $336), but a computed + # ssi > 0 makes them categorically ineligible -> no eligible person -> $0. + ca_cc_general_assistance_eligible_person: false + ca_cc_general_assistance_eligible: false + ca_cc_general_assistance: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_maximum_grant.yaml similarity index 90% rename from policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.yaml rename to policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_maximum_grant.yaml index 4b1231aab9e..26c9c00cebd 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_maximum_grant.yaml @@ -18,7 +18,7 @@ spm_unit: members: [person1] output: - ca_cc_general_assistance_base_amount: 336 + ca_cc_general_assistance_maximum_grant: 336 - name: Two eligible adults receive the couple grant standard of $454. period: 2024-01 @@ -44,9 +44,9 @@ spm_unit: members: [person1, person2] output: - ca_cc_general_assistance_base_amount: 454 + ca_cc_general_assistance_maximum_grant: 454 -- name: No eligible persons yields a base amount of zero. +- name: No eligible persons yields a maximum grant of zero. period: 2024-01 input: people: @@ -64,7 +64,7 @@ spm_unit: members: [person1] output: - ca_cc_general_assistance_base_amount: 0 + ca_cc_general_assistance_maximum_grant: 0 - name: Three eligible adults fall through to the single grant standard of $336. period: 2024-01 @@ -97,4 +97,4 @@ members: [person1, person2, person3] output: # num_eligible == 3 -> where(num_eligible == 2, ...) is false -> single $336 - ca_cc_general_assistance_base_amount: 336 + ca_cc_general_assistance_maximum_grant: 336 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible.yaml new file mode 100644 index 00000000000..f30b06f964a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible.yaml @@ -0,0 +1,85 @@ +# Composite SPM-unit eligibility: at least one eligible person AND no dependent +# children AND income below the grant standard. +- name: Otherwise-eligible single adult with low income and no children is eligible. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 300 * 12 # $300/month countable < $336 MAP + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_eligible: true + +- name: Adult with income below MAP but a dependent child is not eligible (no-children gate). + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 100 * 12 # income passes, but the child gate fails + child1: + age: 5 + is_tax_unit_head_or_spouse: false + households: + household: + members: [person1, child1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1, child1] + output: + ca_cc_general_assistance_income_eligible: true + ca_cc_general_assistance_eligible: false + +- name: No eligible person (SSI recipient) is not eligible even with zero income. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + ssi: 100 # categorically ineligible -> no eligible person + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_eligible: false + +- name: Income at or above the grant standard is not eligible. + period: 2024-01 + input: + people: + person1: + age: 30 + is_tax_unit_head_or_spouse: true + immigration_status: CITIZEN + personal_property: 0 + employment_income: 400 * 12 # $400/month countable > $336 MAP + households: + household: + members: [person1] + county: CONTRA_COSTA_COUNTY_CA + spm_units: + spm_unit: + members: [person1] + output: + ca_cc_general_assistance_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.yaml index b935206a218..2a113e2ca48 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.yaml @@ -1,5 +1,6 @@ -# Income eligible when countable income < grant standard (MAP) AND the unit has no -# dependent children (strict no-children gate). Single MAP = $336/month. +# Income eligible when countable income < the grant standard (MAP). Single MAP = +# $336/month. The no-dependent-children and eligible-person gates live in +# ca_cc_general_assistance_eligible, not here. - name: Eligible single adult with income below the $336 single MAP and no children. period: 2024-01 input: @@ -40,30 +41,6 @@ output: ca_cc_general_assistance_income_eligible: false -- name: Ineligible adult with income below MAP but a dependent child (strict gate). - period: 2024-01 - input: - people: - person1: - age: 30 - is_tax_unit_head_or_spouse: true - immigration_status: CITIZEN - personal_property: 0 - employment_income: 300 * 12 # below MAP, but the no-children gate fails - child1: - age: 5 - is_tax_unit_head_or_spouse: false - households: - household: - members: [person1, child1] - county: CONTRA_COSTA_COUNTY_CA - spm_units: - spm_unit: - members: [person1, child1] - output: - spm_unit_count_children: 1 - ca_cc_general_assistance_income_eligible: false - - name: Boundary - income exactly at the $336 single MAP is ineligible (strict < gate). period: 2024-01 input: diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance.py b/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance.py index 10f734bee1b..55e085a53ef 100644 --- a/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance.py +++ b/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance.py @@ -7,13 +7,13 @@ class ca_cc_general_assistance(Variable): unit = USD label = "Contra Costa County General Assistance" definition_period = MONTH - defined_for = "ca_cc_general_assistance_income_eligible" + defined_for = "ca_cc_general_assistance_eligible" reference = "https://ehsd.org/aging-and-adult-services/general-assistance/" def formula(spm_unit, period, parameters): - base_amount = spm_unit("ca_cc_general_assistance_base_amount", period) + maximum_grant = spm_unit("ca_cc_general_assistance_maximum_grant", period) countable_income = spm_unit("ca_cc_general_assistance_countable_income", period) - # Fill-the-gap: the grant standard minus net countable income. Floor + # Fill-the-gap: the maximum grant minus net countable income. Floor # countable income at zero so net-negative flows (e.g. self-employment - # losses) cannot inflate the grant above the standard. - return max_(base_amount - max_(countable_income, 0), 0) + # losses) cannot inflate the grant above the maximum. + return max_(maximum_grant - max_(countable_income, 0), 0) diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.py b/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance_maximum_grant.py similarity index 87% rename from policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.py rename to policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance_maximum_grant.py index dea5d8f029c..f1b0825b614 100644 --- a/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance_base_amount.py +++ b/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance_maximum_grant.py @@ -1,11 +1,11 @@ from policyengine_us.model_api import * -class ca_cc_general_assistance_base_amount(Variable): +class ca_cc_general_assistance_maximum_grant(Variable): value_type = float entity = SPMUnit unit = USD - label = "Contra Costa County General Assistance base amount" + label = "Contra Costa County General Assistance maximum grant" definition_period = MONTH defined_for = "ca_cc_general_assistance_eligible_person" reference = "https://ehsd.org/aging-and-adult-services/general-assistance/" diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible.py b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible.py new file mode 100644 index 00000000000..43d2a1c3d79 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_eligible.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class ca_cc_general_assistance_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Contra Costa County General Assistance" + definition_period = MONTH + defined_for = "in_cc" + reference = "https://ehsd.org/aging-and-adult-services/general-assistance/" + + def formula(spm_unit, period, parameters): + has_eligible_person = ( + add(spm_unit, period, ["ca_cc_general_assistance_eligible_person"]) > 0 + ) + # General Assistance serves adults without dependent children; families + # with children are directed to CalWORKs. A dependent child is a minor + # (is_child) who is also a tax-unit dependent. In practice every minor is + # a tax-unit dependent (only adults can be a tax-unit head or spouse), so + # this currently equals the count of minor children in the unit. + person = spm_unit.members + is_dependent_child = person("is_child", period.this_year) & person( + "is_tax_unit_dependent", period.this_year + ) + no_dependent_children = spm_unit.sum(is_dependent_child) == 0 + income_eligible = spm_unit("ca_cc_general_assistance_income_eligible", period) + return has_eligible_person & no_dependent_children & income_eligible diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.py b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.py index 83f71b315d4..28d7402c8e3 100644 --- a/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.py +++ b/policyengine_us/variables/gov/local/ca/cc/ga/eligibility/ca_cc_general_assistance_income_eligible.py @@ -7,14 +7,11 @@ class ca_cc_general_assistance_income_eligible(Variable): label = "Eligible for Contra Costa County General Assistance based on income requirements" definition_period = MONTH defined_for = "in_cc" - # The EHSD program page states GA serves "an adult without dependent - # children"; families with children are directed to CalWORKs. reference = "https://ehsd.org/aging-and-adult-services/general-assistance/" def formula(spm_unit, period, parameters): income = spm_unit("ca_cc_general_assistance_countable_income", period) - base_amount = spm_unit("ca_cc_general_assistance_base_amount", period) - # General Assistance serves adults without dependent children; families - # with children are directed to CalWORKs. - no_children = spm_unit("spm_unit_count_children", period.this_year) == 0 - return (income < base_amount) & no_children + maximum_grant = spm_unit("ca_cc_general_assistance_maximum_grant", period) + # Countable income must be strictly below the grant standard ("earnings + # less than the maximum allowable grant"). + return income < maximum_grant From 7ee6dc28d62c1c891a7edd9874bdc7c066e874bb Mon Sep 17 00:00:00 2001 From: Ziming Date: Sun, 7 Jun 2026 01:08:53 -0400 Subject: [PATCH 5/5] Note 3+ eligible adults should not happen in Contra Costa GA Document that 3+ eligible adults in one SPM unit is not a real GA configuration (each adult or couple is a separate case); the fall-through to the single grant standard is a defensive default. Clarify the comment in ca_cc_general_assistance_maximum_grant and the corresponding test. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../ca/cc/ga/ca_cc_general_assistance_maximum_grant.yaml | 5 +++-- .../ca/cc/ga/ca_cc_general_assistance_maximum_grant.py | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_maximum_grant.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_maximum_grant.yaml index 26c9c00cebd..8a4506a40ef 100644 --- a/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_maximum_grant.yaml +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/cc/ga/ca_cc_general_assistance_maximum_grant.yaml @@ -66,7 +66,7 @@ output: ca_cc_general_assistance_maximum_grant: 0 -- name: Three eligible adults fall through to the single grant standard of $336. +- name: Three eligible adults (should not happen) fall through to the single $336 standard. period: 2024-01 input: people: @@ -96,5 +96,6 @@ spm_unit: members: [person1, person2, person3] output: - # num_eligible == 3 -> where(num_eligible == 2, ...) is false -> single $336 + # 3+ eligible adults should not occur in practice (each adult/couple is a + # separate GA case); num_eligible != 2 -> single $336 as a safe default. ca_cc_general_assistance_maximum_grant: 336 diff --git a/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance_maximum_grant.py b/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance_maximum_grant.py index f1b0825b614..c2a3167fbd5 100644 --- a/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance_maximum_grant.py +++ b/policyengine_us/variables/gov/local/ca/cc/ga/ca_cc_general_assistance_maximum_grant.py @@ -16,7 +16,10 @@ def formula(spm_unit, period, parameters): "ca_cc_general_assistance_eligible_person", period ) num_eligible = spm_unit.sum(eligible_persons) - # When two adults in the unit are eligible we apply the couple grant. We - # do not verify that the two eligible adults are married to each other; - # we don't track marital pairing within the SPM unit at the moment. + # GA aids a single adult ($336) or an eligible couple ($454). Exactly two + # eligible adults get the couple grant; we do not verify they are married + # to each other (marital pairing is not tracked within the SPM unit). + # NOTE: 3+ eligible adults in one SPM unit should not happen in practice + # -- each adult or couple is a separate GA case -- so any count other than + # two falls through to the single standard as a safe default. return where(num_eligible == 2, p.married, p.single)