diff --git a/changelog.d/fix-sc-ccap-activity-no-parent.fixed.md b/changelog.d/fix-sc-ccap-activity-no-parent.fixed.md new file mode 100644 index 00000000000..6b5093b791b --- /dev/null +++ b/changelog.d/fix-sc-ccap-activity-no-parent.fixed.md @@ -0,0 +1 @@ +Require the presence of at least one head/spouse for South Carolina CCAP activity eligibility so units with only dependents no longer vacuously pass the test. diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/dss/ccap/sc_ccap_activity_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/dss/ccap/sc_ccap_activity_eligible.yaml new file mode 100644 index 00000000000..60f2501d767 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/dss/ccap/sc_ccap_activity_eligible.yaml @@ -0,0 +1,160 @@ +# South Carolina CCAP activity eligibility tests +# Per the SC CCAP Policy Manual sec. 2.13, the applicant (head/spouse) +# must individually satisfy an activity requirement - work hours above +# the threshold, full-time study, or documented disability. +# +# The test also must not vacuously pass for an SPM unit that contains +# no head/spouse (e.g. unaccompanied minors): activity eligibility +# requires at least one head/spouse in the unit. + +- name: Case 1, working parent meets activity requirement. + period: 2025-01 + input: + people: + person1: + age: 30 + weekly_hours_worked: 30 + person2: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: SC + output: + sc_ccap_activity_eligible: true + +- name: Case 2, parent below the work hour threshold fails. + period: 2025-01 + input: + people: + person1: + age: 30 + weekly_hours_worked: 10 + is_full_time_student: false + is_disabled: false + person2: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: SC + output: + sc_ccap_activity_eligible: false + +- name: Case 3, full-time student parent meets requirement. + period: 2025-01 + input: + people: + person1: + age: 22 + weekly_hours_worked: 0 + is_full_time_student: true + person2: + age: 2 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: SC + output: + sc_ccap_activity_eligible: true + +- name: Case 4, disabled parent plus working parent. + period: 2025-01 + input: + people: + person1: + age: 35 + weekly_hours_worked: 40 + person2: + age: 33 + weekly_hours_worked: 0 + is_full_time_student: false + is_disabled: true + person3: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: SC + output: + sc_ccap_activity_eligible: true + +- name: Case 5, two parents where one fails activity test. + period: 2025-01 + input: + people: + person1: + age: 35 + weekly_hours_worked: 40 + person2: + age: 33 + weekly_hours_worked: 0 + is_full_time_student: false + is_disabled: false + person3: + age: 5 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: SC + output: + sc_ccap_activity_eligible: false + +- name: Case 6, SPM unit with only dependents has no activity-eligible parent. + period: 2025-01 + input: + people: + person1: + age: 16 + is_tax_unit_dependent: true + person2: + age: 10 + is_tax_unit_dependent: true + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: SC + output: + # No head/spouse in the unit -> must not vacuously pass the test + sc_ccap_activity_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/sc/dss/ccap/sc_ccap_maximum_weekly_benefit.yaml b/policyengine_us/tests/policy/baseline/gov/states/sc/dss/ccap/sc_ccap_maximum_weekly_benefit.yaml index d7ab9f32d2e..167c43b314b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/sc/dss/ccap/sc_ccap_maximum_weekly_benefit.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/sc/dss/ccap/sc_ccap_maximum_weekly_benefit.yaml @@ -13,18 +13,28 @@ input: people: person1: + age: 30 + weekly_hours_worked: 30 + person2: age: 0 + is_tax_unit_dependent: true childcare_hours_per_week: 30 sc_ccap_provider_type: CENTER sc_ccap_quality_level: C + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] households: household: - members: [person1] + members: [person1, person2] state_code: SC sc_ccap_geography: URBAN output: # Center, Level C, Urban, FT, Under 1 = $213/wk - sc_ccap_maximum_weekly_benefit: [213] + sc_ccap_maximum_weekly_benefit: [0, 213] - name: Case 2, level C center urban full time age 3. period: 2025-01 @@ -32,18 +42,28 @@ input: people: person1: + age: 30 + weekly_hours_worked: 30 + person2: age: 3 + is_tax_unit_dependent: true childcare_hours_per_week: 30 sc_ccap_provider_type: CENTER sc_ccap_quality_level: C + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] households: household: - members: [person1] + members: [person1, person2] state_code: SC sc_ccap_geography: URBAN output: # Center, Level C, Urban, FT, Age 3 = $195/wk - sc_ccap_maximum_weekly_benefit: [195] + sc_ccap_maximum_weekly_benefit: [0, 195] - name: Case 3, level C center urban full time school age. period: 2025-01 @@ -51,18 +71,28 @@ input: people: person1: + age: 30 + weekly_hours_worked: 30 + person2: age: 8 + is_tax_unit_dependent: true childcare_hours_per_week: 30 sc_ccap_provider_type: CENTER sc_ccap_quality_level: C + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] households: household: - members: [person1] + members: [person1, person2] state_code: SC sc_ccap_geography: URBAN output: # Center, Level C, Urban, FT, 5-12 in school = $165/wk - sc_ccap_maximum_weekly_benefit: [165] + sc_ccap_maximum_weekly_benefit: [0, 165] - name: Case 4, FFN full time infant. period: 2025-01 @@ -70,17 +100,27 @@ input: people: person1: + age: 30 + weekly_hours_worked: 30 + person2: age: 0 + is_tax_unit_dependent: true childcare_hours_per_week: 30 sc_ccap_provider_type: FFN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] households: household: - members: [person1] + members: [person1, person2] state_code: SC sc_ccap_geography: URBAN output: # FFN, any location, FT, Under 1-2 = $50/wk - sc_ccap_maximum_weekly_benefit: [50] + sc_ccap_maximum_weekly_benefit: [0, 50] - name: Case 5, FFN full time school age. period: 2025-01 @@ -88,17 +128,27 @@ input: people: person1: + age: 30 + weekly_hours_worked: 30 + person2: age: 8 + is_tax_unit_dependent: true childcare_hours_per_week: 30 sc_ccap_provider_type: FFN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] households: household: - members: [person1] + members: [person1, person2] state_code: SC sc_ccap_geography: URBAN output: # FFN, any location, FT, Age 3-12 = $46/wk - sc_ccap_maximum_weekly_benefit: [46] + sc_ccap_maximum_weekly_benefit: [0, 46] - name: Case 6, FFN half time infant. period: 2025-01 @@ -106,17 +156,27 @@ input: people: person1: + age: 30 + weekly_hours_worked: 30 + person2: age: 0 + is_tax_unit_dependent: true childcare_hours_per_week: 20 sc_ccap_provider_type: FFN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] households: household: - members: [person1] + members: [person1, person2] state_code: SC sc_ccap_geography: RURAL output: # FFN, any location, HT, Under 3 = $30/wk - sc_ccap_maximum_weekly_benefit: [30] + sc_ccap_maximum_weekly_benefit: [0, 30] - name: Case 7, FFN half time school age. period: 2025-01 @@ -124,17 +184,27 @@ input: people: person1: + age: 30 + weekly_hours_worked: 30 + person2: age: 8 + is_tax_unit_dependent: true childcare_hours_per_week: 20 sc_ccap_provider_type: FFN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] households: household: - members: [person1] + members: [person1, person2] state_code: SC sc_ccap_geography: RURAL output: # FFN, any location, HT, School age = $24/wk - sc_ccap_maximum_weekly_benefit: [24] + sc_ccap_maximum_weekly_benefit: [0, 24] - name: Case 8, special needs surcharge. period: 2025-01 @@ -142,20 +212,30 @@ input: people: person1: + age: 30 + weekly_hours_worked: 30 + person2: age: 5 + is_tax_unit_dependent: true childcare_hours_per_week: 30 sc_ccap_provider_type: CENTER sc_ccap_quality_level: C is_disabled: true + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] households: household: - members: [person1] + members: [person1, person2] state_code: SC sc_ccap_geography: URBAN output: # Age 5 defaults to in school (is_in_k12_school imputed True for ages 5-17) # Center C, Urban, FT, Age 5-12 in school = $165 + $20 special needs = $185/wk - sc_ccap_maximum_weekly_benefit: [185] + sc_ccap_maximum_weekly_benefit: [0, 185] - name: Case 9, foster care surcharge. period: 2025-01 @@ -163,19 +243,29 @@ input: people: person1: + age: 30 + weekly_hours_worked: 30 + person2: age: 3 + is_tax_unit_dependent: true childcare_hours_per_week: 30 sc_ccap_provider_type: CENTER sc_ccap_quality_level: C is_in_foster_care: true + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] households: household: - members: [person1] + members: [person1, person2] state_code: SC sc_ccap_geography: URBAN output: # Center C, Urban, FT, Age 3 = $195 + $30 foster surcharge = $225/wk - sc_ccap_maximum_weekly_benefit: [225] + sc_ccap_maximum_weekly_benefit: [0, 225] # Second child discount tests # Per Policy Manual 5.11, the discount is provider-determined and applies diff --git a/policyengine_us/variables/gov/states/sc/dss/ccap/eligibility/sc_ccap_activity_eligible.py b/policyengine_us/variables/gov/states/sc/dss/ccap/eligibility/sc_ccap_activity_eligible.py index 96e06a7c832..0c26a098a92 100644 --- a/policyengine_us/variables/gov/states/sc/dss/ccap/eligibility/sc_ccap_activity_eligible.py +++ b/policyengine_us/variables/gov/states/sc/dss/ccap/eligibility/sc_ccap_activity_eligible.py @@ -23,4 +23,10 @@ def formula(spm_unit, period, parameters): # or both parents disabled). is_disabled = person("is_disabled", period.this_year) individually_eligible = meets_work_requirement | is_student | is_disabled - return spm_unit.sum(is_head_or_spouse & ~individually_eligible) == 0 + # Require at least one head/spouse in the unit so an SPM unit + # containing only dependents does not vacuously pass the test, + # and require every head/spouse present to be individually + # eligible. Mirrors the VA CCSP activity-test pattern. + has_head_or_spouse = spm_unit.sum(is_head_or_spouse) >= 1 + all_covered = spm_unit.sum(is_head_or_spouse & ~individually_eligible) == 0 + return has_head_or_spouse & all_covered