diff --git a/changelog.d/8556.added.md b/changelog.d/8556.added.md new file mode 100644 index 00000000000..c7c1bbb4b03 --- /dev/null +++ b/changelog.d/8556.added.md @@ -0,0 +1 @@ +Added the Orange County, California General Relief benefit, paying the maximum aid payment by economic unit size and shared-housing situation net of countable income. diff --git a/policyengine_us/parameters/gov/local/ca/oc/general_relief/eligibility/adult_age_threshold.yaml b/policyengine_us/parameters/gov/local/ca/oc/general_relief/eligibility/adult_age_threshold.yaml new file mode 100644 index 00000000000..44d4f8afdda --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/oc/general_relief/eligibility/adult_age_threshold.yaml @@ -0,0 +1,11 @@ +description: Orange County General Relief limits aid to adults without minor children. +values: + 2022-02-01: 18 + +metadata: + unit: year + period: year + label: Orange County General Relief adult age threshold + reference: + - title: Orange County General Relief regulations, section 10.6.v + href: https://www.ssa.ocgov.com/sites/ssa/files/2026-01/GR%20Reg%20SECTION%2010%20-%20Approved%20-%20January%202026.pdf#page=08 diff --git a/policyengine_us/parameters/gov/local/ca/oc/general_relief/eligibility/qualified_immigration_status.yaml b/policyengine_us/parameters/gov/local/ca/oc/general_relief/eligibility/qualified_immigration_status.yaml new file mode 100644 index 00000000000..e1093132902 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/oc/general_relief/eligibility/qualified_immigration_status.yaml @@ -0,0 +1,14 @@ +description: Orange County General Relief treats these PolicyEngine immigration statuses as qualified lawful statuses. +values: + 2026-01-01: + - CITIZEN + - LEGAL_PERMANENT_RESIDENT + - DEPORTATION_WITHHELD + +metadata: + unit: list + period: year + label: Orange County General Relief qualified immigration statuses + reference: + - title: Orange County General Relief regulations, section 40.1 + href: https://www.ssa.ocgov.com/sites/ssa/files/2026-01/GR%20Reg%20SECTION%2040%20-%20Approved%20-%20January%202026.pdf#page=01 diff --git a/policyengine_us/parameters/gov/local/ca/oc/general_relief/income/earned_income_deduction_rate.yaml b/policyengine_us/parameters/gov/local/ca/oc/general_relief/income/earned_income_deduction_rate.yaml new file mode 100644 index 00000000000..12b26886b39 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/oc/general_relief/income/earned_income_deduction_rate.yaml @@ -0,0 +1,11 @@ +description: Orange County General Relief deducts this share of gross earned income. +values: + 2022-02-01: 0.2 + +metadata: + unit: /1 + period: year + label: Orange County General Relief earned income deduction rate + reference: + - title: Orange County General Relief regulations, section 70.2.o + href: https://www.ssa.ocgov.com/sites/ssa/files/2025-03/Income.pdf#page=04 diff --git a/policyengine_us/parameters/gov/local/ca/oc/general_relief/income/sources/earned.yaml b/policyengine_us/parameters/gov/local/ca/oc/general_relief/income/sources/earned.yaml new file mode 100644 index 00000000000..b2250471e05 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/oc/general_relief/income/sources/earned.yaml @@ -0,0 +1,14 @@ +description: Orange County General Relief counts these available earned income sources. +values: + 2024-11-01: + - employment_income + - self_employment_income + - sstb_self_employment_income + +metadata: + unit: list + period: year + label: Orange County General Relief earned income sources + reference: + - title: Orange County General Relief regulations, section 70.2 + href: https://www.ssa.ocgov.com/sites/ssa/files/2025-03/Income.pdf#page=02 diff --git a/policyengine_us/parameters/gov/local/ca/oc/general_relief/income/sources/unearned.yaml b/policyengine_us/parameters/gov/local/ca/oc/general_relief/income/sources/unearned.yaml new file mode 100644 index 00000000000..22453193165 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/oc/general_relief/income/sources/unearned.yaml @@ -0,0 +1,28 @@ +description: Orange County General Relief counts these available unearned income sources. +values: + 2024-11-01: + - rental_income + - interest_income + - dividend_income + - social_security + - unemployment_compensation + - ca_state_disability_insurance + - veterans_benefits + - pension_income + - retirement_distributions + - financial_assistance + - educational_assistance + - life_insurance_benefits + - disability_benefits + +metadata: + unit: list + period: year + label: Orange County General Relief unearned income sources + reference: + - title: Orange County General Relief regulations, section 70.2 + href: https://www.ssa.ocgov.com/sites/ssa/files/2025-03/Income.pdf#page=01 + - title: Orange County General Relief regulations, section 70.2.c + href: https://www.ssa.ocgov.com/sites/ssa/files/2025-03/Income.pdf#page=02 + - title: Orange County General Relief regulations, sections 70.2.f through 70.2.l + href: https://www.ssa.ocgov.com/sites/ssa/files/2025-03/Income.pdf#page=03 diff --git a/policyengine_us/parameters/gov/local/ca/oc/general_relief/payment/max_aid_payment.yaml b/policyengine_us/parameters/gov/local/ca/oc/general_relief/payment/max_aid_payment.yaml new file mode 100644 index 00000000000..cb3080fcc60 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/oc/general_relief/payment/max_aid_payment.yaml @@ -0,0 +1,35 @@ +description: Orange County provides this maximum aid payment based on economic unit size under the General Relief program. +metadata: + unit: currency-USD + breakdown: + - range(1, 11) + breakdown_labels: + - Economic unit size + period: month + label: Orange County General Relief maximum aid payment + reference: + - title: County of Orange General Relief Program Monthly Maximum Aid Payment (MAP) Table, effective April 1, 2015 + href: https://www.ochealthinfo.com/sites/hca/files/2021-07/DUI%20Program%20Standards%20%28FINAL%29%207.2021.pdf#page=32 + - title: 2017 Orange County Continuum of Care Application, Social Service Agency Benefits (single homeless individual maximum, effective October 1, 2016) + href: https://ochealthinfo.com/sites/hca/files/import/data/files/73607.pdf#page=21 +1: + 2015-04-01: 350 + 2016-10-01: 355 +2: + 2015-04-01: 569 +3: + 2015-04-01: 704 +4: + 2015-04-01: 840 +5: + 2015-04-01: 954 +6: + 2015-04-01: 1_072 +7: + 2015-04-01: 1_178 +8: + 2015-04-01: 1_283 +9: + 2015-04-01: 1_387 +10: + 2015-04-01: 1_490 diff --git a/policyengine_us/parameters/gov/local/ca/oc/general_relief/payment/shared_housing_reduction.yaml b/policyengine_us/parameters/gov/local/ca/oc/general_relief/payment/shared_housing_reduction.yaml new file mode 100644 index 00000000000..d94e4db3c48 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/oc/general_relief/payment/shared_housing_reduction.yaml @@ -0,0 +1,27 @@ +description: Orange County reduces the maximum aid payment by this share when the economic unit shares housing with this number of other people under the General Relief program. +metadata: + type: single_amount + threshold_unit: person + amount_unit: /1 + period: year + label: Orange County General Relief shared housing reduction + reference: + - title: Orange County General Relief regulations, section 80.3.a(3) + href: https://www.ssa.ocgov.com/sites/ssa/files/2025-03/Benefits_Services.pdf#page=04 +brackets: + - threshold: + 2015-04-01: 0 + amount: + 2015-04-01: 0 + - threshold: + 2015-04-01: 1 + amount: + 2015-04-01: 0.15 + - threshold: + 2015-04-01: 2 + amount: + 2015-04-01: 0.2 + - threshold: + 2015-04-01: 3 + amount: + 2015-04-01: 0.25 diff --git a/policyengine_us/parameters/gov/local/ca/oc/general_relief/resources/home_equity_limit.yaml b/policyengine_us/parameters/gov/local/ca/oc/general_relief/resources/home_equity_limit.yaml new file mode 100644 index 00000000000..9fa351a7efa --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/oc/general_relief/resources/home_equity_limit.yaml @@ -0,0 +1,11 @@ +description: Orange County General Relief limits the net value of a primary residence to this amount. +values: + 2022-02-01: 5_000 + +metadata: + unit: currency-USD + period: year + label: Orange County General Relief home equity limit + reference: + - title: Orange County General Relief regulations, section 50.2 + href: https://www.ssa.ocgov.com/sites/ssa/files/2023-04/GR%20Reg%20SECTION%2050%20-%20Approved%20-%20March%202023_0.pdf#page=01 diff --git a/policyengine_us/parameters/gov/local/ca/oc/general_relief/resources/liquid_resource_disregard.yaml b/policyengine_us/parameters/gov/local/ca/oc/general_relief/resources/liquid_resource_disregard.yaml new file mode 100644 index 00000000000..e4d828636d3 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/oc/general_relief/resources/liquid_resource_disregard.yaml @@ -0,0 +1,11 @@ +description: Orange County General Relief disregards liquid resources up to this amount when reducing the initial-month grant. +values: + 2012-11-01: 50 + +metadata: + unit: currency-USD + period: year + label: Orange County General Relief liquid resource disregard + reference: + - title: Orange County General Relief regulations, section 60.2.a + href: https://www.ssa.ocgov.com/sites/ssa/files/2023-04/GR%20Reg%20SECTION%2060%20-%20Approved%20-%20March%202023_0.pdf#page=01 diff --git a/policyengine_us/parameters/gov/local/ca/oc/general_relief/resources/property_limit.yaml b/policyengine_us/parameters/gov/local/ca/oc/general_relief/resources/property_limit.yaml new file mode 100644 index 00000000000..727dea4feb5 --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/oc/general_relief/resources/property_limit.yaml @@ -0,0 +1,11 @@ +description: Orange County General Relief limits combined countable secondary real and personal property to this amount. +values: + 2022-02-01: 1_000 + +metadata: + unit: currency-USD + period: year + label: Orange County General Relief countable property limit + reference: + - title: Orange County General Relief regulations, section 50.2 + href: https://www.ssa.ocgov.com/sites/ssa/files/2023-04/GR%20Reg%20SECTION%2050%20-%20Approved%20-%20March%202023_0.pdf#page=01 diff --git a/policyengine_us/parameters/gov/local/ca/oc/general_relief/resources/vehicle_exclusion.yaml b/policyengine_us/parameters/gov/local/ca/oc/general_relief/resources/vehicle_exclusion.yaml new file mode 100644 index 00000000000..528237aa16c --- /dev/null +++ b/policyengine_us/parameters/gov/local/ca/oc/general_relief/resources/vehicle_exclusion.yaml @@ -0,0 +1,11 @@ +description: Orange County General Relief excludes one vehicle per economic unit when its net value does not exceed this amount. +values: + 2012-11-01: 4_650 + +metadata: + unit: currency-USD + period: year + label: Orange County General Relief vehicle exclusion threshold + reference: + - title: Orange County General Relief regulations, section 60.4.c + href: https://www.ssa.ocgov.com/sites/ssa/files/2023-04/GR%20Reg%20SECTION%2060%20-%20Approved%20-%20March%202023_0.pdf#page=02 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index d66185d7f72..5b62055ca21 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -1285,6 +1285,17 @@ programs: variable: la_general_relief parameter_prefix: gov.local.ca.la.general_relief + - id: ca_oc_general_relief + name: Orange County General Relief + full_name: Orange County General Relief + category: Benefits + agency: Local + status: complete + coverage: Orange County + variable: ca_oc_general_relief + parameter_prefix: gov.local.ca.oc.general_relief + notes: Monthly maximum aid payment by economic unit size and shared-housing situation (April 2015 / October 2016 schedule) net of countable income; component-value deductions for in-kind aid and administrative-history rules are not modeled + - id: ca_riv_general_relief name: Riverside County General Relief full_name: Riverside County General Relief diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/ca_oc_general_relief.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/ca_oc_general_relief.yaml new file mode 100644 index 00000000000..6c864d04b42 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/ca_oc_general_relief.yaml @@ -0,0 +1,87 @@ +- name: Single eligible adult with no income receives the full maximum aid payment. + period: 2017-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + ssi: 0 + households: + household: + members: [person1] + in_oc: true + spm_units: + spm_unit: + members: [person1] + ca_tanf: 0 + output: + # MAP 355, no countable income: grant = 355. + ca_oc_general_relief: 355 + +- name: Earnings below the maximum aid payment reduce the grant. + period: 2017-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + ssi: 0 + employment_income: 300 * 12 + households: + household: + members: [person1] + in_oc: true + spm_units: + spm_unit: + members: [person1] + ca_tanf: 0 + output: + # Gross earned 300/month; countable earned = 300 x (1 - 0.2) = 240. + # Grant = max(355 - 240, 0) = 115. + ca_oc_general_relief: 115 + +- name: Earnings above the maximum aid payment yield a zero grant. + period: 2017-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + ssi: 0 + employment_income: 600 * 12 + households: + household: + members: [person1] + in_oc: true + spm_units: + spm_unit: + members: [person1] + ca_tanf: 0 + output: + # Gross earned 600/month; countable earned = 480 > MAP 355. + # Grant = max(355 - 480, 0) = 0. + ca_oc_general_relief: 0 + +- name: Two-person economic unit with no income receives the size-2 maximum aid payment. + period: 2017-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + ssi: 0 + person2: + age: 35 + immigration_status: CITIZEN + ssi: 0 + households: + household: + members: [person1, person2] + in_oc: true + spm_units: + spm_unit: + members: [person1, person2] + ca_tanf: 0 + output: + # MAP size 2 = 569, no countable income. + ca_oc_general_relief: 569 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_demographic_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_demographic_eligible.yaml new file mode 100644 index 00000000000..a03abe3b29c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_demographic_eligible.yaml @@ -0,0 +1,35 @@ +- name: A unit of only adults meets the demographic requirement. + period: 2026-01 + input: + people: + adult1: + age: 30 + adult2: + age: 45 + households: + household: + members: [adult1, adult2] + in_oc: true + spm_units: + spm_unit: + members: [adult1, adult2] + output: + ca_oc_general_relief_demographic_eligible: true + +- name: A unit containing a minor child does not meet the demographic requirement. + period: 2026-01 + input: + people: + adult: + age: 30 + child: + age: 10 + households: + household: + members: [adult, child] + in_oc: true + spm_units: + spm_unit: + members: [adult, child] + output: + ca_oc_general_relief_demographic_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_eligible_person.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_eligible_person.yaml new file mode 100644 index 00000000000..1893888817d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_eligible_person.yaml @@ -0,0 +1,51 @@ +- name: An adult citizen not on other assistance is an eligible person. + period: 2026-01 + input: + age: 30 + immigration_status: CITIZEN + county_str: ORANGE_COUNTY_CA + state_code: CA + output: + ca_oc_general_relief_eligible_person: true + +- name: A person below the adult age threshold is not an eligible person. + period: 2026-01 + input: + age: 17 + immigration_status: CITIZEN + county_str: ORANGE_COUNTY_CA + state_code: CA + output: + ca_oc_general_relief_eligible_person: false + +- name: A person at the adult age threshold is an eligible person. + period: 2026-01 + input: + age: 18 + immigration_status: CITIZEN + county_str: ORANGE_COUNTY_CA + state_code: CA + output: + ca_oc_general_relief_eligible_person: true + +- name: An undocumented adult is not an eligible person. + period: 2026-01 + input: + age: 30 + immigration_status: UNDOCUMENTED + county_str: ORANGE_COUNTY_CA + state_code: CA + output: + ca_oc_general_relief_eligible_person: false + +- name: A disabled adult who receives SSI is not an eligible person. + period: 2026-01 + input: + age: 30 + immigration_status: CITIZEN + is_disabled: true + meets_ssi_disability_criteria: true + county_str: ORANGE_COUNTY_CA + state_code: CA + output: + ca_oc_general_relief_eligible_person: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_immigration_status_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_immigration_status_eligible.yaml new file mode 100644 index 00000000000..92d59271154 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_immigration_status_eligible.yaml @@ -0,0 +1,47 @@ +- name: A citizen meets the modeled immigration-status rule. + period: 2026-01 + input: + immigration_status: CITIZEN + in_oc: true + output: + ca_oc_general_relief_immigration_status_eligible: true + +- name: An undocumented person does not meet the modeled immigration-status rule. + period: 2026-01 + input: + immigration_status: UNDOCUMENTED + in_oc: true + output: + ca_oc_general_relief_immigration_status_eligible: false + +- name: A person paroled for one year does not meet the manual's indefinite-stay standard. + period: 2026-01 + input: + immigration_status: PAROLED_ONE_YEAR + in_oc: true + output: + ca_oc_general_relief_immigration_status_eligible: false + +- name: A permanent legal resident meets the modeled immigration-status rule. + period: 2026-01 + input: + immigration_status: LEGAL_PERMANENT_RESIDENT + in_oc: true + output: + ca_oc_general_relief_immigration_status_eligible: true + +- name: A person granted an indefinite stay from deportation meets the modeled rule. + period: 2026-01 + input: + immigration_status: DEPORTATION_WITHHELD + in_oc: true + output: + ca_oc_general_relief_immigration_status_eligible: true + +- name: A refugee is not in the regulation's enumerated eligible list. + period: 2026-01 + input: + immigration_status: REFUGEE + in_oc: true + output: + ca_oc_general_relief_immigration_status_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_receives_other_cash_assistance.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_receives_other_cash_assistance.yaml new file mode 100644 index 00000000000..020358bf597 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_receives_other_cash_assistance.yaml @@ -0,0 +1,45 @@ +# Inputs describe the family (age, disability, immigration, work history); +# the model computes whether they receive SSI / CalWORKs / CAPI. +- name: An able-bodied adult with modest earnings receives no other cash assistance. + period: 2026-01 + input: + age: 30 + immigration_status: CITIZEN + employment_income: 6_000 + county_str: ORANGE_COUNTY_CA + state_code: CA + output: + ca_oc_general_relief_receives_other_cash_assistance: false + +- name: A disabled adult with no income receives SSI. + period: 2026-01 + input: + age: 30 + immigration_status: CITIZEN + is_disabled: true + meets_ssi_disability_criteria: true + county_str: ORANGE_COUNTY_CA + state_code: CA + output: + ca_oc_general_relief_receives_other_cash_assistance: true + +- name: An aged adult with no income receives SSI. + period: 2026-01 + input: + age: 70 + immigration_status: CITIZEN + county_str: ORANGE_COUNTY_CA + state_code: CA + output: + ca_oc_general_relief_receives_other_cash_assistance: true + +- name: A recently arrived aged permanent resident without work history receives CAPI. + period: 2026-01 + input: + age: 70 + immigration_status: LEGAL_PERMANENT_RESIDENT + ssi_qualifying_quarters_earnings: 0 + county_str: ORANGE_COUNTY_CA + state_code: CA + output: + ca_oc_general_relief_receives_other_cash_assistance: true diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/in_oc.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/in_oc.yaml new file mode 100644 index 00000000000..b3e22784143 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/in_oc.yaml @@ -0,0 +1,13 @@ +- name: Orange County is identified from the county string. + period: 2026 + input: + county_str: ORANGE_COUNTY_CA + output: + in_oc: true + +- name: A different California county is not Orange County. + period: 2026 + input: + county_str: RIVERSIDE_COUNTY_CA + output: + in_oc: false diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_earned_income.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_earned_income.yaml new file mode 100644 index 00000000000..64d54645c6e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_earned_income.yaml @@ -0,0 +1,24 @@ +- name: Countable earned income applies the twenty percent deduction. + period: 2026-01 + input: + employment_income: 1_000 * 12 + in_oc: true + output: + ca_oc_general_relief_gross_earned_income: 1_000 + ca_oc_general_relief_countable_earned_income: 800 + +- name: Zero earned income produces zero countable earned income. + period: 2026-01 + input: + in_oc: true + output: + ca_oc_general_relief_countable_earned_income: 0 + +- name: Negative self-employment income does not reduce countable earned income below zero. + period: 2026-01 + input: + self_employment_income: -1_000 * 12 + in_oc: true + output: + ca_oc_general_relief_gross_earned_income: -1_000 + ca_oc_general_relief_countable_earned_income: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_income_person.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_income_person.yaml new file mode 100644 index 00000000000..f2d7679eb8c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_income_person.yaml @@ -0,0 +1,29 @@ +- name: Countable earned income applies the twenty percent deduction. + period: 2026-01 + input: + employment_income: 1_000 * 12 + in_oc: true + output: + ca_oc_general_relief_gross_earned_income: 1_000 + ca_oc_general_relief_countable_earned_income: 800 + ca_oc_general_relief_countable_income_person: 800 + +- name: Health premiums and court-ordered child support reduce countable income once. + period: 2026-01 + input: + employment_income: 1_000 * 12 + rental_income: 200 * 12 + health_insurance_premiums: 100 * 12 + child_support_expense: 50 * 12 + in_oc: true + output: + ca_oc_general_relief_countable_income_person: 850 + +- name: Income from a person receiving SSI is excluded. + period: 2026-01 + input: + employment_income: 1_000 * 12 + ssi: 100 + in_oc: true + output: + ca_oc_general_relief_countable_income_person: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/integration.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/integration.yaml new file mode 100644 index 00000000000..8b311cfc217 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/integration.yaml @@ -0,0 +1,229 @@ +- name: A single adult citizen with resources below the limits receives the maximum aid payment. + period: 2026-01 + input: + people: + person: + age: 30 + immigration_status: CITIZEN + ssi: 0 + households: + household: + members: [person] + in_oc: true + spm_units: + spm_unit: + members: [person] + ca_tanf: 0 + output: + ca_oc_general_relief_aided_person_count: 1 + ca_oc_general_relief_resources_eligible: true + ca_oc_general_relief_eligible: true + # EU size 1, no shared housing, no countable income. + ca_oc_general_relief_max_aid_payment: 355 + ca_oc_general_relief: 355 + +- name: An undocumented adult does not pass the partial screen. + period: 2026-01 + input: + people: + person: + age: 30 + immigration_status: UNDOCUMENTED + ssi: 0 + households: + household: + members: [person] + in_oc: true + spm_units: + spm_unit: + members: [person] + ca_tanf: 0 + output: + ca_oc_general_relief_aided_person_count: 0 + ca_oc_general_relief_eligible: false + +- name: A unit with a minor child does not pass the partial screen. + period: 2026-01 + input: + people: + adult: + age: 30 + child: + age: 10 + households: + household: + members: [adult, child] + county_str: ORANGE_COUNTY_CA + state_code: CA + output: + # General Relief aids adults without minor children; a family with a child + # is routed to CalWORKs (Sec 20 must-apply, Sec 20.4.b, Sec 80.2.d), so the + # parent cannot also receive GR. + ca_oc_general_relief_demographic_eligible: false + ca_oc_general_relief_eligible: false + +- name: A person receiving SSI does not pass the partial screen. + period: 2026-01 + input: + people: + person: + age: 30 + ssi: 100 + households: + household: + members: [person] + in_oc: true + spm_units: + spm_unit: + members: [person] + ca_tanf: 0 + output: + ca_oc_general_relief_receives_other_cash_assistance: true + ca_oc_general_relief_aided_person_count: 0 + ca_oc_general_relief_eligible: false + +- name: A CalWORKs unit does not pass the partial screen. + period: 2026-01 + input: + people: + person: + age: 30 + ssi: 0 + households: + household: + members: [person] + in_oc: true + spm_units: + spm_unit: + members: [person] + ca_tanf: 100 * 12 + output: + ca_oc_general_relief_receives_other_cash_assistance: true + ca_oc_general_relief_aided_person_count: 0 + ca_oc_general_relief_eligible: false + +- name: Property above the limit does not pass the partial screen. + period: 2026-01 + input: + people: + person: + age: 30 + ssi: 0 + personal_property: 1_001 + households: + household: + members: [person] + in_oc: true + spm_units: + spm_unit: + members: [person] + ca_tanf: 0 + output: + ca_oc_general_relief_resources_eligible: false + ca_oc_general_relief_eligible: false + +- name: Income above the maximum aid payment yields a zero grant. + period: 2026-01 + input: + people: + person: + age: 30 + employment_income: 1_000 * 12 + ssi: 0 + households: + household: + members: [person] + in_oc: true + spm_units: + spm_unit: + members: [person] + ca_tanf: 0 + output: + # Countable income 800 exceeds the size-1 MAP (355), so the grant is 0, + # though the unit still passes the categorical screen. + ca_oc_general_relief_countable_income: 800 + ca_oc_general_relief_eligible: true + ca_oc_general_relief: 0 + +# Mapping the eligible population from real family inputs: only able-bodied, +# childless, qualified-immigration adults with low assets pass the screen. +- name: An able-bodied childless citizen adult with low assets passes the partial screen. + period: 2026-01 + input: + people: + person: + age: 30 + immigration_status: CITIZEN + households: + household: + members: [person] + county_str: ORANGE_COUNTY_CA + state_code: CA + output: + ca_oc_general_relief_receives_other_cash_assistance: false + ca_oc_general_relief_eligible: true + +- name: A disabled adult receives SSI and so does not pass the partial screen. + period: 2026-01 + input: + people: + person: + age: 30 + immigration_status: CITIZEN + is_disabled: true + meets_ssi_disability_criteria: true + households: + household: + members: [person] + county_str: ORANGE_COUNTY_CA + state_code: CA + output: + ca_oc_general_relief_receives_other_cash_assistance: true + ca_oc_general_relief_eligible: false + +- name: A recently arrived aged permanent resident receives CAPI and so does not pass the partial screen. + period: 2026-01 + input: + people: + person: + age: 70 + immigration_status: LEGAL_PERMANENT_RESIDENT + ssi_qualifying_quarters_earnings: 0 + households: + household: + members: [person] + county_str: ORANGE_COUNTY_CA + state_code: CA + output: + # No SSI (not an SSI-qualified noncitizen), but receives CAPI, which is an + # excluded "other type of public assistance" under Sec 20.4.b. + ca_oc_general_relief_receives_other_cash_assistance: true + ca_oc_general_relief_eligible: false + +- name: A single adult sharing a home with one roommate has the grant reduced for shared housing. + period: 2026-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + ssi: 0 + person2: + age: 45 + immigration_status: CITIZEN + ssi: 0 + households: + household: + members: [person1, person2] + in_oc: true + spm_units: + spm_unit1: + members: [person1] + ca_tanf: 0 + spm_unit2: + members: [person2] + ca_tanf: 0 + output: + # Each one-person economic unit shares with 1 other person, so the size-1 + # MAP (355) is reduced 15%: 355 x 0.85 = 301.75. + ca_oc_general_relief: [301.75, 301.75] diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/payment/ca_oc_general_relief_max_aid_payment.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/payment/ca_oc_general_relief_max_aid_payment.yaml new file mode 100644 index 00000000000..16efc520322 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/payment/ca_oc_general_relief_max_aid_payment.yaml @@ -0,0 +1,158 @@ +- name: Single economic unit, no shared housing, April 2015 schedule. + period: 2016-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + ssi: 0 + households: + household: + members: [person1] + in_oc: true + spm_units: + spm_unit: + members: [person1] + ca_tanf: 0 + output: + # EU size 1, no shared housing, effective April 1, 2015. + ca_oc_general_relief_max_aid_payment: 350 + +- name: Single economic unit, no shared housing, October 2016 schedule. + period: 2017-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + ssi: 0 + households: + household: + members: [person1] + in_oc: true + spm_units: + spm_unit: + members: [person1] + ca_tanf: 0 + output: + # EU size 1 increased from 350 to 355 effective October 1, 2016. + ca_oc_general_relief_max_aid_payment: 355 + +- name: Two-person economic unit, no shared housing. + period: 2017-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + ssi: 0 + person2: + age: 35 + immigration_status: CITIZEN + ssi: 0 + households: + household: + members: [person1, person2] + in_oc: true + spm_units: + spm_unit: + members: [person1, person2] + ca_tanf: 0 + output: + # EU size 2, no shared housing (both members in one economic unit). + ca_oc_general_relief_max_aid_payment: 569 + +- name: Four-person economic unit, no shared housing. + period: 2017-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + ssi: 0 + person2: + age: 35 + immigration_status: CITIZEN + ssi: 0 + person3: + age: 40 + immigration_status: CITIZEN + ssi: 0 + person4: + age: 45 + immigration_status: CITIZEN + ssi: 0 + households: + household: + members: [person1, person2, person3, person4] + in_oc: true + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + ca_tanf: 0 + output: + # EU size 4, no shared housing. + ca_oc_general_relief_max_aid_payment: 840 + +- name: Two single-person economic units sharing one home (one other person each). + period: 2017-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + ssi: 0 + person2: + age: 40 + immigration_status: CITIZEN + ssi: 0 + households: + household: + members: [person1, person2] + in_oc: true + spm_units: + spm_unit1: + members: [person1] + ca_tanf: 0 + spm_unit2: + members: [person2] + ca_tanf: 0 + output: + # Each EU shares with 1 other person: 355 x (1 - 0.15) = 301.75. + ca_oc_general_relief_max_aid_payment: [301.75, 301.75] + +- name: Single economic unit sharing a home with three other people. + period: 2017-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + ssi: 0 + person2: + age: 40 + immigration_status: CITIZEN + ssi: 0 + person3: + age: 41 + immigration_status: CITIZEN + ssi: 0 + person4: + age: 42 + immigration_status: CITIZEN + ssi: 0 + households: + household: + members: [person1, person2, person3, person4] + in_oc: true + spm_units: + spm_unit1: + members: [person1] + ca_tanf: 0 + spm_unit2: + members: [person2, person3, person4] + ca_tanf: 0 + output: + # spm_unit1: EU size 1 sharing with 3 others: 355 x (1 - 0.25) = 266.25. + # spm_unit2: EU size 3 sharing with 1 other: 704 x (1 - 0.15) = 598.4. + ca_oc_general_relief_max_aid_payment: [266.25, 598.4] diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_countable_vehicle_value.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_countable_vehicle_value.yaml new file mode 100644 index 00000000000..2b2ac83dee3 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_countable_vehicle_value.yaml @@ -0,0 +1,15 @@ +- name: Vehicle equity below the exclusion has no countable value. + period: 2026 + input: + household_vehicles_equity: 4_650 + in_oc: true + output: + ca_oc_general_relief_countable_vehicle_value: 0 + +- name: Vehicle equity above the exclusion has countable value. + period: 2026 + input: + household_vehicles_equity: 4_800 + in_oc: true + output: + ca_oc_general_relief_countable_vehicle_value: 4_800 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_excess_liquid_resources.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_excess_liquid_resources.yaml new file mode 100644 index 00000000000..e04c4fd7b53 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_excess_liquid_resources.yaml @@ -0,0 +1,15 @@ +- name: Liquid resources at the disregard do not reduce an initial-month grant. + period: 2026 + input: + spm_unit_cash_assets: 50 + in_oc: true + output: + ca_oc_general_relief_excess_liquid_resources: 0 + +- name: Liquid resources above the disregard expose the amount available to reduce an initial-month grant. + period: 2026 + input: + spm_unit_cash_assets: 75 + in_oc: true + output: + ca_oc_general_relief_excess_liquid_resources: 25 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_other_real_estate_equity.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_other_real_estate_equity.yaml new file mode 100644 index 00000000000..c61557a8cb9 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_other_real_estate_equity.yaml @@ -0,0 +1,7 @@ +- name: Other real estate equity uses the household value. + period: 2026 + input: + household_other_real_estate_equity: 700 + in_oc: true + output: + ca_oc_general_relief_other_real_estate_equity: 700 diff --git a/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_resources_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_resources_eligible.yaml new file mode 100644 index 00000000000..2aac0769cf7 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_resources_eligible.yaml @@ -0,0 +1,26 @@ +- name: Resources at both limits meet the resource screen. + period: 2026-01 + input: + home_equity: 5_000 + personal_property: 1_000 + in_oc: true + output: + ca_oc_general_relief_resources_eligible: true + +- name: Home equity above the primary-residence limit fails the resource screen. + period: 2026-01 + input: + home_equity: 5_001 + in_oc: true + output: + ca_oc_general_relief_resources_eligible: false + +- name: Combined countable property above the property limit fails the resource screen. + period: 2026-01 + input: + personal_property: 500 + household_other_real_estate_equity: 501 + in_oc: true + output: + ca_oc_general_relief_countable_property: 1_001 + ca_oc_general_relief_resources_eligible: false diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/ca_oc_general_relief.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/ca_oc_general_relief.py new file mode 100644 index 00000000000..c3826893997 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/ca_oc_general_relief.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "Orange County General Relief" + definition_period = MONTH + defined_for = "ca_oc_general_relief_eligible" + reference = "https://www.ssa.ocgov.com/sites/ssa/files/2025-03/Benefits_Services.pdf#page=01" + + def formula(spm_unit, period, parameters): + # The GR benefit is the maximum aid payment less all net countable + # income (Sec 80.2.d, Sec 80.3.c-e). The grant cannot be negative. + # We don't model the component-value deductions for in-kind aid met at + # no cost (Sec 80.3.b) at the moment, because Orange County does not + # publish the component-value dollar amounts. + max_aid_payment = spm_unit("ca_oc_general_relief_max_aid_payment", period) + countable_income = spm_unit("ca_oc_general_relief_countable_income", period) + return max_(max_aid_payment - countable_income, 0) diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/ca_oc_general_relief_eligible.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/ca_oc_general_relief_eligible.py new file mode 100644 index 00000000000..349abbc92da --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/ca_oc_general_relief_eligible.py @@ -0,0 +1,30 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Orange County General Relief" + definition_period = MONTH + defined_for = "in_oc" + reference = "https://www.ssa.ocgov.com/page/general-relief-regulations" + + def formula(spm_unit, period, parameters): + # Categorical screen: demographic (adults without minor children), + # immigration, public-assistance, and resource rules. Financial + # eligibility (income below the maximum aid payment) is applied in the + # benefit variable ca_oc_general_relief, which nets countable income + # against the MAP. + demographic_eligible = spm_unit( + "ca_oc_general_relief_demographic_eligible", + period, + ) + resources_eligible = spm_unit( + "ca_oc_general_relief_resources_eligible", + period, + ) + aided_person_count = spm_unit( + "ca_oc_general_relief_aided_person_count", + period, + ) + return demographic_eligible & resources_eligible & (aided_person_count > 0) diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_aided_person_count.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_aided_person_count.py new file mode 100644 index 00000000000..3cad3ba81f1 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_aided_person_count.py @@ -0,0 +1,10 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_aided_person_count(Variable): + value_type = int + entity = SPMUnit + label = "Orange County General Relief aided person count" + definition_period = MONTH + defined_for = "in_oc" + adds = ["ca_oc_general_relief_eligible_person"] diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_demographic_eligible.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_demographic_eligible.py new file mode 100644 index 00000000000..add5f10f9be --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_demographic_eligible.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_demographic_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Meets Orange County General Relief demographic requirements" + definition_period = MONTH + defined_for = "in_oc" + reference = ( + "https://www.ssa.ocgov.com/cash-calfresh/faqs/general-relief", + "https://www.ssa.ocgov.com/sites/ssa/files/2025-03/Benefits_Services.pdf#page=02", + ) + + def formula(spm_unit, period, parameters): + # General Relief aids adults without minor children. A unit with a minor + # child is effectively routed to CalWORKs, and the parent cannot also + # receive GR: the unit must apply for any aid it appears eligible for or + # be ineligible (Sec 20, "Failure ... to apply for any aid ... results + # in ineligibility"); a parent receiving CalWORKs is an excluded member + # (Sec 20.4.b); and a parent who has exhausted the CalWORKs time limit + # is excluded from the GR MAP until all children turn 18 (Sec 80.2.d). + # So no realistic family has a child on CalWORKs and that child's parent + # on GR. The rare non-parent-caretaker case is not modeled. + p = parameters(period).gov.local.ca.oc.general_relief.eligibility + age = spm_unit.members("monthly_age", period) + return spm_unit.all(age >= p.adult_age_threshold) diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_eligible_person.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_eligible_person.py new file mode 100644 index 00000000000..a11391cdd3a --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_eligible_person.py @@ -0,0 +1,25 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_eligible_person(Variable): + value_type = bool + entity = Person + label = "Eligible person for Orange County General Relief" + definition_period = MONTH + defined_for = "in_oc" + reference = "https://www.ssa.ocgov.com/sites/ssa/files/2026-01/GR%20Reg%20SECTION%2020%20-%20Approved%20-%20January%202026.pdf#page=03" + + def formula(person, period, parameters): + p = parameters(period).gov.local.ca.oc.general_relief.eligibility + age_eligible = person("monthly_age", period) >= p.adult_age_threshold + immigration_status_eligible = person( + "ca_oc_general_relief_immigration_status_eligible", + period, + ) + receives_other_cash_assistance = person( + "ca_oc_general_relief_receives_other_cash_assistance", + period, + ) + return ( + age_eligible & immigration_status_eligible & ~receives_other_cash_assistance + ) diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_immigration_status_eligible.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_immigration_status_eligible.py new file mode 100644 index 00000000000..be10de1de66 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_immigration_status_eligible.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_immigration_status_eligible(Variable): + value_type = bool + entity = Person + label = "Eligible for Orange County General Relief due to immigration status" + definition_period = MONTH + defined_for = "in_oc" + reference = "https://www.ssa.ocgov.com/sites/ssa/files/2026-01/GR%20Reg%20SECTION%2040%20-%20Approved%20-%20January%202026.pdf#page=01" + + def formula(person, period, parameters): + # NOTE: Section 40.1 also makes victims of trafficking, domestic + # violence, and other serious crimes (T/U-visa, VAWA) eligible, but + # PolicyEngine's ImmigrationStatus enum has no value for that pathway, + # so we don't track it at the moment. + p = parameters(period).gov.local.ca.oc.general_relief.eligibility + status = person("immigration_status", period.this_year).decode_to_str() + return np.isin(status, p.qualified_immigration_status) diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_receives_other_cash_assistance.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_receives_other_cash_assistance.py new file mode 100644 index 00000000000..d2633162b3c --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/eligibility/ca_oc_general_relief_receives_other_cash_assistance.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_receives_other_cash_assistance(Variable): + value_type = bool + entity = Person + label = "Receives other cash assistance that excludes Orange County General Relief" + definition_period = MONTH + defined_for = "in_oc" + reference = "https://www.ssa.ocgov.com/sites/ssa/files/2026-01/GR%20Reg%20SECTION%2020%20-%20Approved%20-%20January%202026.pdf#page=03" + + def formula(person, period, parameters): + # Section 20.4.b excludes recipients of "another type of public + # assistance (SSI/SSP, CalWORKs, Refugee Cash Assistance (RCA))"; the + # list is non-exhaustive ("include but are not limited to"), so CAPI -- + # California's SSI-equivalent cash aid for immigrants -- is also an + # excluding program. CAPI recipients do NOT have ssi > 0, so ca_capi is + # checked separately. + # CalWORKs and CAPI receipt are only available at the SPM-unit level, so + # any unit receiving them excludes its members; this does not + # distinguish child-only cases. Refugee Cash Assistance has no + # California variable in PolicyEngine, so we don't track RCA at the + # moment. + receives_ssi = person("ssi", period) > 0 + receives_calworks = person.spm_unit("ca_tanf", period) > 0 + receives_capi = person.spm_unit("ca_capi", period) > 0 + return receives_ssi | receives_calworks | receives_capi diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_earned_income.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_earned_income.py new file mode 100644 index 00000000000..c8e1707a455 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_earned_income.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_countable_earned_income(Variable): + value_type = float + entity = Person + label = "Orange County General Relief countable earned income" + unit = USD + definition_period = MONTH + defined_for = "in_oc" + reference = "https://www.ssa.ocgov.com/sites/ssa/files/2025-03/Income.pdf#page=04" + + def formula(person, period, parameters): + p = parameters(period).gov.local.ca.oc.general_relief.income + gross_earned_income = person( + "ca_oc_general_relief_gross_earned_income", + period, + ) + return max_(gross_earned_income * (1 - p.earned_income_deduction_rate), 0) diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_income.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_income.py new file mode 100644 index 00000000000..06c4c4d3ea9 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_income.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_countable_income(Variable): + value_type = float + entity = SPMUnit + label = "Orange County General Relief countable income" + unit = USD + definition_period = MONTH + defined_for = "in_oc" + adds = ["ca_oc_general_relief_countable_income_person"] diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_income_person.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_income_person.py new file mode 100644 index 00000000000..db9e040a25c --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_countable_income_person.py @@ -0,0 +1,45 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_countable_income_person(Variable): + value_type = float + entity = Person + label = "Orange County General Relief countable income per person" + unit = USD + definition_period = MONTH + defined_for = "in_oc" + reference = ( + "https://www.ssa.ocgov.com/sites/ssa/files/2025-03/Income.pdf#page=04", + "https://www.ssa.ocgov.com/sites/ssa/files/2025-03/Income.pdf#page=05", + ) + + def formula(person, period, parameters): + # NOTE: Section 70.2.p also allows mandatory federal/state income tax + # withheld from unearned income as a deduction; we don't track that at + # the moment (negligible for the very-low-income General Relief + # population). + countable_income = add( + person, + period, + [ + "ca_oc_general_relief_countable_earned_income", + "ca_oc_general_relief_gross_unearned_income", + ], + ) + deductions = add( + person, + period, + [ + "health_insurance_premiums", + "child_support_expense", + ], + ) + receives_other_cash_assistance = person( + "ca_oc_general_relief_receives_other_cash_assistance", + period, + ) + return where( + receives_other_cash_assistance, + 0, + max_(countable_income - deductions, 0), + ) diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_gross_earned_income.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_gross_earned_income.py new file mode 100644 index 00000000000..750ab7efd0c --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_gross_earned_income.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_gross_earned_income(Variable): + value_type = float + entity = Person + label = "Orange County General Relief gross earned income" + unit = USD + definition_period = MONTH + defined_for = "in_oc" + adds = "gov.local.ca.oc.general_relief.income.sources.earned" diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_gross_unearned_income.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_gross_unearned_income.py new file mode 100644 index 00000000000..11c5acd3d90 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/income/ca_oc_general_relief_gross_unearned_income.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_gross_unearned_income(Variable): + value_type = float + entity = Person + label = "Orange County General Relief gross unearned income" + unit = USD + definition_period = MONTH + defined_for = "in_oc" + adds = "gov.local.ca.oc.general_relief.income.sources.unearned" diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/payment/ca_oc_general_relief_max_aid_payment.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/payment/ca_oc_general_relief_max_aid_payment.py new file mode 100644 index 00000000000..8b80340a1c6 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/payment/ca_oc_general_relief_max_aid_payment.py @@ -0,0 +1,33 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_max_aid_payment(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "Orange County General Relief maximum aid payment" + definition_period = MONTH + defined_for = "in_oc" + reference = ( + "https://www.ochealthinfo.com/sites/hca/files/2021-07/DUI%20Program%20Standards%20%28FINAL%29%207.2021.pdf#page=32", + "https://www.ssa.ocgov.com/sites/ssa/files/2025-03/Benefits_Services.pdf#page=04", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.local.ca.oc.general_relief.payment + # The MAP is based on the size of the GR Economic Unit and its housing + # arrangement (Sec 80.2.d). It covers only the aided persons: children + # and members excluded for SSI/other cash assistance or immigration + # status are not included in the MAP. + size = spm_unit("ca_oc_general_relief_aided_person_count", period) + capped_size = clip(size, 1, 10) + base = p.max_aid_payment[capped_size] + # The MAP is reduced when the Economic Unit shares housing with one or + # more people who are not part of the unit (Sec 80.3.a(3)). We proxy the + # number of other people sharing the home as the household members + # outside the Economic Unit (the SPM unit). + household_size = spm_unit.household("household_size", period.this_year) + unit_size = spm_unit("spm_unit_size", period.this_year) + other_people = max_(household_size - unit_size, 0) + reduction = p.shared_housing_reduction.calc(other_people) + return base * (1 - reduction) diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_countable_personal_property.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_countable_personal_property.py new file mode 100644 index 00000000000..35f8059169c --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_countable_personal_property.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_countable_personal_property(Variable): + value_type = float + entity = SPMUnit + label = "Orange County General Relief countable personal property" + unit = USD + quantity_type = STOCK + definition_period = YEAR + defined_for = "in_oc" + # NOTE: uses available personal-property inputs; we don't separate all + # Orange County exclusions (household effects up to $500, burial reserves + # up to $1,000) at the moment. + adds = ["personal_property"] diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_countable_property.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_countable_property.py new file mode 100644 index 00000000000..b5c59c452c4 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_countable_property.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_countable_property(Variable): + value_type = float + entity = SPMUnit + label = "Orange County General Relief countable property" + unit = USD + quantity_type = STOCK + definition_period = YEAR + defined_for = "in_oc" + adds = [ + "ca_oc_general_relief_countable_personal_property", + "ca_oc_general_relief_other_real_estate_equity", + "ca_oc_general_relief_countable_vehicle_value", + ] diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_countable_vehicle_value.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_countable_vehicle_value.py new file mode 100644 index 00000000000..84d7a2b368f --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_countable_vehicle_value.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_countable_vehicle_value(Variable): + value_type = float + entity = SPMUnit + label = "Orange County General Relief countable vehicle value" + unit = USD + quantity_type = STOCK + definition_period = YEAR + defined_for = "in_oc" + reference = "https://www.ssa.ocgov.com/sites/ssa/files/2023-04/GR%20Reg%20SECTION%2060%20-%20Approved%20-%20March%202023_0.pdf#page=02" + + def formula(spm_unit, period, parameters): + # NOTE: uses total household vehicle equity as a proxy for the net value + # of one vehicle per economic unit. + p = parameters(period).gov.local.ca.oc.general_relief.resources + vehicle_equity = spm_unit.household("household_vehicles_equity", period) + return where(vehicle_equity <= p.vehicle_exclusion, 0, vehicle_equity) diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_excess_liquid_resources.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_excess_liquid_resources.py new file mode 100644 index 00000000000..c57f80c42b9 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_excess_liquid_resources.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_excess_liquid_resources(Variable): + value_type = float + entity = SPMUnit + label = "Orange County General Relief excess liquid resources" + unit = USD + quantity_type = STOCK + definition_period = YEAR + defined_for = "in_oc" + reference = "https://www.ssa.ocgov.com/sites/ssa/files/2023-04/GR%20Reg%20SECTION%2060%20-%20Approved%20-%20March%202023_0.pdf#page=01" + + def formula(spm_unit, period, parameters): + # NOTE: amount available to reduce an initial-month grant; the ordinary + # monthly payment is not modeled because Orange County's MAP schedule + # is not publicly available. + p = parameters(period).gov.local.ca.oc.general_relief.resources + liquid_resources = spm_unit("spm_unit_cash_assets", period) + return max_(liquid_resources - p.liquid_resource_disregard, 0) diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_home_equity.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_home_equity.py new file mode 100644 index 00000000000..12aa9dd1bfd --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_home_equity.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_home_equity(Variable): + value_type = float + entity = SPMUnit + label = "Orange County General Relief home equity" + unit = USD + quantity_type = STOCK + definition_period = YEAR + defined_for = "in_oc" + adds = ["home_equity"] diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_other_real_estate_equity.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_other_real_estate_equity.py new file mode 100644 index 00000000000..0015899b1af --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_other_real_estate_equity.py @@ -0,0 +1,16 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_other_real_estate_equity(Variable): + value_type = float + entity = SPMUnit + label = "Orange County General Relief other real estate equity" + unit = USD + quantity_type = STOCK + definition_period = YEAR + defined_for = "in_oc" + + def formula(spm_unit, period, parameters): + # NOTE: uses household other-real-estate equity; we don't track whether + # secondary real property is under a good-faith effort to sell. + return spm_unit.household("household_other_real_estate_equity", period) diff --git a/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_resources_eligible.py b/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_resources_eligible.py new file mode 100644 index 00000000000..306cec47b39 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/general_relief/resources/ca_oc_general_relief_resources_eligible.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class ca_oc_general_relief_resources_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Meets Orange County General Relief resource requirements" + definition_period = MONTH + defined_for = "in_oc" + reference = "https://www.ssa.ocgov.com/sites/ssa/files/2023-04/GR%20Reg%20SECTION%2050%20-%20Approved%20-%20March%202023_0.pdf#page=01" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.local.ca.oc.general_relief.resources + home_equity = spm_unit("ca_oc_general_relief_home_equity", period.this_year) + property_value = spm_unit( + "ca_oc_general_relief_countable_property", + period.this_year, + ) + return (home_equity <= p.home_equity_limit) & ( + property_value <= p.property_limit + ) diff --git a/policyengine_us/variables/gov/local/ca/oc/in_oc.py b/policyengine_us/variables/gov/local/ca/oc/in_oc.py new file mode 100644 index 00000000000..fee554c8258 --- /dev/null +++ b/policyengine_us/variables/gov/local/ca/oc/in_oc.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class in_oc(Variable): + value_type = bool + entity = Household + definition_period = YEAR + label = "Is in Orange County" + + def formula(household, period, parameters): + county = household("county_str", period) + return county == "ORANGE_COUNTY_CA" diff --git a/sources/working_references.md b/sources/working_references.md new file mode 100644 index 00000000000..bdcde704a38 --- /dev/null +++ b/sources/working_references.md @@ -0,0 +1,70 @@ +# Orange County General Relief working references + +## Program + +- Program: Orange County, California General Relief (GR). +- Variable prefix: `ca_oc_general_relief`. +- Parameter prefix: `gov.local.ca.oc.general_relief`. +- Registry status: `partial`. +- Official regulations index: https://www.ssa.ocgov.com/page/general-relief-regulations +- Official FAQ: https://www.ssa.ocgov.com/cash-calfresh/faqs/general-relief +- User-provided consolidated manual: `/Users/ziminghua/Downloads/GR Regulation Manual.pdf` +- Consolidated manual SHA-256: `2a9f4e5be086106b73f6b22abb55127461bdec873164b0671e81fc42b8bb47d7` +- Consolidated manual metadata: Orange County Social Services Agency, created March 19, 2026, 58 PDF pages. +- Extraction: `/tmp/ca-oc-general-relief-docs/manual-text/gr-regulation-manual.txt` +- Rendered pages: `/tmp/ca-oc-general-relief-docs/manual-rendered/page-01.png` through `page-58.png` + +## Official PDF references + +- Section 10, Introduction: + https://www.ssa.ocgov.com/sites/ssa/files/2026-01/GR%20Reg%20SECTION%2010%20-%20Approved%20-%20January%202026.pdf#page=01 +- Section 20, Eligibility Determination: + https://www.ssa.ocgov.com/sites/ssa/files/2026-01/GR%20Reg%20SECTION%2020%20-%20Approved%20-%20January%202026.pdf#page=01 +- Section 30, Program Requirements and Penalties: + https://www.ssa.ocgov.com/sites/ssa/files/2026-01/GR%20Reg%20SECTION%2030%20-%20Approved%20-%20January%202026.pdf#page=01 +- Section 40, Residence: + https://www.ssa.ocgov.com/sites/ssa/files/2026-01/GR%20Reg%20SECTION%2040%20-%20Approved%20-%20January%202026.pdf#page=01 +- Section 50, Real Property: + https://www.ssa.ocgov.com/sites/ssa/files/2023-04/GR%20Reg%20SECTION%2050%20-%20Approved%20-%20March%202023_0.pdf#page=01 +- Section 60, Personal Property: + https://www.ssa.ocgov.com/sites/ssa/files/2023-04/GR%20Reg%20SECTION%2060%20-%20Approved%20-%20March%202023_0.pdf#page=01 +- Section 70, Income: + https://www.ssa.ocgov.com/sites/ssa/files/2025-03/Income.pdf#page=01 +- Section 80, Benefits and Services: + https://www.ssa.ocgov.com/sites/ssa/files/2025-03/Benefits_Services.pdf#page=01 +- Section 90, Responsible Relatives: + https://www.ssa.ocgov.com/sites/ssa/files/2023-04/GR%20Reg%20SECTION%2090%20-%20Approved%20-%20March%202023_0.pdf#page=01 + +## Verified simulatable rules + +- GR is a residual relief program for people ineligible for federal or state cash aid programs. Section 10.3, PDF page 01. +- A GR economic unit (GR-EU) includes people living together who are legally and/or economically dependent. Section 10.6.j, PDF page 05. +- The FAQ describes the target population as eligible indigent adult lawful residents without custody of minor children. +- Recipients of SSI/SSP, CalWORKs, and Refugee Cash Assistance are excluded members of the GR-EU. Section 20.4.b, PDF page 03. +- County residence requires 15 consecutive calendar days immediately before application. Section 40.2, PDF page 01. +- Eligible immigration pathways include U.S. citizens, permanent legal residents, people granted an indefinite stay from deportation, and qualifying victims of trafficking, domestic violence, and other serious crimes. Temporary visa holders and undocumented non-citizens are ineligible. Section 40.1, PDF page 01. +- Primary-residence real property is limited to $5,000 net value. Combined countable secondary real and personal property is limited to $1,000. Section 50.2, PDF page 01. +- Cash or liquid resources over $50 reduce the initial-month grant. Section 60.2.a, PDF page 01. +- Personal-property exclusions include household furniture and personal effects up to $500, one vehicle per EU with net value up to $4,650, and qualifying burial reserves up to $1,000. Section 60.4, PDF page 02. +- Current income includes earned income, countable grants or gifts, certain loans, rental income, lump sums, retirement withdrawals, and 10% of roomer or boarder payments. Energy assistance and qualifying reimbursements are excluded. Section 70.2, PDF pages 01-03. +- Net earned income deducts 20% of gross earnings, medical insurance payments, and verified court-ordered support actually paid. Section 70.2.o, PDF page 04. +- Net unearned income deducts medical insurance payments, verified court-ordered support actually paid, and mandatory federal or state income tax deductions. Section 70.2.p, PDF page 04. +- Financial eligibility subtracts current net income from the maximum aid payment (MAP). Section 80.2.d, PDF page 02. +- MAP excludes children and other excluded members. Section 80.2.d, PDF page 02. +- CalWORKs or RCA recipient members use a difference-of-MAP method; other excluded members use the MAP for eligible GR-EU members. Section 80.3.a, PDF page 04. +- Shared housing reduces MAP by 15% for one unrelated person, 20% for two unrelated people, and 25% for three or more unrelated people. Section 80.3.a.3, PDF page 04. +- Housing and utility expenses are allowed up to the housing and utility component value. Homeless people receive the full housing and utility component value. Section 80.3.b.1, PDF page 05. +- Food, transportation, and clothing component values are deducted only when the entire component is provided at no cost. CalFresh receipt does not reduce the food component value. Section 80.3.b.1, PDF page 05. +- Employable participants are limited to 90 days of GR benefits in any 12-month period. Section 30.7.c, PDF page 05. + +## Important missing source + +The official regulations define the regular monthly benefit formula but do not publish: + +- the regular MAP table by eligible GR-EU size; +- the housing and utility component values; +- the food component values; +- the transportation component values; +- the clothing component values. + +These values are required to calculate the ordinary monthly GR benefit. Request an official Orange County companion schedule, procedure, or current eligibility handbook before implementing the full payment calculation.