diff --git a/changelog.d/wv-ccap.added.md b/changelog.d/wv-ccap.added.md new file mode 100644 index 00000000000..a971ee4b859 --- /dev/null +++ b/changelog.d/wv-ccap.added.md @@ -0,0 +1 @@ +Implement West Virginia Child Care Assistance Program (CCAP). diff --git a/policyengine_us/parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml b/policyengine_us/parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml index 89dc3c0bef2..3e052ea2073 100644 --- a/policyengine_us/parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml +++ b/policyengine_us/parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml @@ -15,6 +15,7 @@ values: - ri_child_care_subsidies # Rhode Island Child Care Assistance Program - sc_child_care_subsidies # South Carolina Child Care Scholarship Program - va_child_care_subsidies # Virginia Child Care Subsidy Program + - wv_child_care_subsidies # West Virginia Child Care Assistance Program metadata: unit: list diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/age_group/informal_months.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/age_group/informal_months.yaml new file mode 100644 index 00000000000..fa8e0fed508 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/age_group/informal_months.yaml @@ -0,0 +1,24 @@ +description: West Virginia defines these informal care age group boundaries in months under the Child Care Assistance Program. +metadata: + type: single_amount + threshold_unit: month + amount_unit: /1 + period: year + label: West Virginia CCAP informal care age group by months + reference: + - title: WV Child Care Subsidy Appendix B — Rate Structure (Oct 1, 2024) + href: https://bfa.wv.gov/media/6831/download?inline + +# Maps age in months to WVCCAPInformalAgeGroup enum index, matching +# Appendix B's INFANT (0-24 months) and TODDLER+ (25+ months) bands: +# 0 = UNDER_2 (0-24 months) +# 1 = AGE_2_AND_OVER (25+ months) +brackets: + - threshold: + 2024-01-01: 0 + amount: + 2024-01-01: 0 + - threshold: + 2024-01-01: 25 + amount: + 2024-01-01: 1 diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/age_group/months.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/age_group/months.yaml new file mode 100644 index 00000000000..6a7222c15ff --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/age_group/months.yaml @@ -0,0 +1,33 @@ +description: West Virginia defines these child age group boundaries in months under the Child Care Assistance Program. +metadata: + type: single_amount + threshold_unit: month + amount_unit: /1 + period: year + label: West Virginia CCAP child age group by months + reference: + - title: WV Child Care Subsidy Appendix B — Rate Structure (Oct 1, 2024) + href: https://bfa.wv.gov/media/6831/download?inline + +# Maps age in months to WVCCAPChildAgeCategory enum index: +# 0 = INFANT (0-24 months) +# 1 = TODDLER (25-36 months) +# 2 = PRESCHOOL (37-59 months) +# 3 = SCHOOL_AGE (60+ months) +brackets: + - threshold: + 2024-01-01: 0 + amount: + 2024-01-01: 0 + - threshold: + 2024-01-01: 25 + amount: + 2024-01-01: 1 + - threshold: + 2024-01-01: 37 + amount: + 2024-01-01: 2 + - threshold: + 2024-01-01: 60 + amount: + 2024-01-01: 3 diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/copayment/max_share.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/copayment/max_share.yaml new file mode 100644 index 00000000000..8bbd8a29bed --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/copayment/max_share.yaml @@ -0,0 +1,11 @@ +description: West Virginia limits the co-payment to this share of gross family income under the Child Care Assistance Program. +values: + 2024-01-01: 0.07 + +metadata: + unit: /1 + period: year + label: West Virginia CCAP maximum co-payment share + reference: + - title: WV CCDF State Plan FFY 2025-2027, Section 3.1.1 — Family Co-payment (7%) + href: https://bfa.wv.gov/media/39915/download?inline#page=39 diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/copayment/rate.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/copayment/rate.yaml new file mode 100644 index 00000000000..b43816d67c3 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/copayment/rate.yaml @@ -0,0 +1,39 @@ +description: West Virginia sets this co-payment share of income by federal poverty level ratio under the Child Care Assistance Program. +metadata: + type: single_amount + threshold_unit: /1 + amount_unit: /1 + period: year + label: West Virginia CCAP co-payment rate by FPL ratio + reference: + - title: WV Child Care Subsidy Appendix A — Sliding Fee Scale (Oct 1, 2024) + href: https://bfa.wv.gov/media/6826/download?inline + - title: WV CCDF State Plan FFY 2025-2027, Section 3.1.2 — Sliding Fee Scale + href: https://bfa.wv.gov/media/39915/download?inline#page=39 + +# Simplified percentage approximation of the 176-cell sliding fee scale. +# Derived from the 3-person family column in Appendix A as a representative +# middle case. Actual daily dollar fees vary by family size; this percentage +# approximation produces reasonable copay amounts across family sizes. +# The 7% cap (max_share parameter) provides an upper bound per CCDF rules. +brackets: + - threshold: + 2024-10-01: 0 + amount: + 2024-10-01: 0 + - threshold: + 2024-10-01: 0.4001 + amount: + 2024-10-01: 0.025 + - threshold: + 2024-10-01: 0.7001 + amount: + 2024-10-01: 0.03 + - threshold: + 2024-10-01: 1.1001 + amount: + 2024-10-01: 0.035 + - threshold: + 2024-10-01: 1.5001 + amount: + 2024-10-01: 0.04 diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/eligibility/activity_hours.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/eligibility/activity_hours.yaml new file mode 100644 index 00000000000..0d4ab91a520 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/eligibility/activity_hours.yaml @@ -0,0 +1,11 @@ +description: West Virginia sets this minimum weekly activity hours for parent eligibility under the Child Care Assistance Program. +values: + 2024-01-01: 20 + +metadata: + unit: hour + period: week + label: West Virginia CCAP minimum weekly activity hours + reference: + - title: WV Child Care Subsidy Policy & Procedures Manual, Chapter 3, Section 3.6.1 — Working Recipients + href: https://bfa.wv.gov/media/6766/download?inline#page=32 diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/eligibility/child_age_limit.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/eligibility/child_age_limit.yaml new file mode 100644 index 00000000000..2cc703d23bc --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/eligibility/child_age_limit.yaml @@ -0,0 +1,13 @@ +description: West Virginia limits child eligibility to under this age under the Child Care Assistance Program. +values: + 2024-01-01: 13 + +metadata: + unit: year + period: year + label: West Virginia CCAP child age limit + reference: + - title: WV Child Care Subsidy Policy & Procedures Manual, Chapter 3, Section 3.1 — Child Age Requirement + href: https://bfa.wv.gov/media/6766/download?inline#page=25 + - title: WV CCDF State Plan FFY 2025-2027, Section 2.2 + href: https://bfa.wv.gov/media/39915/download?inline#page=16 diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/eligibility/special_needs_child_age_limit.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/eligibility/special_needs_child_age_limit.yaml new file mode 100644 index 00000000000..60a7a898028 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/eligibility/special_needs_child_age_limit.yaml @@ -0,0 +1,13 @@ +description: West Virginia limits special needs child eligibility to under this age under the Child Care Assistance Program. +values: + 2024-01-01: 18 + +metadata: + unit: year + period: year + label: West Virginia CCAP special needs child age limit + reference: + - title: WV Child Care Subsidy Policy & Procedures Manual, Chapter 3, Section 3.1.2 — Special Needs Children + href: https://bfa.wv.gov/media/6766/download?inline#page=25 + - title: WV CCDF State Plan FFY 2025-2027, Section 2.2 + href: https://bfa.wv.gov/media/39915/download?inline#page=16 diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/countable_income/sources.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/countable_income/sources.yaml new file mode 100644 index 00000000000..b742f9066dd --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/countable_income/sources.yaml @@ -0,0 +1,34 @@ +description: West Virginia counts these income sources under the Child Care Assistance Program. +values: + 2024-01-01: + - employment_income + - self_employment_income + - social_security + - ssi + - unemployment_compensation + - workers_compensation + - pension_income + - alimony_income + - child_support_received + - dividend_income + - interest_income + - rental_income + - veterans_benefits + - military_retirement_pay + # TANF is countable per Manual Sec 5.2.4.3 but excluded here to avoid + # a circular dependency: + # wv_ccap_countable_income -> tanf -> wv_works + # -> wv_works_countable_earned_income (deducts childcare_expenses) + # -> childcare_expenses -> wv_ccap -> wv_ccap_income_eligible + # -> wv_ccap_countable_income + # The is_tanf_enrolled bypass in wv_ccap_income_eligible already + # makes TANF-active families categorically income-eligible. + # - tanf # would belong here + +metadata: + unit: list + period: year + label: West Virginia CCAP countable income sources + reference: + - title: WV Child Care Subsidy Policy & Procedures Manual, Chapter 5, Sections 5.2.1-5.2.4 — Countable Income + href: https://bfa.wv.gov/media/6766/download?inline#page=51 diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/smi_rate.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/smi_rate.yaml new file mode 100644 index 00000000000..c8675c9d92b --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/income/smi_rate.yaml @@ -0,0 +1,13 @@ +description: West Virginia limits income to this share of the state median income under the Child Care Assistance Program. +values: + 2024-01-01: 0.85 + +metadata: + unit: /1 + period: year + label: West Virginia CCAP SMI rate + reference: + - title: WV CCDF State Plan FFY 2025-2027, Section 2.2.4 + href: https://bfa.wv.gov/media/39915/download?inline#page=20 + - title: WV 2024 State Median Income Chart + href: https://bfa.wv.gov/media/6781/download?inline diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/center.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/center.yaml new file mode 100644 index 00000000000..5bece5a0a0c --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/center.yaml @@ -0,0 +1,39 @@ +description: West Virginia provides these daily reimbursement rates for child care centers under the Child Care Assistance Program. +metadata: + period: day + unit: currency-USD + label: West Virginia CCAP child care center daily rates + breakdown: + - wv_ccap_quality_tier + - wv_ccap_child_age_category + reference: + - title: WV Child Care Subsidy Appendix B — Rate Structure (Oct 1, 2024) + href: https://bfa.wv.gov/media/6831/download?inline + +TIER_I: + INFANT: + 2024-10-01: 39 + TODDLER: + 2024-10-01: 37 + PRESCHOOL: + 2024-10-01: 35 + SCHOOL_AGE: + 2024-10-01: 32 +TIER_II: + INFANT: + 2024-10-01: 42 + TODDLER: + 2024-10-01: 40 + PRESCHOOL: + 2024-10-01: 38 + SCHOOL_AGE: + 2024-10-01: 35 +TIER_III: + INFANT: + 2024-10-01: 45 + TODDLER: + 2024-10-01: 43 + PRESCHOOL: + 2024-10-01: 41 + SCHOOL_AGE: + 2024-10-01: 39 diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/family_facility.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/family_facility.yaml new file mode 100644 index 00000000000..64ca0918478 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/family_facility.yaml @@ -0,0 +1,39 @@ +description: West Virginia provides these daily reimbursement rates for family child care facilities under the Child Care Assistance Program. +metadata: + period: day + unit: currency-USD + label: West Virginia CCAP family child care facility daily rates + breakdown: + - wv_ccap_quality_tier + - wv_ccap_child_age_category + reference: + - title: WV Child Care Subsidy Appendix B — Rate Structure (Oct 1, 2024) + href: https://bfa.wv.gov/media/6831/download?inline + +TIER_I: + INFANT: + 2024-10-01: 35 + TODDLER: + 2024-10-01: 33 + PRESCHOOL: + 2024-10-01: 33 + SCHOOL_AGE: + 2024-10-01: 32 +TIER_II: + INFANT: + 2024-10-01: 38 + TODDLER: + 2024-10-01: 36 + PRESCHOOL: + 2024-10-01: 36 + SCHOOL_AGE: + 2024-10-01: 35 +TIER_III: + INFANT: + 2024-10-01: 41 + TODDLER: + 2024-10-01: 39 + PRESCHOOL: + 2024-10-01: 39 + SCHOOL_AGE: + 2024-10-01: 38 diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/family_home.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/family_home.yaml new file mode 100644 index 00000000000..7fdb3c13284 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/family_home.yaml @@ -0,0 +1,39 @@ +description: West Virginia provides these daily reimbursement rates for family child care homes under the Child Care Assistance Program. +metadata: + period: day + unit: currency-USD + label: West Virginia CCAP family child care home daily rates + breakdown: + - wv_ccap_quality_tier + - wv_ccap_child_age_category + reference: + - title: WV Child Care Subsidy Appendix B — Rate Structure (Oct 1, 2024) + href: https://bfa.wv.gov/media/6831/download?inline + +TIER_I: + INFANT: + 2024-10-01: 30 + TODDLER: + 2024-10-01: 30 + PRESCHOOL: + 2024-10-01: 29 + SCHOOL_AGE: + 2024-10-01: 26 +TIER_II: + INFANT: + 2024-10-01: 33 + TODDLER: + 2024-10-01: 33 + PRESCHOOL: + 2024-10-01: 32 + SCHOOL_AGE: + 2024-10-01: 29 +TIER_III: + INFANT: + 2024-10-01: 36 + TODDLER: + 2024-10-01: 36 + PRESCHOOL: + 2024-10-01: 35 + SCHOOL_AGE: + 2024-10-01: 32 diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/informal_relative.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/informal_relative.yaml new file mode 100644 index 00000000000..1053ece84d9 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/informal_relative.yaml @@ -0,0 +1,15 @@ +description: West Virginia provides these daily reimbursement rates for informal or relative care under the Child Care Assistance Program. +metadata: + period: day + unit: currency-USD + label: West Virginia CCAP informal relative care daily rates + breakdown: + - wv_ccap_informal_age_group + reference: + - title: WV Child Care Subsidy Appendix B — Rate Structure (Oct 1, 2024) + href: https://bfa.wv.gov/media/6831/download?inline + +UNDER_2: + 2024-10-01: 7.5 +AGE_2_AND_OVER: + 2024-10-01: 6 diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/out_of_school_time.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/out_of_school_time.yaml new file mode 100644 index 00000000000..b4ad81e8810 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/rates/out_of_school_time.yaml @@ -0,0 +1,11 @@ +description: West Virginia provides this daily reimbursement rate for out of school time programs under the Child Care Assistance Program. +values: + 2024-10-01: 14.5 + +metadata: + period: day + unit: currency-USD + label: West Virginia CCAP out of school time daily rate + reference: + - title: WV Child Care Subsidy Appendix B — Rate Structure (Oct 1, 2024) + href: https://bfa.wv.gov/media/6831/download?inline diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/supplements/non_traditional_hours.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/supplements/non_traditional_hours.yaml new file mode 100644 index 00000000000..38c43257cf4 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/supplements/non_traditional_hours.yaml @@ -0,0 +1,11 @@ +description: West Virginia provides this daily supplement for non-traditional hours care under the Child Care Assistance Program. +values: + 2024-10-01: 6 + +metadata: + period: day + unit: currency-USD + label: West Virginia CCAP non-traditional hours supplement + reference: + - title: WV Child Care Subsidy Appendix B — Rate Structure (Oct 1, 2024) + href: https://bfa.wv.gov/media/6831/download?inline diff --git a/policyengine_us/parameters/gov/states/wv/dhhr/ccap/supplements/special_needs.yaml b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/supplements/special_needs.yaml new file mode 100644 index 00000000000..de494345e49 --- /dev/null +++ b/policyengine_us/parameters/gov/states/wv/dhhr/ccap/supplements/special_needs.yaml @@ -0,0 +1,11 @@ +description: West Virginia provides this daily supplement for children with special needs under the Child Care Assistance Program. +values: + 2024-10-01: 3 + +metadata: + period: day + unit: currency-USD + label: West Virginia CCAP special needs supplement + reference: + - title: WV Child Care Subsidy Appendix B — Rate Structure (Oct 1, 2024) + href: https://bfa.wv.gov/media/6831/download?inline diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 76b5377b5f3..6f3607ed289 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -550,9 +550,11 @@ programs: full_name: Vermont Child Care Financial Assistance Program variable: vt_ccfap - state: WV - status: in_progress + status: complete name: West Virginia CCAP full_name: West Virginia Child Care Assistance Program + variable: wv_ccap + parameter_prefix: gov.states.wv.dhhr.ccap - id: head_start name: Head Start diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/edge_cases.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/edge_cases.yaml new file mode 100644 index 00000000000..dc7599f97a1 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/edge_cases.yaml @@ -0,0 +1,1731 @@ +# WV CCAP Edge Case Tests +# Income test (single threshold) per CCDF Plan §2.2.4 / §2.2.5(a): +# 85% of state median income. +# WV 4-person SMI (2024-10-01) = 90_661/yr +# Family-size factors: 1p=0.52, 2p=0.68, 3p=0.84, 4p=1.00, 5p=1.16, 6p=1.32 +# 85% SMI family of 2 = 90_661 * 0.68 * 0.85 = 52_401.86/yr = 4_366.82/mo +# 85% SMI family of 3 = 90_661 * 0.84 * 0.85 = 64_731.81/yr = 5_394.32/mo +# 85% SMI family of 11 = 90_661 * 1.47 * 0.85 = 113_280.92/yr = 9_440.08/mo +# 2025 FPG (Contiguous US): first_person = 15_650, additional = 5_500 +# Family of 2 FPG = 21_150/yr = 1_762.50/mo; family of 3 = 26_650/yr. + +# ============================================================ +# Income threshold boundaries (85% SMI) +# ============================================================ + +- name: Case 1, income well below 85% SMI eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 24_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 10_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 10_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 2_000 <= 4_366.82 -> eligible + wv_ccap_income_eligible: true + +- name: Case 2, income just below 85% SMI eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + # 85% SMI family of 2 = 52_401.86/yr + employment_income: 52_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 10_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 10_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 4_333.33 <= 4_366.82 -> eligible (at boundary) + wv_ccap_income_eligible: true + +- name: Case 3, income just above 85% SMI ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + # Just above 85% SMI family of 2 (52_401.86/yr) + employment_income: 53_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 10_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 10_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 4_416.67 > 4_366.82 -> ineligible + wv_ccap_income_eligible: false + +# ============================================================ +# Income above former two-tier FPL ceiling but below 85% SMI +# ============================================================ + +- name: Case 4, income above the former 185% FPL ceiling but below 85% SMI. + period: 2025-01 + input: + people: + person1: + age: 30 + # 185% FPL family of 2 = 39_127.50/yr; 85% SMI family of 2 = 52_401.86/yr + employment_income: 40_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 3_333.33 <= 4_366.82 -> eligible. + # Demonstrates that 85% SMI is the operative income test. + wv_ccap_income_eligible: true + +- name: Case 5, income well above 85% SMI ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 60_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 5_000 > 4_366.82 -> ineligible + wv_ccap_income_eligible: false + +- name: Case 6, income at 85% SMI exact boundary eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + # 85% SMI family of 2 = 52_401.86/yr = 4_366.82/mo; + # use 52_401 to land just under the boundary. + employment_income: 52_401 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 4_366.75 <= 4_366.82 -> eligible (at boundary) + wv_ccap_income_eligible: true + +# ============================================================ +# 85% SMI cap binds for large families +# ============================================================ + +- name: Case 7, large family income above 85% SMI ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + # 85% SMI family of 11 = 113_280.92/yr = 9_440.08/mo + employment_income: 114_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person3: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person4: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person5: + age: 9 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person6: + age: 11 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person7: + age: 32 + immigration_status: CITIZEN + person8: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person9: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person10: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person11: + age: 6 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11] + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11] + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11] + state_code: WV + output: + # monthly income = 9_500 > 9_440.08 -> ineligible + wv_ccap_income_eligible: false + +- name: Case 8, large family income below 85% SMI eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + # Below 85% SMI family of 11 (113_280.92/yr) + employment_income: 100_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person3: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person4: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person5: + age: 9 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person6: + age: 11 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person7: + age: 32 + immigration_status: CITIZEN + person8: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person9: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person10: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + person11: + age: 6 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11] + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11] + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8, person9, person10, person11] + state_code: WV + output: + # monthly income = 8_333.33 <= 9_440.08 -> eligible + wv_ccap_income_eligible: true + +# ============================================================ +# Zero and very high income +# ============================================================ + +- name: Case 9, zero income eligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 0 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 5_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 5_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_income_eligible: true + # FPL ratio = 0 -> below 40% FPL -> $0 copay + wv_ccap_copay: 0 + # Zero income -> zero countable income + wv_ccap_countable_income: 0 + +- name: Case 10, very high income ineligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 500_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_income_eligible: false + wv_ccap: 0 + +# ============================================================ +# Child age boundaries +# ============================================================ + +- name: Case 11, child at exactly age 13 ineligible. + period: 2025-01 + input: + people: + person1: + age: 35 + employment_income: 24_000 + immigration_status: CITIZEN + person2: + # Age 13 -> NOT < 13 -> ineligible (normal child) + age: 13 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_eligible_child: [false, false] + wv_ccap_eligible: false + wv_ccap: 0 + +- name: Case 12, child at age 12.99 eligible. + period: 2025-01 + input: + people: + person1: + age: 35 + employment_income: 24_000 + immigration_status: CITIZEN + person2: + # Age 12.99 -> < 13 -> eligible + age: 12.99 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_eligible_child: [false, true] + +- name: Case 13, special needs child at age 17.99 eligible. + period: 2025-01 + input: + people: + person1: + age: 45 + employment_income: 24_000 + immigration_status: CITIZEN + person2: + # Disabled child age 17.99 -> < 18 -> eligible + age: 17.99 + is_tax_unit_dependent: true + is_disabled: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_eligible_child: [false, true] + +- name: Case 14, special needs child at exactly age 18 ineligible. + period: 2025-01 + input: + people: + person1: + age: 45 + employment_income: 24_000 + immigration_status: CITIZEN + person2: + # Disabled child age 18 -> NOT < 18 -> ineligible + age: 18 + is_tax_unit_dependent: true + is_disabled: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_eligible_child: [false, false] + wv_ccap_eligible: false + +# ============================================================ +# Family size boundaries +# ============================================================ + +- name: Case 15, family size 1 single parent only no eligible child. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 12_000 + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: WV + output: + # No eligible child -> not eligible + wv_ccap_eligible: false + wv_ccap: 0 + +# ============================================================ +# Copay at 40% FPL boundary (should be $0) +# ============================================================ + +- name: Case 16, income at exactly 40% FPL copay is zero. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + # 40% FPL family of 2 = 21_150 * 0.4 = 8_460/yr + employment_income: 8_460 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 8_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 8_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 8_460 / 12 = 705 + # FPL ratio = 705 / 1_762.50 = 0.4 + # Threshold for non-zero copay is 0.4001, so 0.4 -> 0% bracket + wv_ccap_copay: 0 + +- name: Case 17, income just above 40% FPL copay is non-zero. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + # Just above 40% FPL: need FPL ratio > 0.4001 + # 21_150 * 0.4001 = 8_462.12/yr; use 8_475 -> ratio ~0.4008 + employment_income: 8_475 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 8_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 8_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 8_475 / 12 = 706.25 + # FPL ratio = 706.25 / 1_762.50 = 0.4007 > 0.4001 -> 2.5% bracket + # copay = 706.25 * 0.025 = 17.66 + # 7% cap = 706.25 * 0.07 = 49.44 + # min(17.66, 49.44) = 17.66 + wv_ccap_copay: 17.66 + +# ============================================================ +# Copay hitting 7% cap +# ============================================================ + +- name: Case 18, copay capped at 7% of income. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + # High income in 4% bracket (FPL ratio > 1.5001) + # Need enrolled to pass 185% FPL threshold + # Use income at ~170% FPL to be in 4% bracket + # 21_150 * 1.7 = 35_955/yr + employment_income: 35_955 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 10_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 10_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 35_955 / 12 = 2_996.25 + # FPL ratio = 2_996.25 / 1_762.50 = 1.7 + # In 4% bracket (> 1.5001) + # uncapped copay = 2_996.25 * 0.04 = 119.85 + # 7% cap = 2_996.25 * 0.07 = 209.74 + # min(119.85, 209.74) = 119.85 (not capped in this case) + wv_ccap_copay: 119.85 + +- name: Case 19, copay rate higher than 7% cap triggers cap. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + # To trigger the 7% cap, the rate bracket must exceed 7%. + # The highest bracket is 4%, so 4% < 7% means cap never binds + # under normal operation. But we verify the cap code path works + # by testing that the 7% cap is applied correctly. + # 4% rate * income = copay; 7% * income = cap + # Since 4% < 7%, the cap never binds for this simplified scale. + # This test confirms the copay correctly equals the uncapped amount. + employment_income: 36_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 10_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 10_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 36_000 / 12 = 3_000 + # FPL ratio = 3_000 / 1_762.50 = 1.7021 -> 4% bracket + # uncapped copay = 3_000 * 0.04 = 120 + # 7% cap = 3_000 * 0.07 = 210 + # min(120, 210) = 120 (cap does not bind) + wv_ccap_copay: 120 + +# ============================================================ +# Activity hours boundary +# ============================================================ + +- name: Case 20, parent at exactly 20 hours per week activity eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 12_000 + immigration_status: CITIZEN + weekly_hours_worked: 20 + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # 20 >= 20 -> meets activity requirement + wv_ccap_activity_eligible: true + +- name: Case 21, parent at 19 hours per week activity ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 12_000 + immigration_status: CITIZEN + weekly_hours_worked: 19 + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # 19 < 20 -> does NOT meet activity requirement + # But person1 is head/spouse, and the formula checks: + # sum(is_head_or_spouse & ~individually_eligible) == 0 + # Person1 is head, not eligible -> sum = 1 != 0 -> false + wv_ccap_activity_eligible: false + +- name: Case 22, full time student bypasses activity hours. + period: 2025-01 + input: + people: + person1: + age: 22 + employment_income: 12_000 + immigration_status: CITIZEN + weekly_hours_worked: 0 + is_full_time_student: true + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Full time student -> individually_eligible + wv_ccap_activity_eligible: true + +# ============================================================ +# Foster child copay always $0 +# ============================================================ + +- name: Case 23, foster child with income copay is zero. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 30_000 + immigration_status: CITIZEN + person2: + age: 5 + is_tax_unit_dependent: true + is_in_foster_care: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 8_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 8_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + # Foster child -> copay = $0 regardless of income + # FPL ratio would be ~1.42 -> normally 3.5% bracket + # But foster child exemption overrides + wv_ccap_copay: 0 + +- name: Case 24, foster child high income copay still zero. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 31_000 + immigration_status: CITIZEN + person2: + age: 5 + is_tax_unit_dependent: true + is_in_foster_care: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 8_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 8_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_copay: 0 + +# ============================================================ +# Empty SPM unit (zero eligible children) +# ============================================================ + +- name: Case 25, adults only no eligible children. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 28 + employment_income: 15_000 + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_eligible_child: [false, false] + wv_ccap_eligible: false + wv_ccap: 0 + +# ============================================================ +# All 5 provider types +# ============================================================ + +- name: Case 26, family home provider rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 3.25 + # 3.25 years = 39 months -> PRESCHOOL (37-59mo) + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: FAMILY_HOME + wv_ccap_quality_tier: TIER_I + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Family Home Tier I Preschool = $29/day + wv_ccap_daily_rate: [0, 29] + +- name: Case 27, family facility provider rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 3.25 + # 3.25 years = 39 months -> PRESCHOOL (37-59mo) + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: FAMILY_FACILITY + wv_ccap_quality_tier: TIER_I + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Family Facility Tier I Preschool = $33/day + wv_ccap_daily_rate: [0, 33] + +- name: Case 28, center provider rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 3.25 + # 3.25 years = 39 months -> PRESCHOOL (37-59mo) + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Center Tier I Preschool = $35/day + wv_ccap_daily_rate: [0, 35] + +- name: Case 29, out of school time provider rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: OUT_OF_SCHOOL_TIME + wv_ccap_quality_tier: TIER_I + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Out of School Time = $14.50/day (flat, no tier/age variation) + wv_ccap_daily_rate: [0, 14.5] + +- name: Case 30, informal relative provider rate under 2. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: INFORMAL_RELATIVE + wv_ccap_quality_tier: TIER_I + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Informal/Relative Under 2 = $7.50/day + wv_ccap_daily_rate: [0, 7.5] + +- name: Case 31, informal relative provider rate age 2 and over. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: INFORMAL_RELATIVE + wv_ccap_quality_tier: TIER_I + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Informal/Relative 2+ = $6.00/day + wv_ccap_daily_rate: [0, 6] + +# ============================================================ +# All 3 quality tiers +# ============================================================ + +- name: Case 32, Tier II center rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 3.25 + # 3.25 years = 39 months -> PRESCHOOL (37-59mo) + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_II + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Center Tier II Preschool = $38/day + wv_ccap_daily_rate: [0, 38] + +- name: Case 33, Tier III center rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 3.25 + # 3.25 years = 39 months -> PRESCHOOL (37-59mo) + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_III + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Center Tier III Preschool = $41/day + wv_ccap_daily_rate: [0, 41] + +# ============================================================ +# All 4 age categories +# ============================================================ + +- name: Case 34, infant age category. + period: 2025-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + person2: + # Age 0.5 = 6 months -> INFANT (0-24 months) + age: 0.5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_child_age_category: [SCHOOL_AGE, INFANT] + +- name: Case 35, toddler age category. + period: 2025-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + person2: + # Age 2.5 = 30 months -> TODDLER (25-36 months) + age: 2.5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_child_age_category: [SCHOOL_AGE, TODDLER] + +- name: Case 36, preschool age category. + period: 2025-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + person2: + # Age 3.25 = 39 months -> PRESCHOOL (37-59 months) + age: 3.25 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_child_age_category: [SCHOOL_AGE, PRESCHOOL] + +- name: Case 37, school age category. + period: 2025-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + person2: + # Age 6 = 72 months -> SCHOOL_AGE (60+ months) + age: 6 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_child_age_category: [SCHOOL_AGE, SCHOOL_AGE] + +# ============================================================ +# TANF categorical eligibility +# ============================================================ + +- name: Case 38, TANF recipient categorically income eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + # Above 85% SMI family of 2 (52_401.86/yr); TANF enrolled bypasses + employment_income: 60_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + is_tanf_enrolled: true + households: + household: + members: [person1, person2] + state_code: WV + output: + # TANF enrolled -> categorically income eligible regardless of income + wv_ccap_income_eligible: true + +# ============================================================ +# Non-traditional hours and special needs supplements +# ============================================================ + +- name: Case 39, non-traditional hours supplement adds to daily rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 3 + # 3 years = 36 months -> TODDLER (25-36mo) + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + wv_ccap_non_traditional_hours: true + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 12_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 12_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + # Center Tier I Toddler = $37 + $6 non-trad = $43 + # daily charge = (12_000/12) / (5 * 52/12) = 1_000 / 21.67 = 46.15 + # daily benefit = min(43, 46.15) = 43 + wv_ccap_daily_benefit: [0, 43] + +- name: Case 40, both special needs and non-traditional supplements. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 8 + is_tax_unit_dependent: true + is_disabled: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + wv_ccap_non_traditional_hours: true + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 15_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 15_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + # Center Tier I School Age = $32 + $3 special needs + $6 non-trad = $41 + # daily charge = (15_000/12) / (5 * 52/12) = 1_250 / 21.67 = 57.69 + # daily benefit = min(41, 57.69) = 41 + wv_ccap_daily_benefit: [0, 41] + +# ============================================================ +# Two-parent family both must meet activity requirement +# ============================================================ + +- name: Case 41, two parents both working activity eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 15_000 + immigration_status: CITIZEN + weekly_hours_worked: 25 + person2: + age: 28 + employment_income: 10_000 + immigration_status: CITIZEN + weekly_hours_worked: 20 + person3: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: WV + output: + # Both parents >= 20 hours -> both individually eligible + wv_ccap_activity_eligible: true + +- name: Case 42, two parents one not meeting hours ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 15_000 + immigration_status: CITIZEN + weekly_hours_worked: 25 + person2: + age: 28 + employment_income: 5_000 + immigration_status: CITIZEN + weekly_hours_worked: 15 + person3: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: WV + output: + # Person2 only 15 hours < 20 and not a student -> not individually eligible + # sum(is_head_or_spouse & ~individually_eligible) = 1 != 0 -> false + wv_ccap_activity_eligible: false + +# ============================================================ +# Benefit capped at actual expenses +# ============================================================ + +- name: Case 43, benefit capped at pre-subsidy expenses minus copay. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 24_000 + immigration_status: CITIZEN + person2: + age: 0.5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_III + childcare_days_per_week: 5 + # Low childcare expenses: rate will exceed daily charge + pre_subsidy_childcare_expenses: 3_600 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 3_600 + households: + household: + members: [person1, person2] + state_code: WV + output: + # Center Tier III Infant = $45/day + wv_ccap_daily_rate: [0, 45] + + # daily charge = (3_600/12) / (5 * 52/12) = 300 / 21.67 = 13.84 + # daily benefit = min(45, 13.84) = 13.84 + wv_ccap_daily_benefit: [0, 13.84] + + # total reimbursement = 13.84 * 21.67 = 299.89 + # FPL ratio = 2_000 / 1_762.50 = 1.1348 -> 3.5% bracket + # copay = 2_000 * 0.035 = 70 + # uncapped = max(300 - 70, 0) = 230 + # benefit = min(230, 299.89) = 230 + wv_ccap: 230 + +# ============================================================ +# Zero childcare days/expenses +# ============================================================ + +- name: Case 44, zero childcare days results in zero benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 24_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 0 + pre_subsidy_childcare_expenses: 0 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 0 + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap: 0 + +# ============================================================ +# Age category boundary: infant/toddler at 13 months +# ============================================================ + +- name: Case 45, child at exactly 12 months is infant. + period: 2025-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + person2: + # Age 1.0 = 12 months -> INFANT (threshold at 25 months for TODDLER) + age: 1.0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # 12 months < 25 threshold -> INFANT + wv_ccap_child_age_category: [SCHOOL_AGE, INFANT] + +- name: Case 46, child at exactly 24 months is infant. + period: 2025-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + person2: + # Age 2.0 = 24 months -> INFANT (threshold for TODDLER at 25 months) + age: 2.0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # 24 months < 25 threshold -> INFANT + wv_ccap_child_age_category: [SCHOOL_AGE, INFANT] + +- name: Case 47, child at 5 years is school age. + period: 2025-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + person2: + # Age 5.0 = 60 months -> SCHOOL_AGE (threshold at 60 months) + age: 5.0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # 60 months >= 60 threshold -> SCHOOL_AGE + wv_ccap_child_age_category: [SCHOOL_AGE, SCHOOL_AGE] + +# ============================================================ +# Informal age group boundaries +# ============================================================ + +- name: Case 48, informal age under 2 group. + period: 2025-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + person2: + # Age 1.5 = 18 months -> UNDER_2 + age: 1.5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # 18 months < 25 -> UNDER_2 + wv_ccap_informal_age_group: [AGE_2_AND_OVER, UNDER_2] + +- name: Case 49, informal age 24 months still in infant band. + period: 2025-01 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + person2: + # Age 2.0 = 24 months; Appendix B INFANT covers 0-24 months + age: 2.0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # 24 months < 25 -> UNDER_2 (matches Appendix B INFANT 0-24mo at $7.50) + wv_ccap_informal_age_group: [AGE_2_AND_OVER, UNDER_2] + +# ============================================================ +# Multiple children in one family +# ============================================================ + +- name: Case 50, two eligible children different ages and providers. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: FAMILY_HOME + wv_ccap_quality_tier: TIER_II + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 6_000 + person3: + age: 6 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 3 + pre_subsidy_childcare_expenses: 4_000 + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + spm_unit_pre_subsidy_childcare_expenses: 10_000 + households: + household: + members: [person1, person2, person3] + state_code: WV + output: + wv_ccap_eligible_child: [false, true, true] + + # Person2: Family Home Tier II Infant = $33/day + # Person3: Center Tier I School Age = $32/day + wv_ccap_daily_rate: [0, 33, 32] + + # Person2 age 1 = 12 months -> INFANT + # Person3 age 6 = 72 months -> SCHOOL_AGE + wv_ccap_child_age_category: [SCHOOL_AGE, INFANT, SCHOOL_AGE] + + # FPG family of 3: 26_650 + # FPL ratio = (20_000/12) / (26_650/12) = 1_666.67 / 2_220.83 = 0.7505 + # -> 3.0% bracket (>= 0.7001) + # copay = 1_666.67 * 0.03 = 50 + wv_ccap_copay: 50 + + # Person2 (FAMILY_HOME Tier II Infant, 5 days/wk, 6_000/yr): + # monthly expenses = 500; days/mo = 5 * 52/12 = 21.667 + # daily_charge = 500/21.667 = 23.077; daily_benefit = min(33, 23.077) = 23.077 + # reimbursement = 23.077 * 21.667 = 500 + # Person3 (CENTER Tier I School-Age, 3 days/wk, 4_000/yr): + # monthly expenses = 333.33; days/mo = 3 * 52/12 = 13 + # daily_charge = 333.33/13 = 25.641; daily_benefit = min(32, 25.641) = 25.641 + # reimbursement = 25.641 * 13 = 333.33 + # total reimbursement = 833.33 + # monthly pre_subsidy = 10_000/12 = 833.33 + # uncapped = max(833.33 - 50, 0) = 783.33 + # benefit = min(783.33, 833.33) = 783.33 + wv_ccap: 783.33 + +# ============================================================ +# Child-only SPM unit cannot pass activity test +# ============================================================ + +- name: Case 51, child-only SPM unit fails activity test. + period: 2025-01 + input: + people: + person1: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: WV + output: + # No head/spouse caretaker present -> activity test must fail, + # otherwise child-only units would pass on income + assets alone. + wv_ccap_activity_eligible: false + wv_ccap_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/integration.yaml new file mode 100644 index 00000000000..acc5f875c9a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/integration.yaml @@ -0,0 +1,237 @@ +# WV CCAP Integration Tests +# 2025 FPG (Contiguous US): +# first_person = 15_650, additional = 5_500 +# Family of 2: 21_150 +# Family of 3: 26_650 + +- name: Case 1, basic eligible family with center care. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 24_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 8_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 8_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + # === Eligibility === + wv_ccap_eligible_child: [false, true] + + # Single income test at 85% SMI: WV family-of-2 = 4_366.82/mo + # monthly income = 2_000 <= 4_366.82 -> eligible + wv_ccap_income_eligible: true + is_ccdf_asset_eligible: true + wv_ccap_eligible: true + + # === Age category === + # Person1 (age 35) = 420 months -> SCHOOL_AGE; Person2 (age 3) = 36 months -> TODDLER + wv_ccap_child_age_category: [SCHOOL_AGE, TODDLER] + + # === Daily rate === + # Center Tier I Toddler = $37/day + wv_ccap_daily_rate: [0, 37] + + # === Copay === + # FPL ratio = 2_000 / 1_762.50 = 1.1348 -> 3.5% bracket + # copay = 2_000 * 0.035 = 70 + wv_ccap_copay: 70 + + # === Daily benefit === + # daily charge = (8_000/12) / (5 * 52/12) = 666.67 / 21.67 = 30.77 + # daily benefit = min(37, 30.77) = 30.77 + wv_ccap_daily_benefit: [0, 30.77] + + # === Monthly benefit === + # total reimbursement = 30.77 * 21.67 = 666.78 + # uncapped = max(666.67 - 70, 0) = 596.67 + # benefit = min(596.67, 666.78) = 596.67 + wv_ccap: 596.67 + +- name: Case 2, low income family with zero copay. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + employment_income: 6_000 + immigration_status: CITIZEN + person2: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: FAMILY_HOME + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 6_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 6_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_eligible_child: [false, true] + wv_ccap_income_eligible: true + wv_ccap_eligible: true + + # Person1 (age 28) = 336 months -> SCHOOL_AGE; Person2 (age 1) = 12 months -> INFANT + wv_ccap_child_age_category: [SCHOOL_AGE, INFANT] + + # Family Home Tier I Infant = $30/day + wv_ccap_daily_rate: [0, 30] + + # FPL ratio = 500 / 1_762.50 = 0.2837 < 0.40 -> 0% copay + wv_ccap_copay: 0 + + # daily charge = 500 / 21.67 = 23.07 + # daily benefit = min(30, 23.07) = 23.07 + wv_ccap_daily_benefit: [0, 23.07] + + # total reimbursement = (500/21.6667) * 21.6667 = 500 + # uncapped = max(500 - 0, 0) = 500 + # benefit = min(500, 500) = 500 + wv_ccap: 500 + +- name: Case 3, ineligible family gets zero benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + # Above 85% SMI family of 2 (52_401.86/yr) + employment_income: 60_000 + immigration_status: CITIZEN + weekly_hours_worked: 40 + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 10_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 10_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 5_000 > 4_366.82 (85% SMI family of 2) + wv_ccap_income_eligible: false + wv_ccap_eligible: false + wv_ccap: 0 + +- name: Case 4, special needs child with supplement. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 24_000 + immigration_status: CITIZEN + person2: + age: 15 + is_tax_unit_dependent: true + is_disabled: true + immigration_status: CITIZEN + ssi: 0 + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_II + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 10_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 10_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + # Disabled child age 15 < 18 -> eligible + wv_ccap_eligible_child: [false, true] + wv_ccap_income_eligible: true + wv_ccap_eligible: true + + # Person1 (age 40) = 480 months -> SCHOOL_AGE; Person2 (age 15) = 180 months -> SCHOOL_AGE + wv_ccap_child_age_category: [SCHOOL_AGE, SCHOOL_AGE] + + # Center Tier II School Age = $35/day + wv_ccap_daily_rate: [0, 35] + + # daily rate with special needs supplement = 35 + 3 = 38 + # daily charge = (10_000/12) / 21.67 = 833.33 / 21.67 = 38.46 + # daily benefit = min(38, 38.46) = 38 + wv_ccap_daily_benefit: [0, 38] + + # total reimbursement = 38 * 21.67 = 823.33 + # copay: FPL ratio = 2_000 / 1_762.50 = 1.1348 -> 3.5% + # copay = 2_000 * 0.035 = 70 + wv_ccap_copay: 70 + + # uncapped = max(833.33 - 70, 0) = 763.33 + # benefit = min(763.33, 823.33) = 763.33 + wv_ccap: 763.33 + +- name: Case 5, non-WV family gets zero benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 24_000 + person2: + age: 4 + is_tax_unit_dependent: true + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 8_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 8_000 + households: + household: + members: [person1, person2] + state_code: VA + output: + wv_ccap: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_child_age_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_child_age_category.yaml new file mode 100644 index 00000000000..ca87599180d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_child_age_category.yaml @@ -0,0 +1,88 @@ +# WV CCAP child age category tests +# Infant (0-24mo), Toddler (25-36mo), Pre-School (37-59mo), School-Age (60+mo) +# Age group is derived from age in months via bracket parameter. +# age_in_months = age * 12 (since age is YEAR-defined float) + +- name: Case 1, infant at 6 months. + period: 2025-01 + input: + people: + person1: + age: 0.5 + # 0.5 years = 6 months -> INFANT (0-12mo bracket) + households: + household: + members: [person1] + state_code: WV + output: + wv_ccap_child_age_category: INFANT + +- name: Case 2, toddler at 30 months. + period: 2025-01 + input: + people: + person1: + age: 2.5 + # 2.5 years = 30 months -> TODDLER (25-36mo bracket) + households: + household: + members: [person1] + state_code: WV + output: + wv_ccap_child_age_category: TODDLER + +- name: Case 3, preschool at 40 months. + period: 2025-01 + input: + people: + person1: + age: 3.33 + # 3.33 years ~ 40 months -> PRESCHOOL (37-59mo bracket) + households: + household: + members: [person1] + state_code: WV + output: + wv_ccap_child_age_category: PRESCHOOL + +- name: Case 4, school-age at 72 months. + period: 2025-01 + input: + people: + person1: + age: 6 + # 6 years = 72 months -> SCHOOL_AGE (60+ months bracket) + households: + household: + members: [person1] + state_code: WV + output: + wv_ccap_child_age_category: SCHOOL_AGE + +- name: Case 5, boundary at exactly 25 months. + period: 2025-01 + input: + people: + person1: + age: 2.0834 + # 2.0834 years = 25.0008 months -> TODDLER (threshold at 25) + households: + household: + members: [person1] + state_code: WV + output: + wv_ccap_child_age_category: TODDLER + +- name: Case 6, boundary at exactly 37 months. + period: 2025-01 + input: + people: + person1: + age: 3.0834 + # 3.0834 years = 37.0008 months -> PRESCHOOL (threshold at 37) + households: + household: + members: [person1] + state_code: WV + output: + wv_ccap_child_age_category: PRESCHOOL diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_copay.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_copay.yaml new file mode 100644 index 00000000000..e0fc2d1e73f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_copay.yaml @@ -0,0 +1,104 @@ +# WV CCAP Co-payment Tests +# 2025 FPG family of 2: 21_150 + +- name: Case 1, income below 40% FPL pays zero copay. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 6_000 + person2: + age: 5 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # FPL ratio = 500 / 1_762.50 = 0.2837 < 0.40 -> 0% rate + wv_ccap_copay: 0 + +- name: Case 2, mid-range income copay. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 18_000 + person2: + age: 5 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 1_500 + # FPL ratio = 1_500 / 1_762.50 = 0.8511 -> 3% rate + # copay = 1_500 * 0.03 = 45 + wv_ccap_copay: 45 + +- name: Case 3, copay capped at 7% of income. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 36_000 + person2: + age: 5 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 3_000 + # FPL ratio = 3_000 / 1_762.50 = 1.7021 -> 4% bracket rate + # uncapped copay = 3_000 * 0.04 = 120 + # 7% cap = 3_000 * 0.07 = 210 + # 120 <= 210 -> copay = 120 + wv_ccap_copay: 120 + +- name: Case 4, foster family pays zero copay. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 36_000 + person2: + age: 5 + is_in_foster_care: true + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_copay: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_countable_income.yaml new file mode 100644 index 00000000000..9e5f7dee1fe --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_countable_income.yaml @@ -0,0 +1,75 @@ +# WV CCAP countable income tests +# wv_ccap_countable_income uses adds = sources parameter list +# Sources: employment_income, self_employment_income, social_security, ssi, +# unemployment_compensation, workers_compensation, pension_income, +# alimony_income, child_support_received, dividend_income, interest_income, +# rental_income, veterans_benefits, military_retirement_pay +# Note: tanf excluded from sources to break circular dependency +# (TANF recipients are categorically eligible via is_tanf_enrolled) + +- name: Case 1, employment and unearned income counted. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 24_000 + social_security: 6_000 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Monthly: employment 24,000/12 = 2,000 + SS 6,000/12 = 500 + # Total monthly = 2,500 + wv_ccap_countable_income: 2_500 + +- name: Case 2, SNAP is excluded from countable income. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 18_000 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + snap: 2_400 + households: + household: + members: [person1, person2] + state_code: WV + output: + # Monthly: employment 18,000/12 = 1,500 + # SNAP (2,400/yr) is excluded -> not counted + wv_ccap_countable_income: 1_500 + +- name: Case 3, self-employment income counted. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + self_employment_income: 36_000 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Monthly: self_employment 36,000/12 = 3,000 + wv_ccap_countable_income: 3_000 diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_daily_benefit.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_daily_benefit.yaml new file mode 100644 index 00000000000..44a151aaad8 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_daily_benefit.yaml @@ -0,0 +1,100 @@ +# WV CCAP daily benefit tests +# Daily benefit per child = min(rate, actual daily charge) + +- name: Case 1, rate minus copay share gives positive benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 24_000 + person2: + age: 3 + # 3 years = 36 months -> TODDLER (25-36mo) + is_tax_unit_dependent: true + childcare_days_per_week: 5 + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + pre_subsidy_childcare_expenses: 8_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Center Tier I Toddler = $37/day + # Daily rate for this child = $37 + wv_ccap_daily_rate: [0, 37] + +- name: Case 2, zero copay means full rate as benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 6_000 + person2: + age: 1 + is_tax_unit_dependent: true + childcare_days_per_week: 5 + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_II + pre_subsidy_childcare_expenses: 10_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Below 40% FPL -> $0 copay + # Center Tier II Infant = $42/day + # Full rate as daily benefit + wv_ccap_daily_rate: [0, 42] + +- name: Case 3, non-traditional hours supplement adds $6/day. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 6_000 + person2: + age: 3 + # 3 years = 36 months -> TODDLER (25-36mo) + is_tax_unit_dependent: true + childcare_days_per_week: 5 + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + wv_ccap_non_traditional_hours: true + pre_subsidy_childcare_expenses: 12_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Below 40% FPL -> $0 copay + # Center Tier I Toddler = $37/day + # Non-traditional hours supplement = $6/day + # total_rate = 37 + 6 = $43/day + # daily_charge = 12_000 / (5 * 52/12) = 12_000 / 21.6667 = $553.85/day + # min(43, 553.85) = $43/day + wv_ccap_daily_benefit: [0, 43] diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_daily_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_daily_rate.yaml new file mode 100644 index 00000000000..9f780474ef4 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_daily_rate.yaml @@ -0,0 +1,189 @@ +# WV CCAP Daily Provider Rate Tests + +- name: Case 1, center Tier I infant rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 0.5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Infant (0-12 months), Center, Tier I = $39 + wv_ccap_daily_rate: [0, 39] + +- name: Case 2, family home Tier II toddler rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 2.5 + # 2.5 years = 30 months -> TODDLER (25-36mo) + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: FAMILY_HOME + wv_ccap_quality_tier: TIER_II + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Toddler (25-36 months), Family Home, Tier II = $33 + wv_ccap_daily_rate: [0, 33] + +- name: Case 3, family facility Tier III preschool rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 3.25 + # 3.25 years = 39 months -> PRESCHOOL (37-59mo) + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: FAMILY_FACILITY + wv_ccap_quality_tier: TIER_III + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Preschool (37-59 months), Family Facility, Tier III = $39 + wv_ccap_daily_rate: [0, 39] + +- name: Case 4, out of school time rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: OUT_OF_SCHOOL_TIME + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Out of School Time Tier I = $14.50 + wv_ccap_daily_rate: [0, 14.5] + +- name: Case 5, informal relative under 2 rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: INFORMAL_RELATIVE + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Under 2, Informal/Relative = $7.50 + wv_ccap_daily_rate: [0, 7.5] + +- name: Case 6, informal relative age 2+ rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: INFORMAL_RELATIVE + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # 2+, Informal/Relative = $6.00 + wv_ccap_daily_rate: [0, 6] + +- name: Case 7, center Tier III school age rate. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_III + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # School Age (60+ months), Center, Tier III = $39 + wv_ccap_daily_rate: [0, 39] diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_eligible.yaml new file mode 100644 index 00000000000..c91c6bf10b3 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_eligible.yaml @@ -0,0 +1,171 @@ +# WV CCAP overall eligibility tests +# Combines: eligible child + income eligible + activity eligible + +- name: Case 1, eligible child and income and activity. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 24_000 + weekly_hours_worked: 30 + person2: + age: 5 + is_tax_unit_dependent: true + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Child age 5 < 13 -> eligible child + # Income 24,000 < 185% FPL (39,127.50) -> income eligible + # Parent works 30 hrs >= 20 -> activity eligible + wv_ccap_eligible: true + +- name: Case 2, no eligible child means not eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 24_000 + weekly_hours_worked: 30 + person2: + age: 15 + 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: WV + output: + # Child age 15 >= 13, not disabled -> no eligible child + wv_ccap_eligible: false + +- name: Case 3, income too high means not eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + # Need income above 85% SMI for family of 2: + # WV 4-person SMI (2024-10-01) = 90,661; 2-person factor = 0.68 + # 85% SMI family of 2 = 90,661 * 0.68 * 0.85 = 52,401.86/yr + employment_income: 60_000 + weekly_hours_worked: 40 + person2: + age: 5 + is_tax_unit_dependent: true + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # 60,000 > 52,401.86 -> not income eligible + wv_ccap_eligible: false + +- name: Case 4, parent not meeting activity hours means not eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 12_000 + weekly_hours_worked: 10 + is_full_time_student: false + person2: + age: 5 + is_tax_unit_dependent: true + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Parent works 10 hrs < 20 minimum, not student -> not activity eligible + wv_ccap_eligible: false + +- name: Case 5, two-parent family both meeting activity requirement. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 18_000 + weekly_hours_worked: 25 + person2: + age: 28 + employment_income: 12_000 + weekly_hours_worked: 20 + person3: + age: 3 + is_tax_unit_dependent: true + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: WV + output: + # Both parents work >= 20 hrs -> activity eligible + # Combined income: 30,000 < 185% FPL-3 (49,302.50) -> income eligible + # Child age 3 < 13 -> eligible child + wv_ccap_eligible: true + +- name: Case 6, minor parent in qualifying activity remains eligible. + period: 2025-01 + input: + people: + person1: + age: 17 + employment_income: 12_000 + weekly_hours_worked: 25 + person2: + age: 1 + is_tax_unit_dependent: true + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # Manual §1.1.10, §4.5.3.6, §4.5.6 contemplate minor parents in + # qualifying activity. Parent age 17 working 25 hrs/wk meets the + # activity test; income well below 85% SMI; child age 1 eligible. + wv_ccap_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_eligible_child.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_eligible_child.yaml new file mode 100644 index 00000000000..d950bd9514b --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_eligible_child.yaml @@ -0,0 +1,118 @@ +- name: Case 1, child under 13 who is a citizen and dependent. + period: 2025-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_eligible_child: [false, true] + +- name: Case 2, child age 13 ineligible without disability. + period: 2025-01 + input: + people: + person1: + age: 35 + person2: + age: 13 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_eligible_child: [false, false] + +- name: Case 3, disabled child age 15 eligible. + period: 2025-01 + input: + people: + person1: + age: 40 + person2: + age: 15 + is_tax_unit_dependent: true + is_disabled: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_eligible_child: [false, true] + +- name: Case 4, undocumented child ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: UNDOCUMENTED + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + wv_ccap_eligible_child: [false, false] + +- name: Case 5, non-tax-dependent child still eligible (residency, not tax dependency, governs). + period: 2025-01 + input: + people: + person1: + age: 30 + person2: + age: 8 + is_tax_unit_dependent: false + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # §3.2 requires the child to reside with the family, not to be a tax + # dependent. With the dependency filter removed, a co-resident child + # under 13 who is a citizen remains eligible. + wv_ccap_eligible_child: [false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml new file mode 100644 index 00000000000..789fc181d5f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_ccap_income_eligible.yaml @@ -0,0 +1,102 @@ +# WV CCAP Income Eligibility Tests +# Single income test per CCDF Plan §2.2.4 / §2.2.5(a): 85% of state median income. +# WV 4-person SMI (2024-10-01) = 90_661/yr +# Family-size factors: 1p=0.52, 2p=0.68, 3p=0.84, 4p=1.00, 5p=1.16, 6p=1.32 +# 85% SMI family of 2 = 90_661 * 0.68 * 0.85 = 52_401.86/yr = 4_366.82/mo + +- name: Case 1, income below 85% SMI eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 24_000 + person2: + age: 5 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 2_000 <= 4_366.82 -> eligible + wv_ccap_income_eligible: true + +- name: Case 2, income above 85% SMI ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 60_000 + person2: + age: 5 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 5_000 > 4_366.82 -> ineligible + wv_ccap_income_eligible: false + +- name: Case 3, income at 85% SMI boundary eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + # Just below 85% SMI for family of 2 + employment_income: 52_000 + person2: + age: 5 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: WV + output: + # monthly income = 4_333.33 <= 4_366.82 -> eligible + wv_ccap_income_eligible: true + +- name: Case 4, TANF recipients categorically eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 60_000 + person2: + age: 5 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + is_tanf_enrolled: true + households: + household: + members: [person1, person2] + state_code: WV + output: + # Income above SMI but TANF bypass applies per Manual §3.2.1. + # The bypass extends to TANF children-only cases (§3.2.1.4) that + # should still meet the income test — we don't currently model that + # distinction. + wv_ccap_income_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_child_care_subsidies.yaml b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_child_care_subsidies.yaml new file mode 100644 index 00000000000..d9d129a6048 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/wv/dhhr/ccap/wv_child_care_subsidies.yaml @@ -0,0 +1,31 @@ +- name: Case 1, WV child care subsidies wrapper. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 24_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + wv_ccap_provider_type: CENTER + wv_ccap_quality_tier: TIER_I + childcare_days_per_week: 5 + pre_subsidy_childcare_expenses: 8_000 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 8_000 + households: + household: + members: [person1, person2] + state_code: WV + output: + # wv_ccap monthly = ~596.67 -> annual = ~7_160 + wv_child_care_subsidies: 7_160 diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_activity_eligible.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_activity_eligible.py new file mode 100644 index 00000000000..7f116fdadd6 --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_activity_eligible.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class wv_ccap_activity_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for West Virginia CCAP based on activity requirements" + definition_period = MONTH + defined_for = StateCode.WV + reference = "https://bfa.wv.gov/media/6766/download?inline#page=32" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.wv.dhhr.ccap.eligibility + person = spm_unit.members + is_head_or_spouse = person("is_tax_unit_head_or_spouse", period.this_year) + hours_worked = person("weekly_hours_worked", period.this_year) + meets_work_requirement = hours_worked >= p.activity_hours + is_student = person("is_full_time_student", period.this_year) + individually_eligible = meets_work_requirement | is_student + # A unit with no head or spouse (e.g., a child-only record) has no + # caretaker to be in a qualifying activity and must not pass. + has_caretaker = spm_unit.sum(is_head_or_spouse) > 0 + no_ineligible_caretaker = ( + spm_unit.sum(is_head_or_spouse & ~individually_eligible) == 0 + ) + return has_caretaker & no_ineligible_caretaker diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_eligible.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_eligible.py new file mode 100644 index 00000000000..8692aa52e89 --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_eligible.py @@ -0,0 +1,25 @@ +from policyengine_us.model_api import * + + +class wv_ccap_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for West Virginia CCAP" + definition_period = MONTH + defined_for = StateCode.WV + reference = ( + "https://bfa.wv.gov/media/6766/download?inline#page=25", + "https://bfa.wv.gov/media/39915/download?inline#page=16", + ) + + def formula(spm_unit, period, parameters): + # We don't enforce a minimum parent-age floor: §1.1.10 recognizes + # emancipated minors, §1.1.13 treats them as separate families, and + # §4.5.3.6 / §4.5.6 explicitly contemplate minor parents in high + # school or home schooling. The activity requirement below carries + # the substantive caretaker check. + has_eligible_child = add(spm_unit, period, ["wv_ccap_eligible_child"]) > 0 + income_eligible = spm_unit("wv_ccap_income_eligible", period) + asset_eligible = spm_unit("is_ccdf_asset_eligible", period.this_year) + activity_eligible = spm_unit("wv_ccap_activity_eligible", period) + return has_eligible_child & income_eligible & asset_eligible & activity_eligible diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_eligible_child.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_eligible_child.py new file mode 100644 index 00000000000..ae94d306101 --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_eligible_child.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class wv_ccap_eligible_child(Variable): + value_type = bool + entity = Person + label = "Eligible child for West Virginia CCAP" + definition_period = MONTH + defined_for = StateCode.WV + reference = ( + "https://bfa.wv.gov/media/6766/download?inline#page=25", + "https://bfa.wv.gov/media/39915/download?inline#page=16", + ) + + def formula(person, period, parameters): + # Manual Sec 3.1.2 extends eligibility to ages 13-17 if EITHER the + # child is under court supervision (Sec 3.1.2.1) OR has special + # needs (Sec 3.1.2.2). We only model the special-needs branch + # because we don't track court-supervision status at the moment. + p = parameters(period).gov.states.wv.dhhr.ccap.eligibility + age = person("age", period.this_year) + is_disabled = person("is_disabled", period.this_year) + age_eligible = where( + is_disabled, age < p.special_needs_child_age_limit, age < p.child_age_limit + ) + immigration_eligible = person( + "is_ccdf_immigration_eligible_child", period.this_year + ) + return age_eligible & immigration_eligible diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_income_eligible.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_income_eligible.py new file mode 100644 index 00000000000..ed93b3e65a6 --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/eligibility/wv_ccap_income_eligible.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class wv_ccap_income_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for West Virginia CCAP based on income" + definition_period = MONTH + defined_for = StateCode.WV + reference = ( + "https://bfa.wv.gov/media/39915/download?inline#page=20", + "https://bfa.wv.gov/media/6781/download?inline", + ) + + def formula(spm_unit, period, parameters): + # Per CCDF State Plan §2.2.4 / §2.2.5(a), WV sets its sole income + # ceiling at 85% of state median income; graduated phase-out is + # marked "Not applicable" because the threshold already sits at + # the federal CCDF ceiling. + p = parameters(period).gov.states.wv.dhhr.ccap.income + countable_income = spm_unit("wv_ccap_countable_income", period) + smi = spm_unit("hhs_smi", period) + smi_eligible = countable_income <= smi * p.smi_rate + # TANF recipients are categorically income-eligible per Policy + # Manual §3.2.1. We don't currently distinguish "TANF children- + # only" cases (§3.2.1.4), which must still meet the income test; + # the bypass applies to all is_tanf_enrolled units. + is_tanf = spm_unit("is_tanf_enrolled", period) + return is_tanf | smi_eligible diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap.py new file mode 100644 index 00000000000..f4fde69b0b0 --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class wv_ccap(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "West Virginia CCAP benefit amount" + definition_period = MONTH + defined_for = "wv_ccap_eligible" + reference = ( + "https://bfa.wv.gov/media/6766/download?inline#page=73", + "https://bfa.wv.gov/media/39915/download?inline#page=41", + ) + + def formula(spm_unit, period, parameters): + copay = spm_unit("wv_ccap_copay", period) + person = spm_unit.members + daily_benefit = person("wv_ccap_daily_benefit", period) + days_per_week = person("childcare_days_per_week", period.this_year) + days_per_month = days_per_week * (WEEKS_IN_YEAR / MONTHS_IN_YEAR) + total_reimbursement = spm_unit.sum(daily_benefit * days_per_month) + pre_subsidy_childcare_expenses = spm_unit( + "spm_unit_pre_subsidy_childcare_expenses", period + ) + uncapped = max_(pre_subsidy_childcare_expenses - copay, 0) + return min_(uncapped, total_reimbursement) diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_child_age_category.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_child_age_category.py new file mode 100644 index 00000000000..f1237c50b4a --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_child_age_category.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class WVCCAPChildAgeCategory(Enum): + INFANT = "Infant (0-24 months)" + TODDLER = "Toddler (25-36 months)" + PRESCHOOL = "Preschool (37-59 months)" + SCHOOL_AGE = "School Age (60+ months)" + + +class wv_ccap_child_age_category(Variable): + value_type = Enum + entity = Person + possible_values = WVCCAPChildAgeCategory + default_value = WVCCAPChildAgeCategory.PRESCHOOL + definition_period = MONTH + label = "West Virginia CCAP child age category" + defined_for = StateCode.WV + reference = "https://bfa.wv.gov/media/6831/download?inline" + + def formula(person, period, parameters): + age_in_months = person("age", period.this_year) * MONTHS_IN_YEAR + p = parameters(period).gov.states.wv.dhhr.ccap.age_group + return p.months.calc(age_in_months) diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_copay.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_copay.py new file mode 100644 index 00000000000..bd25997c5f4 --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_copay.py @@ -0,0 +1,39 @@ +from policyengine_us.model_api import * + + +class wv_ccap_copay(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "West Virginia CCAP family co-payment" + definition_period = MONTH + defined_for = StateCode.WV + reference = ( + "https://bfa.wv.gov/media/6826/download?inline", + "https://bfa.wv.gov/media/39915/download?inline#page=41", + ) + + def formula(spm_unit, period, parameters): + # Simplified percent-of-income approximation of Appendix A. The + # actual schedule is a 176-cell daily-dollar table (11 family sizes + # x 16 FPL bands), with the fee charged per child up to 3 per + # Manual Sec 6.4.3. The current rate.yaml is derived from the + # 3-person column as a representative middle case; see that file + # for the divergence by family size. The 7% max_share cap and the + # under-40%-FPL waiver are encoded in the rate schedule itself; + # only the foster-child waiver needs an explicit override here. + p = parameters(period).gov.states.wv.dhhr.ccap.copayment + countable_income = spm_unit("wv_ccap_countable_income", period) + fpg = spm_unit("spm_unit_fpg", period) + mask = fpg > 0 + fpl_ratio = np.divide( + countable_income, + fpg, + out=np.zeros_like(countable_income, dtype=float), + where=mask, + ) + has_foster_child = add(spm_unit, period, ["is_in_foster_care"]) > 0 + copay_rate = p.rate.calc(fpl_ratio) + uncapped_copay = countable_income * copay_rate + capped_copay = min_(uncapped_copay, countable_income * p.max_share) + return where(has_foster_child, 0, capped_copay) diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_countable_income.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_countable_income.py new file mode 100644 index 00000000000..754b8ab530b --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_countable_income.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class wv_ccap_countable_income(Variable): + value_type = float + entity = SPMUnit + label = "West Virginia CCAP countable income" + definition_period = MONTH + unit = USD + defined_for = StateCode.WV + reference = "https://bfa.wv.gov/media/6766/download?inline#page=49" + + adds = "gov.states.wv.dhhr.ccap.income.countable_income.sources" diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_daily_benefit.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_daily_benefit.py new file mode 100644 index 00000000000..405bc7a1c1c --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_daily_benefit.py @@ -0,0 +1,32 @@ +from policyengine_us.model_api import * + + +class wv_ccap_daily_benefit(Variable): + value_type = float + entity = Person + unit = USD + label = "West Virginia CCAP daily benefit per child" + definition_period = MONTH + defined_for = "wv_ccap_eligible_child" + reference = "https://bfa.wv.gov/media/6766/download?inline#page=73" + + def formula(person, period, parameters): + p = parameters(period).gov.states.wv.dhhr.ccap + daily_rate = person("wv_ccap_daily_rate", period) + is_disabled = person("is_disabled", period.this_year) + special_needs_supplement = where(is_disabled, p.supplements.special_needs, 0) + non_trad = person("wv_ccap_non_traditional_hours", period) + non_trad_supplement = where(non_trad, p.supplements.non_traditional_hours, 0) + total_rate = daily_rate + special_needs_supplement + non_trad_supplement + pre_subsidy = person("pre_subsidy_childcare_expenses", period) + daily_days = person("childcare_days_per_week", period.this_year) * ( + WEEKS_IN_YEAR / MONTHS_IN_YEAR + ) + mask = daily_days > 0 + daily_charge = np.divide( + pre_subsidy, + daily_days, + out=np.zeros_like(pre_subsidy, dtype=float), + where=mask, + ) + return max_(min_(total_rate, daily_charge), 0) diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_daily_rate.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_daily_rate.py new file mode 100644 index 00000000000..74fff8dabb3 --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_daily_rate.py @@ -0,0 +1,45 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.wv.dhhr.ccap.wv_ccap_provider_type import ( + WVCCAPProviderType, +) + + +class wv_ccap_daily_rate(Variable): + value_type = float + entity = Person + unit = USD + label = "West Virginia CCAP daily provider reimbursement rate" + definition_period = MONTH + defined_for = "wv_ccap_eligible_child" + reference = "https://bfa.wv.gov/media/6831/download?inline" + + def formula(person, period, parameters): + p = parameters(period).gov.states.wv.dhhr.ccap.rates + provider_type = person("wv_ccap_provider_type", period) + quality_tier = person("wv_ccap_quality_tier", period) + age_category = person("wv_ccap_child_age_category", period) + informal_age = person("wv_ccap_informal_age_group", period) + + family_home_rate = p.family_home[quality_tier][age_category] + family_facility_rate = p.family_facility[quality_tier][age_category] + center_rate = p.center[quality_tier][age_category] + out_of_school_rate = p.out_of_school_time + informal_rate = p.informal_relative[informal_age] + + types = WVCCAPProviderType + return select( + [ + provider_type == types.FAMILY_HOME, + provider_type == types.FAMILY_FACILITY, + provider_type == types.CENTER, + provider_type == types.OUT_OF_SCHOOL_TIME, + provider_type == types.INFORMAL_RELATIVE, + ], + [ + family_home_rate, + family_facility_rate, + center_rate, + out_of_school_rate, + informal_rate, + ], + ) diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_informal_age_group.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_informal_age_group.py new file mode 100644 index 00000000000..f77c7c649f6 --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_informal_age_group.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class WVCCAPInformalAgeGroup(Enum): + UNDER_2 = "Under 2 years" + AGE_2_AND_OVER = "2 years and over" + + +class wv_ccap_informal_age_group(Variable): + value_type = Enum + entity = Person + possible_values = WVCCAPInformalAgeGroup + default_value = WVCCAPInformalAgeGroup.AGE_2_AND_OVER + definition_period = MONTH + label = "West Virginia CCAP informal care age group" + defined_for = StateCode.WV + reference = "https://bfa.wv.gov/media/6831/download?inline" + + def formula(person, period, parameters): + age_in_months = person("age", period.this_year) * MONTHS_IN_YEAR + p = parameters(period).gov.states.wv.dhhr.ccap.age_group + return p.informal_months.calc(age_in_months) diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_non_traditional_hours.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_non_traditional_hours.py new file mode 100644 index 00000000000..177db982069 --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_non_traditional_hours.py @@ -0,0 +1,9 @@ +from policyengine_us.model_api import * + + +class wv_ccap_non_traditional_hours(Variable): + value_type = bool + entity = Person + definition_period = MONTH + label = "Whether child receives care during non-traditional hours for West Virginia CCAP" + defined_for = StateCode.WV diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_provider_type.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_provider_type.py new file mode 100644 index 00000000000..fd0ad73f391 --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_provider_type.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class WVCCAPProviderType(Enum): + FAMILY_HOME = "Family Child Care Home" + FAMILY_FACILITY = "Family Child Care Facility" + CENTER = "Child Care Center" + OUT_OF_SCHOOL_TIME = "Out of School Time" + INFORMAL_RELATIVE = "Informal/Relative Care" + + +class wv_ccap_provider_type(Variable): + value_type = Enum + entity = Person + possible_values = WVCCAPProviderType + default_value = WVCCAPProviderType.CENTER + definition_period = MONTH + label = "West Virginia CCAP child care provider type" + defined_for = StateCode.WV + reference = "https://bfa.wv.gov/media/6831/download?inline" diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_quality_tier.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_quality_tier.py new file mode 100644 index 00000000000..8cd6a0ed39c --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_ccap_quality_tier.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class WVCCAPQualityTier(Enum): + TIER_I = "Tier I" + TIER_II = "Tier II" + TIER_III = "Tier III" + + +class wv_ccap_quality_tier(Variable): + value_type = Enum + entity = Person + possible_values = WVCCAPQualityTier + default_value = WVCCAPQualityTier.TIER_I + definition_period = MONTH + label = "West Virginia CCAP provider quality tier" + defined_for = StateCode.WV + reference = "https://bfa.wv.gov/media/6831/download?inline" diff --git a/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_child_care_subsidies.py b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_child_care_subsidies.py new file mode 100644 index 00000000000..6730185a6cd --- /dev/null +++ b/policyengine_us/variables/gov/states/wv/dhhr/ccap/wv_child_care_subsidies.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class wv_child_care_subsidies(Variable): + value_type = float + entity = SPMUnit + label = "West Virginia child care subsidies" + unit = USD + definition_period = YEAR + defined_for = StateCode.WV + adds = ["wv_ccap"] diff --git a/uv.lock b/uv.lock index 76042ff3b95..040a348fa5b 100644 --- a/uv.lock +++ b/uv.lock @@ -2974,7 +2974,7 @@ wheels = [ [[package]] name = "policyengine-us" -version = "1.691.7" +version = "1.691.10" source = { editable = "." } dependencies = [ { name = "microdf-python" },