diff --git a/changelog.d/nh-ccap.added.md b/changelog.d/nh-ccap.added.md new file mode 100644 index 00000000000..b99321a2926 --- /dev/null +++ b/changelog.d/nh-ccap.added.md @@ -0,0 +1 @@ +Add New Hampshire 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 367612a52ae..4c9e17fc861 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 @@ -5,6 +5,7 @@ values: - co_child_care_subsidies # Colorado Child Care Assistance Program - ma_child_care_subsidies # Massachusetts Child Care Financial Assistance - ne_child_care_subsidies # Nebraska Child Care Subsidy + - nh_child_care_subsidies # New Hampshire Child Care Scholarship Program metadata: unit: list diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/age_category/infant_max_months.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/age_category/infant_max_months.yaml new file mode 100644 index 00000000000..b149765a3fe --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/age_category/infant_max_months.yaml @@ -0,0 +1,13 @@ +description: New Hampshire sets the infant age category as up to this age in months under the Child Care Scholarship Program. +values: + 2024-01-01: 18 + +metadata: + unit: month + period: year + label: New Hampshire CCAP infant age category upper bound in months + reference: + - title: He-C 6910.17(i) (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.17 + - title: New Hampshire CCDF State Plan 2025-2027, Section 4.3.2 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=60 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/age_category/preschool_max_months.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/age_category/preschool_max_months.yaml new file mode 100644 index 00000000000..4e083c24b3a --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/age_category/preschool_max_months.yaml @@ -0,0 +1,13 @@ +description: New Hampshire sets the preschool age category as up to this age in months under the Child Care Scholarship Program. +values: + 2024-01-01: 79 + +metadata: + unit: month + period: year + label: New Hampshire CCAP preschool age category upper bound in months + reference: + - title: He-C 6910.17(i) (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.17 + - title: New Hampshire CCDF State Plan 2025-2027, Section 4.3.2 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=60 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/age_category/toddler_max_months.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/age_category/toddler_max_months.yaml new file mode 100644 index 00000000000..f5f8ce558cb --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/age_category/toddler_max_months.yaml @@ -0,0 +1,13 @@ +description: New Hampshire sets the toddler age category as up to this age in months under the Child Care Scholarship Program. +values: + 2024-01-01: 36 + +metadata: + unit: month + period: year + label: New Hampshire CCAP toddler age category upper bound in months + reference: + - title: He-C 6910.17(i) (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.17 + - title: New Hampshire CCDF State Plan 2025-2027, Section 4.3.2 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=60 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/cost_share/step_1_fpg_rate.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/cost_share/step_1_fpg_rate.yaml new file mode 100644 index 00000000000..d784f027140 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/cost_share/step_1_fpg_rate.yaml @@ -0,0 +1,13 @@ +description: New Hampshire sets this share of the federal poverty guideline as the upper threshold for zero cost share under the Child Care Scholarship Program. +values: + 2024-01-01: 1 + +metadata: + unit: /1 + period: year + label: New Hampshire CCAP step 1 FPG rate threshold + reference: + - title: He-C 6910.18, Table 6910.19 (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.18 + - title: New Hampshire CCDF State Plan 2025-2027, Section 3.2.1 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=42 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/cost_share/step_2_amount.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/cost_share/step_2_amount.yaml new file mode 100644 index 00000000000..f0340f4babb --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/cost_share/step_2_amount.yaml @@ -0,0 +1,13 @@ +description: New Hampshire provides this amount as the flat weekly cost share under the Child Care Scholarship Program. +values: + 2024-01-01: 5 + +metadata: + unit: currency-USD + period: week + label: New Hampshire CCAP step 2 weekly cost share amount + reference: + - title: He-C 6910.18, Table 6910.19 (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.18 + - title: New Hampshire CCDF State Plan 2025-2027, Section 3.2.1 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=42 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/cost_share/step_2_fpg_rate.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/cost_share/step_2_fpg_rate.yaml new file mode 100644 index 00000000000..d34ea812152 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/cost_share/step_2_fpg_rate.yaml @@ -0,0 +1,13 @@ +description: New Hampshire sets this share of the federal poverty guideline as the upper threshold for the flat weekly cost share under the Child Care Scholarship Program. +values: + 2024-01-01: 1.38 + +metadata: + unit: /1 + period: year + label: New Hampshire CCAP step 2 FPG rate threshold + reference: + - title: He-C 6910.18, Table 6910.19 (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.18 + - title: New Hampshire CCDF State Plan 2025-2027, Section 3.2.1 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=42 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/cost_share/step_3_rate.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/cost_share/step_3_rate.yaml new file mode 100644 index 00000000000..2f3a18e8dc1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/cost_share/step_3_rate.yaml @@ -0,0 +1,13 @@ +description: New Hampshire sets this share of family income as the cost share for families above 138% of the federal poverty guideline under the Child Care Scholarship Program. +values: + 2024-01-01: 0.07 + +metadata: + unit: /1 + period: year + label: New Hampshire CCAP step 3 income cost share rate + reference: + - title: He-C 6910.18, Table 6910.19 (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.18 + - title: New Hampshire CCDF State Plan 2025-2027, Section 3.2.1 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=42 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/eligibility/child_age_limit.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/eligibility/child_age_limit.yaml new file mode 100644 index 00000000000..85398f88a4e --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/eligibility/child_age_limit.yaml @@ -0,0 +1,13 @@ +description: New Hampshire limits the Child Care Scholarship Program to children younger than this age. +values: + 2024-01-01: 13 + +metadata: + unit: year + period: year + label: New Hampshire CCAP child age limit + reference: + - title: He-C 6910.07(b)(3) (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.07 + - title: New Hampshire CCDF State Plan 2025-2027, Section 2.3.1 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=26 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/eligibility/disabled_child_age_limit.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/eligibility/disabled_child_age_limit.yaml new file mode 100644 index 00000000000..391fff72795 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/eligibility/disabled_child_age_limit.yaml @@ -0,0 +1,13 @@ +description: New Hampshire limits the Child Care Scholarship Program to disabled children younger than this age. +values: + 2024-01-01: 18 + +metadata: + unit: year + period: year + label: New Hampshire CCAP disabled child age limit + reference: + - title: He-C 6910.07(e) (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.07 + - title: New Hampshire CCDF State Plan 2025-2027, Section 2.3.1 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=26 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/eligibility/qualified_immigration_statuses.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/eligibility/qualified_immigration_statuses.yaml new file mode 100644 index 00000000000..6f29d0abdc1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/eligibility/qualified_immigration_statuses.yaml @@ -0,0 +1,17 @@ +description: New Hampshire limits the Child Care Scholarship Program to children of these immigration statuses. +values: + 2024-01-01: + - CITIZEN + - LEGAL_PERMANENT_RESIDENT + - REFUGEE + - ASYLEE + +metadata: + unit: list + period: year + label: New Hampshire CCAP qualified immigration statuses + reference: + - title: He-C 6910.09(c)(2) (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.09 + - title: New Hampshire CCDF State Plan 2025-2027, Section 2.3.3 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=27 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/income/countable_income/sources.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/income/countable_income/sources.yaml new file mode 100644 index 00000000000..18266ee965b --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/income/countable_income/sources.yaml @@ -0,0 +1,31 @@ +description: New Hampshire uses these income sources as countable income under the Child Care Scholarship Program. +values: + 2024-01-01: + # Earned income + - employment_income + - self_employment_income + - farm_income + # Unearned income + - social_security + - pension_income + - retirement_distributions + - unemployment_compensation + - workers_compensation + - child_support_received + - alimony_income + - interest_income + - dividend_income + - rental_income + - veterans_benefits + - disability_benefits + - capital_gains + +metadata: + unit: list + period: year + label: New Hampshire CCAP countable income sources + reference: + - title: He-C 6910.06(b)-(c),(e) (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.06 + - title: New Hampshire CCDF State Plan 2025-2027, Section 2.2.4 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=25 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/income/income_limit_smi_rate.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/income/income_limit_smi_rate.yaml new file mode 100644 index 00000000000..cf8aa7cb5f1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/income/income_limit_smi_rate.yaml @@ -0,0 +1,13 @@ +description: New Hampshire limits gross income to this share of the state median income under the Child Care Scholarship Program. +values: + 2024-01-01: 0.85 + +metadata: + unit: /1 + period: year + label: New Hampshire CCAP income limit SMI rate + reference: + - title: He-C 6910.06(b) (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.06 + - title: New Hampshire CCDF State Plan 2025-2027, Section 2.2.4 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=24 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/disability_supplement/amount.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/disability_supplement/amount.yaml new file mode 100644 index 00000000000..ca477997773 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/disability_supplement/amount.yaml @@ -0,0 +1,20 @@ +description: New Hampshire provides this weekly supplement for children with disabilities or significant special needs under the Child Care Scholarship Program. + +metadata: + period: week + unit: currency-USD + label: New Hampshire CCAP disability supplement weekly amount + breakdown: + - nh_ccap_service_level + reference: + - title: He-C 6910.17(g) (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.17 + - title: New Hampshire CCDF State Plan 2025-2027, Section 4.3.3 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=55 + +FULL_TIME: + 2024-01-01: 100 +HALF_TIME: + 2024-01-01: 75 +PART_TIME: + 2024-01-01: 50 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/exempt_center_rate.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/exempt_center_rate.yaml new file mode 100644 index 00000000000..eae4ad9b2c7 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/exempt_center_rate.yaml @@ -0,0 +1,13 @@ +description: New Hampshire sets this share of the licensed child care center rate for license-exempt centers under the Child Care Scholarship Program. +values: + 2024-01-01: 0.5 + +metadata: + unit: /1 + period: year + label: New Hampshire CCAP license-exempt center rate factor + reference: + - title: He-C 6910.17(d) (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.17 + - title: New Hampshire CCDF State Plan 2025-2027, Section 4.3.2 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=52 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/exempt_in_home_rate.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/exempt_in_home_rate.yaml new file mode 100644 index 00000000000..182aebe00ac --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/exempt_in_home_rate.yaml @@ -0,0 +1,13 @@ +description: New Hampshire sets this share of the licensed family child care home rate for license-exempt in-home providers under the Child Care Scholarship Program. +values: + 2024-01-01: 0.7 + +metadata: + unit: /1 + period: year + label: New Hampshire CCAP license-exempt in-home rate factor + reference: + - title: He-C 6910.17(c) (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.17 + - title: New Hampshire CCDF State Plan 2025-2027, Section 4.3.2 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=52 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/rates/licensed_center.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/rates/licensed_center.yaml new file mode 100644 index 00000000000..5eaf0dc2e9e --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/rates/licensed_center.yaml @@ -0,0 +1,46 @@ +description: New Hampshire provides these weekly standard rates for licensed child care centers under the Child Care Scholarship Program. +# NOTE: Actual effective date is 2024-08-26 per MRS; using 2024-01-01 for microsimulation compatibility. + +metadata: + period: week + unit: currency-USD + label: New Hampshire CCAP licensed center weekly rates + breakdown: + - nh_ccap_child_age_category + - nh_ccap_service_level + reference: + - title: He-C 6910.17(a) (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.17 + - title: CCDF Provider Payment Rates by State (January 2025) - Tables 2-4 + href: https://acf.gov/sites/default/files/documents/occ/CCDF-Provider-Payment-Rates-by-State.pdf#page=6 + - title: New Hampshire CCDF State Plan 2025-2027, Section 4.3.2, Table 1 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=53 + +INFANT: + FULL_TIME: + 2024-01-01: 344.42 + HALF_TIME: + 2024-01-01: 172.21 + PART_TIME: + 2024-01-01: 86.11 +TODDLER: + FULL_TIME: + 2024-01-01: 317.36 + HALF_TIME: + 2024-01-01: 158.68 + PART_TIME: + 2024-01-01: 79.34 +PRESCHOOL: + FULL_TIME: + 2024-01-01: 280 + HALF_TIME: + 2024-01-01: 140 + PART_TIME: + 2024-01-01: 70 +SCHOOL_AGE: + FULL_TIME: + 2024-01-01: 236.25 + HALF_TIME: + 2024-01-01: 118.13 + PART_TIME: + 2024-01-01: 59.06 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/rates/licensed_family.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/rates/licensed_family.yaml new file mode 100644 index 00000000000..852af1c7597 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/payment/rates/licensed_family.yaml @@ -0,0 +1,46 @@ +description: New Hampshire provides these weekly standard rates for licensed family child care homes under the Child Care Scholarship Program. +# NOTE: Actual effective date is 2024-08-26 per MRS; using 2024-01-01 for microsimulation compatibility. + +metadata: + period: week + unit: currency-USD + label: New Hampshire CCAP licensed family home weekly rates + breakdown: + - nh_ccap_child_age_category + - nh_ccap_service_level + reference: + - title: He-C 6910.17(b) (eff. 4-30-24, #13951) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.17 + - title: CCDF Provider Payment Rates by State (January 2025) - Tables 2-4 + href: https://acf.gov/sites/default/files/documents/occ/CCDF-Provider-Payment-Rates-by-State.pdf#page=6 + - title: New Hampshire CCDF State Plan 2025-2027, Section 4.3.2, Table 1 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=53 + +INFANT: + FULL_TIME: + 2024-01-01: 250 + HALF_TIME: + 2024-01-01: 125 + PART_TIME: + 2024-01-01: 63 +TODDLER: + FULL_TIME: + 2024-01-01: 250 + HALF_TIME: + 2024-01-01: 125 + PART_TIME: + 2024-01-01: 63 +PRESCHOOL: + FULL_TIME: + 2024-01-01: 250 + HALF_TIME: + 2024-01-01: 125 + PART_TIME: + 2024-01-01: 63 +SCHOOL_AGE: + FULL_TIME: + 2024-01-01: 200 + HALF_TIME: + 2024-01-01: 100 + PART_TIME: + 2024-01-01: 50 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/service_level/full_time_hours.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/service_level/full_time_hours.yaml new file mode 100644 index 00000000000..e8a668785e1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/service_level/full_time_hours.yaml @@ -0,0 +1,13 @@ +description: New Hampshire sets this threshold as the minimum weekly hours for full-time child care under the Child Care Scholarship Program. +values: + 2024-01-01: 30 + +metadata: + unit: /1 + period: year + label: New Hampshire CCAP full-time hours threshold + reference: + - title: He-C 6910.07(o) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.07 + - title: New Hampshire CCDF State Plan 2025-2027, Section 2.4.3 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=29 diff --git a/policyengine_us/parameters/gov/states/nh/dhhs/ccap/service_level/half_time_hours.yaml b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/service_level/half_time_hours.yaml new file mode 100644 index 00000000000..5eb1eee4812 --- /dev/null +++ b/policyengine_us/parameters/gov/states/nh/dhhs/ccap/service_level/half_time_hours.yaml @@ -0,0 +1,13 @@ +description: New Hampshire sets this threshold as the minimum weekly hours for half-time child care under the Child Care Scholarship Program. +values: + 2024-01-01: 15 + +metadata: + unit: /1 + period: year + label: New Hampshire CCAP half-time hours threshold + reference: + - title: He-C 6910.07(o) + href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.07 + - title: New Hampshire CCDF State Plan 2025-2027, Section 2.4.3 + href: https://www.dhhs.nh.gov/sites/g/files/ehbemt476/files/documents2/ccdf-state-plan-2025-2027.pdf#page=29 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/integration.yaml new file mode 100644 index 00000000000..5343beefdd0 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/integration.yaml @@ -0,0 +1,370 @@ +# Integration tests for NH Child Care Scholarship Program (CCAP) +# He-C 6910, NH DHHS +# +# 2025 reference values: +# FPG family of 3: 15,650 + 5,500*2 = $26,650/yr = $2,220.83/mo +# FPG family of 2: 15,650 + 5,500 = $21,150/yr = $1,762.50/mo +# FPG family of 4: 15,650 + 5,500*3 = $32,150/yr = $2,679.17/mo +# NH SMI (eff 2024-10-01): $146,582/yr +# SMI family of 3: 146,582 * 0.84 = $123,128.88/yr +# 85% SMI family of 3: $104,659.55/yr = $8,721.63/mo +# SMI family of 2: 146,582 * 0.68 = $99,675.76/yr +# 85% SMI family of 2: $84,724.40/yr = $7,060.37/mo +# 100% FPG monthly (fam 3): $2,220.83 +# 138% FPG monthly (fam 3): $3,064.75 + +- name: Case 1, basic eligible family, income below 100% FPG, $0 cost share. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + employment_income: 20_400 + # $20,400/yr = $1,700/mo < $1,762.50 (100% FPG for 2) + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + nh_ccap_provider_type: LICENSED_CENTER + pre_subsidy_childcare_expenses: 18_720 + # $18,720/yr = $360/week + spm_units: + spm_unit: + members: [person1, person2] + + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + # Eligibility chain + nh_ccap_eligible_child: [false, true] + nh_ccap_income_eligible: true + nh_ccap_eligible: true + + # Cost share: $1,700/mo < $1,762.50 (100% FPG for 2) → Step 1 → $0/week + nh_ccap_cost_share: 0 + +- name: Case 2, income between 100-138% FPG, $5 weekly cost share. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 32 + employment_income: 24_000 + # $24,000/yr = $2,000/mo + # Family of 2: 100% FPG = $1,762.50; 138% FPG = $2,432.25 + # $2,000 > $1,762.50 and < $2,432.25 → Step 2 + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 25 + nh_ccap_provider_type: LICENSED_FAMILY + pre_subsidy_childcare_expenses: 15_600 + # $15,600/yr = $300/week + spm_units: + spm_unit: + members: [person1, person2] + + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_eligible_child: [false, true] + nh_ccap_income_eligible: true + nh_ccap_eligible: true + + # Cost share: Step 2 → $5/week + nh_ccap_cost_share: 5 + +- name: Case 3, income above 138% FPG, 7% cost share calculation. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 60_000 + # $60,000/yr = $5,000/mo > $3,064.75 (138% FPG for 3) + # Step 3: 7% * $5,000 / 4.33 = $80.77/week + person2: + age: 35 + employment_income: 0 + person3: + age: 8 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 12 + nh_ccap_provider_type: LICENSED_CENTER + pre_subsidy_childcare_expenses: 7_800 + # $7,800/yr = $150/week + spm_units: + spm_unit: + members: [person1, person2, person3] + + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + nh_ccap_eligible_child: [false, false, true] + nh_ccap_income_eligible: true + nh_ccap_eligible: true + + # Cost share: 7% * $5,000 / (52/12) = $350 / 4.3333 = $80.77/week + nh_ccap_cost_share: 80.77 + +- name: Case 4, two eligible children, cost share split equally. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 24_000 + # $24,000/yr = $2,000/mo + # Family of 4: 100% FPG = $2,679.17/mo + # $2,000 < $2,679.17 → Step 1 → $0 + person2: + age: 35 + employment_income: 0 + person3: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 35 + nh_ccap_provider_type: LICENSED_CENTER + pre_subsidy_childcare_expenses: 20_800 + # $400/week + person4: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 10 + nh_ccap_provider_type: LICENSED_FAMILY + pre_subsidy_childcare_expenses: 7_800 + # $150/week + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + + tax_units: + tax_unit: + members: [person1, person2, person3, person4] + households: + household: + members: [person1, person2, person3, person4] + state_code: NH + output: + nh_ccap_eligible_child: [false, false, true, true] + nh_ccap_income_eligible: true + nh_ccap_eligible: true + + # Cost share: $2,000/mo < $2,679.17 (100% FPG for 4) → $0/week + nh_ccap_cost_share: 0 + +- name: Case 5, TANF enrolled bypasses income test. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 25 + employment_income: 120_000 + # Well above 85% SMI for family of 2 + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + nh_ccap_provider_type: LICENSED_CENTER + pre_subsidy_childcare_expenses: 18_720 + spm_units: + spm_unit: + members: [person1, person2] + + is_tanf_enrolled: true + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + # TANF enrolled → income eligible regardless + nh_ccap_income_eligible: true + nh_ccap_eligible: true + +- name: Case 6, disabled child age 14, eligible via disability extension. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 40 + employment_income: 36_000 + person2: + age: 14 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 35 + nh_ccap_provider_type: LICENSED_CENTER + pre_subsidy_childcare_expenses: 20_800 + spm_units: + spm_unit: + members: [person1, person2] + + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + # Child is 14 but disabled → eligible via He-C 6910.07(e) + nh_ccap_eligible_child: [false, true] + nh_ccap_income_eligible: true + nh_ccap_eligible: true + +- name: Case 7, positive benefit end-to-end, preschool licensed center, income below 100% FPG. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + employment_income: 20_400 + # $20,400/yr = $1,700/mo < $1,762.50 (100% FPG for 2) + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + nh_ccap_provider_type: LICENSED_CENTER + pre_subsidy_childcare_expenses: 18_720 + # $18,720/yr = $360/week + spm_units: + spm_unit: + members: [person1, person2] + + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_eligible_child: [false, true] + nh_ccap_income_eligible: true + nh_ccap_eligible: true + nh_ccap_cost_share: 0 + # Preschool, full-time, licensed center: $280/week + # min($360/wk charge, $280 rate) = $280 + # Cost share: $0 → per-child: $0 + # Weekly payment: $280 - $0 = $280 + # Monthly: $280 * (52/12) = $1,213.33 + nh_ccap: 1_213.33 + +- name: Case 8, disabled child, disability supplement flows through to benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 24_000 + # $24,000/yr = $2,000/mo + # Family of 3: 100% FPG = $2,220.83 + # $2,000 < $2,220.83 → Step 1 → $0 cost share + person2: + age: 35 + employment_income: 0 + person3: + age: 5 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + nh_ccap_provider_type: LICENSED_CENTER + pre_subsidy_childcare_expenses: 20_800 + # $20,800/yr = $400/week + spm_units: + spm_unit: + members: [person1, person2, person3] + + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + nh_ccap_eligible_child: [false, false, true] + nh_ccap_income_eligible: true + nh_ccap_eligible: true + nh_ccap_cost_share: 0 + # Preschool, full-time, licensed center: $280/week base rate + # Disability supplement full-time: $100/week + # Total rate: $280 + $100 = $380 + # min($400/wk charge, $380 total rate) = $380 + # Cost share: $0 → per-child: $0 + # Weekly payment: $380 - $0 = $380 + # Monthly: $380 * (52/12) = $1,646.67 + nh_ccap: 1_646.67 + +- name: Case 9, income above 85% SMI, not TANF enrolled, ineligible (original Case 7). + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 108_000 + # $108,000/yr = $9,000/mo + # Family of 3: 85% SMI = $8,721.63/mo + # $9,000 > $8,721.63 → ineligible + person2: + age: 35 + employment_income: 0 + person3: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + nh_ccap_provider_type: LICENSED_CENTER + pre_subsidy_childcare_expenses: 18_720 + spm_units: + spm_unit: + members: [person1, person2, person3] + + tax_units: + tax_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + nh_ccap_eligible_child: [false, false, true] + nh_ccap_income_eligible: false + nh_ccap_eligible: false + nh_ccap: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap.yaml new file mode 100644 index 00000000000..f5f20d5ad61 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap.yaml @@ -0,0 +1,336 @@ +# Tests for nh_ccap (SPMUnit, MONTH) +# Final benefit = sum over eligible children of: +# max(0, min(provider charge, payment rate + disability supplement) - per-child cost share) +# * weeks_per_month +# He-C 6910.17(e), He-C 6910.18(f) +# +# Uses direct input overrides for intermediate variables +# to isolate benefit calculation logic. +# weeks_per_month = 52/12 = 4.3333... + +- name: Case 1, eligible, rate lower than charge, benefit is rate minus cost share. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 5 + nh_ccap_eligible_child: true + nh_ccap_payment_rate: 300 + pre_subsidy_childcare_expenses: 18_720 + # $18,720/yr = $360/week (> $300 rate) + spm_units: + spm_unit: + members: [person1, person2] + nh_ccap_eligible: true + nh_ccap_cost_share: 10 + households: + household: + members: [person1, person2] + state_code: NH + output: + # min($360/wk charge, $300 rate) = $300 + # 1 eligible child: per-child cost share = $10/1 = $10 + # Weekly: $300 - $10 = $290 + # Monthly: $290 * (52/12) = $1,256.67 + nh_ccap: 1_256.67 + +- name: Case 2, eligible, charge lower than rate, benefit is charge minus cost share. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 5 + nh_ccap_eligible_child: true + nh_ccap_payment_rate: 300 + pre_subsidy_childcare_expenses: 10_400 + # $10,400/yr = $200/week (< $300 rate) + spm_units: + spm_unit: + members: [person1, person2] + nh_ccap_eligible: true + nh_ccap_cost_share: 5 + households: + household: + members: [person1, person2] + state_code: NH + output: + # min($200/wk charge, $300 rate) = $200 + # 1 eligible child: per-child cost share = $5/1 = $5 + # Weekly: $200 - $5 = $195 + # Monthly: $195 * (52/12) = $845 + nh_ccap: 845 + +- name: Case 3, ineligible, zero benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 5 + nh_ccap_eligible_child: true + nh_ccap_payment_rate: 300 + pre_subsidy_childcare_expenses: 18_720 + spm_units: + spm_unit: + members: [person1, person2] + nh_ccap_eligible: false + nh_ccap_cost_share: 10 + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap: 0 + +- name: Case 4, two eligible children, cost share split equally. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 5 + nh_ccap_eligible_child: true + nh_ccap_payment_rate: 300 + pre_subsidy_childcare_expenses: 18_720 + # $360/week charge + person3: + age: 3 + nh_ccap_eligible_child: true + nh_ccap_payment_rate: 350 + pre_subsidy_childcare_expenses: 20_280 + # $390/week charge + spm_units: + spm_unit: + members: [person1, person2, person3] + nh_ccap_eligible: true + nh_ccap_cost_share: 20 + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + # Person2: min($360, $300) - $20/2 = $300 - $10 = $290/week + # Person3: min($390, $350) - $20/2 = $350 - $10 = $340/week + # Total weekly: $290 + $340 = $630 + # Monthly: $630 * (52/12) = $2,730 + nh_ccap: 2_730 + +- name: Case 5, cost share exceeds rate, benefit floors at zero. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 5 + nh_ccap_eligible_child: true + nh_ccap_payment_rate: 50 + pre_subsidy_childcare_expenses: 2_600 + # $50/week charge + spm_units: + spm_unit: + members: [person1, person2] + nh_ccap_eligible: true + nh_ccap_cost_share: 70 + households: + household: + members: [person1, person2] + state_code: NH + output: + # min($50, $50) - $70/1 = $50 - $70 = -$20 → $0 + nh_ccap: 0 + +- name: Case 6, disabled child, disability supplement adds to rate in benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_disabled: true + nh_ccap_eligible_child: true + nh_ccap_payment_rate: 280 + nh_ccap_disability_supplement: 100 + pre_subsidy_childcare_expenses: 20_800 + # $20,800/yr = $400/week (> $280 + $100 = $380 total rate) + spm_units: + spm_unit: + members: [person1, person2] + nh_ccap_eligible: true + nh_ccap_cost_share: 10 + households: + household: + members: [person1, person2] + state_code: NH + output: + # total_weekly_rate = $280 + $100 = $380 + # min($400/wk charge, $380 total rate) = $380 + # 1 eligible child: per-child cost share = $10/1 = $10 + # Weekly: $380 - $10 = $370 + # Monthly: $370 * (52/12) = $1,603.33 + nh_ccap: 1_603.33 + +# --- Edge Cases --- + +- name: Case 7, zero childcare expenses, zero benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 5 + nh_ccap_eligible_child: true + nh_ccap_payment_rate: 300 + pre_subsidy_childcare_expenses: 0 + spm_units: + spm_unit: + members: [person1, person2] + nh_ccap_eligible: true + nh_ccap_cost_share: 0 + households: + household: + members: [person1, person2] + state_code: NH + output: + # weekly_expense = $0/52 = $0 + # min($0, $300) = $0; $0 - $0 = $0/week → $0/month + nh_ccap: 0 + +- name: Case 8, cost share exactly equals capped rate, zero benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 5 + nh_ccap_eligible_child: true + nh_ccap_payment_rate: 200 + pre_subsidy_childcare_expenses: 15_600 + # $15,600/yr = $300/week (> $200 rate) + spm_units: + spm_unit: + members: [person1, person2] + nh_ccap_eligible: true + nh_ccap_cost_share: 200 + households: + household: + members: [person1, person2] + state_code: NH + output: + # min($300/wk, $200) = $200; $200 - $200/1 = $0 → $0/month + nh_ccap: 0 + +- name: Case 9, three eligible children, cost share split three ways. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + person2: + age: 3 + nh_ccap_eligible_child: true + nh_ccap_payment_rate: 280 + pre_subsidy_childcare_expenses: 18_200 + # $18,200/yr = $350/week + person3: + age: 5 + nh_ccap_eligible_child: true + nh_ccap_payment_rate: 250 + pre_subsidy_childcare_expenses: 15_600 + # $15,600/yr = $300/week + person4: + age: 8 + nh_ccap_eligible_child: true + nh_ccap_payment_rate: 200 + pre_subsidy_childcare_expenses: 13_000 + # $13,000/yr = $250/week + spm_units: + spm_unit: + members: [person1, person2, person3, person4] + nh_ccap_eligible: true + nh_ccap_cost_share: 30 + households: + household: + members: [person1, person2, person3, person4] + state_code: NH + output: + # Per-child cost share: $30/3 = $10/week each + # Person2: min($350, $280) - $10 = $280 - $10 = $270/week + # Person3: min($300, $250) - $10 = $250 - $10 = $240/week + # Person4: min($250, $200) - $10 = $200 - $10 = $190/week + # Total weekly: $270 + $240 + $190 = $700/week + # Monthly: $700 * (52/12) = $700 * 4.3333 = $3,033.33 + nh_ccap: 3_033.33 + +- name: Case 10, no eligible children in spm unit, zero benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 14 + nh_ccap_eligible_child: false + spm_units: + spm_unit: + members: [person1, person2] + nh_ccap_eligible: true + nh_ccap_cost_share: 0 + households: + household: + members: [person1, person2] + state_code: NH + output: + # No eligible children → no per-child payments → $0 + nh_ccap: 0 + +- name: Case 11, negative countable income does not inflate benefit. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + self_employment_income: -60_000_000 + person2: + age: 4 + nh_ccap_eligible_child: true + pre_subsidy_childcare_expenses: 15_000 + nh_ccap_payment_rate: 300 + nh_ccap_disability_supplement: 0 + spm_units: + spm_unit: + members: [person1, person2] + nh_ccap_eligible: true + nh_ccap_cost_share: 0 + households: + household: + members: [person1, person2] + state_code: NH + output: + # Negative income → cost share = 0 + # Weekly expense = 15,000 / 52 = $288.46 + # Capped rate = min(288.46, 300) = $288.46 + # Per-child payment = max(288.46 - 0, 0) = $288.46 + # Monthly = 288.46 * 52/12 = $1,250 + # Benefit capped at actual expenses, NOT inflated by negative income + nh_ccap: 1_250 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_activity_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_activity_eligible.yaml new file mode 100644 index 00000000000..205802c49ba --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_activity_eligible.yaml @@ -0,0 +1,166 @@ +- name: Case 1, single employed parent. + period: 2025-01 + input: + people: + person1: + is_tax_unit_head_or_spouse: true + weekly_hours_worked: 40 + is_full_time_student: false + is_disabled: false + person2: + age: 4 + is_tax_unit_head_or_spouse: false + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_activity_eligible: true + +- name: Case 2, single student parent. + period: 2025-01 + input: + people: + person1: + is_tax_unit_head_or_spouse: true + weekly_hours_worked: 0 + is_full_time_student: true + is_disabled: false + person2: + age: 4 + is_tax_unit_head_or_spouse: false + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_activity_eligible: true + +- name: Case 3, single disabled parent. + period: 2025-01 + input: + people: + person1: + is_tax_unit_head_or_spouse: true + weekly_hours_worked: 0 + is_full_time_student: false + is_disabled: true + person2: + age: 4 + is_tax_unit_head_or_spouse: false + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_activity_eligible: true + +- name: Case 4, single unemployed non-student non-disabled parent. + period: 2025-01 + input: + people: + person1: + is_tax_unit_head_or_spouse: true + weekly_hours_worked: 0 + is_full_time_student: false + is_disabled: false + person2: + age: 4 + is_tax_unit_head_or_spouse: false + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_activity_eligible: false + +- name: Case 5, two employed parents. + period: 2025-01 + input: + people: + person1: + is_tax_unit_head_or_spouse: true + weekly_hours_worked: 40 + is_full_time_student: false + is_disabled: false + person2: + is_tax_unit_head_or_spouse: true + weekly_hours_worked: 20 + is_full_time_student: false + is_disabled: false + person3: + age: 4 + is_tax_unit_head_or_spouse: false + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + nh_ccap_activity_eligible: true + +- name: Case 6, two parents one employed one not qualifying. + period: 2025-01 + input: + people: + person1: + is_tax_unit_head_or_spouse: true + weekly_hours_worked: 40 + is_full_time_student: false + is_disabled: false + person2: + is_tax_unit_head_or_spouse: true + weekly_hours_worked: 0 + is_full_time_student: false + is_disabled: false + person3: + age: 4 + is_tax_unit_head_or_spouse: false + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + nh_ccap_activity_eligible: false + +- name: Case 7, child does not affect activity test. + period: 2025-01 + input: + people: + person1: + is_tax_unit_head_or_spouse: true + weekly_hours_worked: 20 + is_full_time_student: false + is_disabled: false + person2: + age: 10 + is_tax_unit_head_or_spouse: false + weekly_hours_worked: 0 + is_full_time_student: false + is_disabled: false + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_activity_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_child_age_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_child_age_category.yaml new file mode 100644 index 00000000000..9806ed237c3 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_child_age_category.yaml @@ -0,0 +1,153 @@ +# Tests for nh_ccap_child_age_category (Person, MONTH) +# Age categories based on age in months. +# He-C 6910.17(i), He-C 6912.16(j) +# INFANT: 0-17 months +# TODDLER: 18-35 months +# PRESCHOOL: 36-78 months +# SCHOOL_AGE: 79-155 months +# +# Note: monthly_age returns age in years; formula multiplies by 12. +# age=0 → 0 months → INFANT +# age=1 → 12 months → INFANT (< 18) +# age=2 → 24 months → TODDLER (>= 18 and < 36) +# age=3 → 36 months → PRESCHOOL (>= 36 and < 79) +# age=5 → 60 months → PRESCHOOL +# age=7 → 84 months → SCHOOL_AGE (>= 79) +# age=12 → 144 months → SCHOOL_AGE (< 156) + +- name: Case 1, age 0, infant. + period: 2025-01 + input: + people: + person1: + age: 0 + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_child_age_category: INFANT + +- name: Case 2, age 1, infant. + period: 2025-01 + input: + people: + person1: + age: 1 + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_child_age_category: INFANT + +- name: Case 3, age 2, toddler. + period: 2025-01 + input: + people: + person1: + age: 2 + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_child_age_category: TODDLER + +- name: Case 4, age 3, preschool. + period: 2025-01 + input: + people: + person1: + age: 3 + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_child_age_category: PRESCHOOL + +- name: Case 5, age 5, preschool. + period: 2025-01 + input: + people: + person1: + age: 5 + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_child_age_category: PRESCHOOL + +- name: Case 6, age 6, preschool. + period: 2025-01 + input: + people: + person1: + age: 6 + households: + household: + members: [person1] + state_code: NH + output: + # age=6 → 72 months → PRESCHOOL (< 79) + nh_ccap_child_age_category: PRESCHOOL + +- name: Case 7, age 7, school age. + period: 2025-01 + input: + people: + person1: + age: 7 + households: + household: + members: [person1] + state_code: NH + output: + # age=7 → 84 months → SCHOOL_AGE (>= 79) + nh_ccap_child_age_category: SCHOOL_AGE + +- name: Case 8, age 12, school age. + period: 2025-01 + input: + people: + person1: + age: 12 + households: + household: + members: [person1] + state_code: NH + output: + # age=12 → 144 months → SCHOOL_AGE (< 156) + nh_ccap_child_age_category: SCHOOL_AGE + +# --- Edge Cases: Maximum and minimum ages --- + +- name: Case 9, age 13, school age (beyond normal eligibility but tests category). + period: 2025-01 + input: + people: + person1: + age: 13 + households: + household: + members: [person1] + state_code: NH + output: + # age=13 → 156 months → SCHOOL_AGE (>= 79) + nh_ccap_child_age_category: SCHOOL_AGE + +- name: Case 10, age 17, school age (disabled child upper bound). + period: 2025-01 + input: + people: + person1: + age: 17 + households: + household: + members: [person1] + state_code: NH + output: + # age=17 → 204 months → SCHOOL_AGE + nh_ccap_child_age_category: SCHOOL_AGE diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_cost_share.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_cost_share.yaml new file mode 100644 index 00000000000..5e2c728ad9d --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_cost_share.yaml @@ -0,0 +1,242 @@ +# Tests for nh_ccap_cost_share (SPMUnit, MONTH) +# Weekly family cost share based on income relative to FPG. +# He-C 6910.18, Table 6910.19 +# +# 2025 FPG family of 3: 15,650 + 5,500*2 = $26,650/year = $2,220.83/month +# Step 1: <= 100% FPG ($2,220.83/mo) → $0/week +# Step 2: > 100% to <= 138% FPG ($3,064.75/mo) → $5/week +# Step 3: > 138% FPG → 7% * monthly income / (52/12) +# +# 2025 FPG family of 2: 15,650 + 5,500 = $21,150/year = $1,762.50/month +# 2025 FPG family of 1: $15,650/year = $1,304.17/month + +- name: Case 1, income at 80% FPG, step 1, $0 cost share. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 21_324 + # $21,324/yr = $1,777/mo < $2,220.83 (100% FPG for 3) + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + nh_ccap_cost_share: 0 + +- name: Case 2, income at 120% FPG, step 2, $5 cost share. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 31_980 + # $31,980/yr = $2,665/mo > $2,220.83 (100% FPG) + # and < $3,064.75 (138% FPG) → Step 2 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + nh_ccap_cost_share: 5 + +- name: Case 3, income at 200% FPG, step 3, 7% cost share. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 53_304 + # $53,304/yr = $4,442/mo > $3,064.75 (138% FPG) + # Step 3: 7% * $4,442 / (52/12) = $71.77/week + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + # $4,442 * 0.07 / (52/12) = $310.94 / 4.3333 = $71.76 + nh_ccap_cost_share: 71.76 + +- name: Case 4, income exactly at 100% FPG boundary, step 1. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 26_650 + # $26,650/yr = $2,220.83/mo = exactly 100% FPG + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + nh_ccap_cost_share: 0 + +- name: Case 5, income just below 138% FPG boundary, step 2. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 36_600 + # 138% FPG = $26,650 * 1.38 = $36,777/yr = $3,064.75/mo + # $36,600/yr = $3,050/mo < $3,064.75 → Step 2 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + nh_ccap_cost_share: 5 + +# --- Edge Cases --- + +- name: Case 6, income $1 above 100% FPG, transitions from step 1 to step 2. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 21_163 + # 2025 FPG family of 2: $21,150/yr = $1,762.50/mo + # $21,163/yr = $1,763.58/mo > $1,762.50 (100% FPG) → Step 2 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_cost_share: 5 + +- name: Case 7, income $1 above 138% FPG, transitions from step 2 to step 3. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 29_200 + # 2025 FPG family of 2: $21,150 + # 138% FPG = $29,187/yr = $2,432.25/mo + # $29,200/yr = $2,433.33/mo > $2,432.25 → Step 3 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + # $2,433.33 * 0.07 = $170.33 + # $170.33 / (52/12) = $170.33 / 4.3333 = $39.31 + nh_ccap_cost_share: 39.31 + +- name: Case 8, zero income, step 1, $0 cost share. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 0 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + # $0 <= 100% FPG → Step 1 → $0 + nh_ccap_cost_share: 0 + +- name: Case 9, single person household, income at 100% FPG boundary. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 5 + employment_income: 15_650 + # 2025 FPG family of 1: $15,650/yr = $1,304.17/mo + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: NH + output: + # $1,304.17 <= $1,304.17 (100% FPG for 1) → Step 1 → $0 + nh_ccap_cost_share: 0 + +- name: Case 10, negative self-employment income, step 1, $0 cost share. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + self_employment_income: -60_000_000 + # Large negative → countable income negative + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + # Negative income <= 100% FPG → Step 1 → $0 + nh_ccap_cost_share: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_disability_supplement.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_disability_supplement.yaml new file mode 100644 index 00000000000..d8f980c8186 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_disability_supplement.yaml @@ -0,0 +1,68 @@ +# Tests for nh_ccap_disability_supplement (Person, MONTH) +# Weekly disability supplement by service level. +# He-C 6910.17(g) +# Full-time: $100/week, Half-time: $75/week, Part-time: $50/week + +- name: Case 1, disabled child, full-time, $100 supplement. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + is_disabled: true + nh_ccap_eligible_child: true + nh_ccap_service_level: FULL_TIME + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_disability_supplement: 100 + +- name: Case 2, disabled child, half-time, $75 supplement. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + is_disabled: true + nh_ccap_eligible_child: true + nh_ccap_service_level: HALF_TIME + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_disability_supplement: 75 + +- name: Case 3, disabled child, part-time, $50 supplement. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + is_disabled: true + nh_ccap_eligible_child: true + nh_ccap_service_level: PART_TIME + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_disability_supplement: 50 + +- name: Case 4, non-disabled child, no supplement. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + is_disabled: false + nh_ccap_eligible_child: true + nh_ccap_service_level: FULL_TIME + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_disability_supplement: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_eligible.yaml new file mode 100644 index 00000000000..7015a45ea1c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_eligible.yaml @@ -0,0 +1,258 @@ +# Tests for nh_ccap_eligible (SPMUnit, MONTH) +# Overall eligibility combines: has eligible child, income eligible, +# asset eligible, and activity test. +# He-C 6910.06, He-C 6910.07 + +- name: Case 1, all criteria met, eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 36_000 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_eligible: true + +- name: Case 2, no eligible child, ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 36_000 + person2: + age: 14 + is_tax_unit_dependent: true + is_disabled: false + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_eligible: false + +- name: Case 3, income too high, ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 120_000 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_eligible: false + +- name: Case 4, activity test not met, ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 36_000 + weekly_hours_worked: 0 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_eligible: false + +- name: Case 5, assets over $1M, ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 36_000 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + + spm_unit_assets: 1_100_000 + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_eligible: false + +- name: Case 6, undocumented child, ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 36_000 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: UNDOCUMENTED + spm_units: + spm_unit: + members: [person1, person2] + + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_eligible: false + +# --- Edge Cases --- + +- name: Case 7, child exactly age 13, ineligible due to age. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 36_000 + person2: + age: 13 + is_disabled: false + is_tax_unit_dependent: true + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + + households: + household: + members: [person1, person2] + state_code: NH + output: + # child_age_limit = 13, age < 13 → false → no eligible child + nh_ccap_eligible: false + +- name: Case 8, disabled child age 17, eligible via disability extension. + period: 2025-01 + input: + people: + person1: + age: 35 + employment_income: 36_000 + person2: + age: 17 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + + households: + household: + members: [person1, person2] + state_code: NH + output: + # disabled_child_age_limit = 18, age 17 < 18 → eligible child + nh_ccap_eligible: true + +- name: Case 9, disabled child age 18, ineligible due to age. + period: 2025-01 + input: + people: + person1: + age: 40 + employment_income: 36_000 + person2: + age: 18 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + + households: + household: + members: [person1, person2] + state_code: NH + output: + # disabled_child_age_limit = 18, age 18 < 18 → false + nh_ccap_eligible: false + +- name: Case 10, zero income, all criteria met, eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 0 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_eligible: true + +- name: Case 11, assets exactly at $1M limit, eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 36_000 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1, person2] + + spm_unit_assets: 1_000_000 + households: + household: + members: [person1, person2] + state_code: NH + output: + # CCDF asset limit is $1M; at exactly $1M → eligible + nh_ccap_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_eligible_child.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_eligible_child.yaml new file mode 100644 index 00000000000..cec0d5df0e2 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_eligible_child.yaml @@ -0,0 +1,184 @@ +# Tests for nh_ccap_eligible_child (Person, MONTH) +# Child must be: under 13 (or disabled under disabled age limit), +# a tax unit dependent, and immigration-status eligible. +# He-C 6910.07(b)(2)-(3), He-C 6910.07(e) + +- name: Case 1, child age 5, citizen, dependent, eligible. + period: 2025-01 + input: + people: + person1: + age: 5 + is_disabled: false + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_eligible_child: true + +- name: Case 2, child age 13, not disabled, ineligible. + period: 2025-01 + input: + people: + person1: + age: 13 + is_disabled: false + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_eligible_child: false + +- name: Case 3, child age 12, not disabled, eligible. + period: 2025-01 + input: + people: + person1: + age: 12 + is_disabled: false + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_eligible_child: true + +- name: Case 4, child age 14, disabled, eligible. + period: 2025-01 + input: + people: + person1: + age: 14 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_eligible_child: true + +- name: Case 5, child age 5, undocumented, ineligible. + period: 2025-01 + input: + people: + person1: + age: 5 + is_disabled: false + is_tax_unit_dependent: true + immigration_status: UNDOCUMENTED + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_eligible_child: false + +- name: Case 6, child age 5, not dependent, ineligible. + period: 2025-01 + input: + people: + person1: + age: 5 + is_disabled: false + is_tax_unit_dependent: false + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_eligible_child: false + +- name: Case 7, child age 5, refugee, eligible. + period: 2025-01 + input: + people: + person1: + age: 5 + is_disabled: false + is_tax_unit_dependent: true + immigration_status: REFUGEE + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_eligible_child: true + +# --- Edge Cases --- + +- name: Case 8, disabled child exactly age 17, eligible. + period: 2025-01 + input: + people: + person1: + age: 17 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: NH + output: + # disabled_child_age_limit = 18, age < 18 → true + nh_ccap_eligible_child: true + +- name: Case 9, disabled child exactly age 18, ineligible. + period: 2025-01 + input: + people: + person1: + age: 18 + is_disabled: true + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: NH + output: + # disabled_child_age_limit = 18, age < 18 → false + nh_ccap_eligible_child: false + +- name: Case 10, non-disabled child age 0, eligible. + period: 2025-01 + input: + people: + person1: + age: 0 + is_disabled: false + is_tax_unit_dependent: true + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_eligible_child: true + +- name: Case 11, adult age 30, not a dependent, ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + is_disabled: false + is_tax_unit_dependent: false + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_eligible_child: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_immigration_status_eligible_person.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_immigration_status_eligible_person.yaml new file mode 100644 index 00000000000..60e12f51a09 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_immigration_status_eligible_person.yaml @@ -0,0 +1,81 @@ +# Tests for nh_ccap_immigration_status_eligible_person (Person, MONTH) +# Child must be US citizen or qualifying non-citizen. +# He-C 6910.07(b)(2) + +- name: Case 1, citizen, eligible. + period: 2025-01 + input: + people: + person1: + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_immigration_status_eligible_person: true + +- name: Case 2, legal permanent resident, eligible. + period: 2025-01 + input: + people: + person1: + immigration_status: LEGAL_PERMANENT_RESIDENT + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_immigration_status_eligible_person: true + +- name: Case 3, refugee, eligible. + period: 2025-01 + input: + people: + person1: + immigration_status: REFUGEE + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_immigration_status_eligible_person: true + +- name: Case 4, asylee, eligible. + period: 2025-01 + input: + people: + person1: + immigration_status: ASYLEE + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_immigration_status_eligible_person: true + +- name: Case 5, undocumented, ineligible. + period: 2025-01 + input: + people: + person1: + immigration_status: UNDOCUMENTED + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_immigration_status_eligible_person: false + +- name: Case 6, DACA, ineligible. + period: 2025-01 + input: + people: + person1: + immigration_status: DACA + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_immigration_status_eligible_person: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_income_eligible.yaml new file mode 100644 index 00000000000..2fdd039ace0 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_income_eligible.yaml @@ -0,0 +1,228 @@ +# Tests for nh_ccap_income_eligible (SPMUnit, MONTH) +# Income must be <= 85% SMI, OR family is TANF-enrolled. +# He-C 6910.06(a)(1), He-C 6910.06(b) +# +# 2025 NH SMI (eff 2024-10-01): $146,582 +# Family of 3 adjustment: 0.52 + 0.16*2 = 0.84 +# SMI for family of 3: 146,582 * 0.84 = $123,128.88/year +# 85% SMI = $104,659.55/year = $8,721.63/month +# Family of 2 adjustment: 0.52 + 0.16 = 0.68 +# SMI for family of 2: 146,582 * 0.68 = $99,675.76/year +# 85% SMI = $84,724.40/year = $7,060.37/month + +- name: Case 1, income well below 85% SMI, eligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 36_000 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + # $36,000/yr = $3,000/mo < $8,721.63 → eligible + nh_ccap_income_eligible: true + +- name: Case 2, income above 85% SMI, ineligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 108_000 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + # $108,000/yr = $9,000/mo > $8,721.63 (85% SMI for 3) → ineligible + nh_ccap_income_eligible: false + +- name: Case 3, income above 85% SMI but TANF enrolled, eligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 108_000 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + is_tanf_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + # TANF enrolled → income eligible regardless of income + nh_ccap_income_eligible: true + +- name: Case 4, single parent with one child, income below 85% SMI, eligible. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 25 + employment_income: 30_000 + person2: + age: 4 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + # $30,000/yr = $2,500/mo < $7,060.37 (85% SMI for 2) → eligible + nh_ccap_income_eligible: true + +- name: Case 5, self-employment income counted toward income test. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + self_employment_income: 108_000 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: NH + output: + # $108,000/yr = $9,000/mo > $8,721.63 (85% SMI for 3) → ineligible + nh_ccap_income_eligible: false + +# --- Edge Cases --- + +- name: Case 6, income just below 85% SMI threshold, eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 84_724 + # 2025 NH SMI family of 2: $146,582 * 0.68 = $99,675.76/yr + # 85% SMI = $84,724.40/yr = $7,060.37/mo + # $84,724/yr = $7,060.33/mo <= $7,060.37 → eligible + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_income_eligible: true + +- name: Case 7, income just above 85% SMI threshold, ineligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 84_725 + # $84,725/yr = $7,060.42/mo > $7,060.37 → ineligible + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_income_eligible: false + +- name: Case 8, zero income, eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 0 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_income_eligible: true + +- name: Case 9, negative self-employment income, eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + self_employment_income: -60_000_000 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: NH + output: + # Negative income <= 85% SMI → eligible + nh_ccap_income_eligible: true + +- name: Case 10, TANF enrolled with zero income, eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + employment_income: 0 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + is_tanf_enrolled: true + households: + household: + members: [person1, person2] + state_code: NH + output: + nh_ccap_income_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_payment_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_payment_rate.yaml new file mode 100644 index 00000000000..baad74b3eae --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_payment_rate.yaml @@ -0,0 +1,251 @@ +# Tests for nh_ccap_payment_rate (Person, MONTH) +# Weekly payment rate by provider type, age category, and service level. +# He-C 6910.17(a)-(d) +# +# Provider types and rate basis: +# LICENSED_CENTER: 75th percentile MRS +# LICENSED_FAMILY: 75th percentile MRS +# LICENSE_EXEMPT_IN_HOME: 70% of licensed family rate (He-C 6910.17(c)) +# LICENSE_EXEMPT_CENTER: 50% of licensed center rate (He-C 6910.17(d)) +# +# NOTE: nh_ccap_payment_rate does NOT include disability supplement. +# Disability supplement is added separately in nh_ccap.py. + +- name: Case 1, licensed center, infant, full-time. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + nh_ccap_eligible_child: true + nh_ccap_child_age_category: INFANT + nh_ccap_service_level: FULL_TIME + nh_ccap_provider_type: LICENSED_CENTER + households: + household: + members: [person1] + state_code: NH + output: + # Licensed center infant full-time: $344.42/week + nh_ccap_payment_rate: 344.42 + +- name: Case 2, licensed family, toddler, half-time. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + nh_ccap_eligible_child: true + nh_ccap_child_age_category: TODDLER + nh_ccap_service_level: HALF_TIME + nh_ccap_provider_type: LICENSED_FAMILY + households: + household: + members: [person1] + state_code: NH + output: + # Licensed family toddler half-time: $125/week + nh_ccap_payment_rate: 125 + +- name: Case 3, licensed center, school age, part-time. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + nh_ccap_eligible_child: true + nh_ccap_child_age_category: SCHOOL_AGE + nh_ccap_service_level: PART_TIME + nh_ccap_provider_type: LICENSED_CENTER + households: + household: + members: [person1] + state_code: NH + output: + # Licensed center school-age part-time: $59.06/week + nh_ccap_payment_rate: 59.06 + +- name: Case 4, license-exempt in-home, preschool, full-time. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + nh_ccap_eligible_child: true + nh_ccap_child_age_category: PRESCHOOL + nh_ccap_service_level: FULL_TIME + nh_ccap_provider_type: LICENSE_EXEMPT_IN_HOME + households: + household: + members: [person1] + state_code: NH + output: + # 70% of licensed family preschool full-time ($250) = $175 + nh_ccap_payment_rate: 175 + +- name: Case 5, license-exempt center, toddler, full-time. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + nh_ccap_eligible_child: true + nh_ccap_child_age_category: TODDLER + nh_ccap_service_level: FULL_TIME + nh_ccap_provider_type: LICENSE_EXEMPT_CENTER + households: + household: + members: [person1] + state_code: NH + output: + # 50% of licensed center toddler full-time ($317.36) = $158.68 + nh_ccap_payment_rate: 158.68 + +- name: Case 6, licensed center, infant, full-time, disabled child (rate excludes supplement). + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + nh_ccap_eligible_child: true + nh_ccap_child_age_category: INFANT + nh_ccap_service_level: FULL_TIME + nh_ccap_provider_type: LICENSED_CENTER + is_disabled: true + households: + household: + members: [person1] + state_code: NH + output: + # Base rate only; disability supplement is in nh_ccap_disability_supplement + # Licensed center infant full-time: $344.42/week + nh_ccap_payment_rate: 344.42 + +- name: Case 7, licensed family, preschool, half-time, disabled child (rate excludes supplement). + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + nh_ccap_eligible_child: true + nh_ccap_child_age_category: PRESCHOOL + nh_ccap_service_level: HALF_TIME + nh_ccap_provider_type: LICENSED_FAMILY + is_disabled: true + households: + household: + members: [person1] + state_code: NH + output: + # Base rate only; disability supplement is in nh_ccap_disability_supplement + # Licensed family preschool half-time: $125/week + nh_ccap_payment_rate: 125 + +- name: Case 8, license-exempt in-home, school age, part-time, disabled child (rate excludes supplement). + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + nh_ccap_eligible_child: true + nh_ccap_child_age_category: SCHOOL_AGE + nh_ccap_service_level: PART_TIME + nh_ccap_provider_type: LICENSE_EXEMPT_IN_HOME + is_disabled: true + households: + household: + members: [person1] + state_code: NH + output: + # 70% of licensed family school-age part-time ($50) = $35 + nh_ccap_payment_rate: 35 + +- name: Case 9, licensed family, infant, full-time. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + nh_ccap_eligible_child: true + nh_ccap_child_age_category: INFANT + nh_ccap_service_level: FULL_TIME + nh_ccap_provider_type: LICENSED_FAMILY + households: + household: + members: [person1] + state_code: NH + output: + # Licensed family infant full-time: $250/week + nh_ccap_payment_rate: 250 + +- name: Case 10, license-exempt in-home, infant, full-time. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + nh_ccap_eligible_child: true + nh_ccap_child_age_category: INFANT + nh_ccap_service_level: FULL_TIME + nh_ccap_provider_type: LICENSE_EXEMPT_IN_HOME + households: + household: + members: [person1] + state_code: NH + output: + # 70% of licensed family infant full-time ($250) = $175 + nh_ccap_payment_rate: 175 + +- name: Case 11, license-exempt center, infant, full-time. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + nh_ccap_eligible_child: true + nh_ccap_child_age_category: INFANT + nh_ccap_service_level: FULL_TIME + nh_ccap_provider_type: LICENSE_EXEMPT_CENTER + households: + household: + members: [person1] + state_code: NH + output: + # 50% of licensed center infant full-time ($344.42) = $172.21 + nh_ccap_payment_rate: 172.21 + +- name: Case 12, licensed center, school age, half-time. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + nh_ccap_eligible_child: true + nh_ccap_child_age_category: SCHOOL_AGE + nh_ccap_service_level: HALF_TIME + nh_ccap_provider_type: LICENSED_CENTER + households: + household: + members: [person1] + state_code: NH + output: + # Licensed center school-age half-time: $118.13/week + nh_ccap_payment_rate: 118.13 + +- name: Case 13, license-exempt center, school age, part-time. + period: 2025-01 + absolute_error_margin: 0.01 + input: + people: + person1: + nh_ccap_eligible_child: true + nh_ccap_child_age_category: SCHOOL_AGE + nh_ccap_service_level: PART_TIME + nh_ccap_provider_type: LICENSE_EXEMPT_CENTER + households: + household: + members: [person1] + state_code: NH + output: + # 50% of licensed center school-age part-time ($59.06) = $29.53 + nh_ccap_payment_rate: 29.53 diff --git a/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_service_level.yaml b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_service_level.yaml new file mode 100644 index 00000000000..a5fb17bdc60 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/nh/dhhs/ccap/nh_ccap_service_level.yaml @@ -0,0 +1,171 @@ +# Tests for nh_ccap_service_level (Person, MONTH) +# Service level based on childcare hours per week. +# He-C 6910.03(y), He-C 6910.07(p) +# Full-time: > 30 hours/week (He-C 6910.03(y): "greater than 30 hours per week") +# Half-time: > 15 and <= 30 hours/week (He-C 6910.03(aa)) +# Part-time: <= 15 hours/week + +- name: Case 1, 40 hours per week, full-time. + period: 2025-01 + input: + people: + person1: + childcare_hours_per_week: 40 + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_service_level: FULL_TIME + +- name: Case 2, 31 hours per week, full-time. + period: 2025-01 + input: + people: + person1: + childcare_hours_per_week: 31 + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_service_level: FULL_TIME + +- name: Case 3, 30 hours per week, half-time (boundary). + period: 2025-01 + input: + people: + person1: + childcare_hours_per_week: 30 + households: + household: + members: [person1] + state_code: NH + output: + # He-C 6910.03(y): full-time is "greater than 30 hours" → 30 is NOT full-time + nh_ccap_service_level: HALF_TIME + +- name: Case 4, 20 hours per week, half-time. + period: 2025-01 + input: + people: + person1: + childcare_hours_per_week: 20 + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_service_level: HALF_TIME + +- name: Case 5, 15 hours per week, part-time (boundary). + period: 2025-01 + input: + people: + person1: + childcare_hours_per_week: 15 + households: + household: + members: [person1] + state_code: NH + output: + # He-C 6910.03(aa): half-time is "greater than 15" → 15 is NOT half-time + nh_ccap_service_level: PART_TIME + +- name: Case 6, 10 hours per week, part-time. + period: 2025-01 + input: + people: + person1: + childcare_hours_per_week: 10 + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_service_level: PART_TIME + +- name: Case 7, 16 hours per week, half-time. + period: 2025-01 + input: + people: + person1: + childcare_hours_per_week: 16 + households: + household: + members: [person1] + state_code: NH + output: + nh_ccap_service_level: HALF_TIME + +# --- Edge Cases: Exact boundary hours --- + +- name: Case 8, exactly 15 hours per week, part-time boundary. + period: 2025-01 + input: + people: + person1: + childcare_hours_per_week: 15 + households: + household: + members: [person1] + state_code: NH + output: + # half_time_hours = 15, hours > 15 → false → default PART_TIME + nh_ccap_service_level: PART_TIME + +- name: Case 9, exactly 30 hours per week, half-time boundary. + period: 2025-01 + input: + people: + person1: + childcare_hours_per_week: 30 + households: + household: + members: [person1] + state_code: NH + output: + # full_time_hours = 30, hours > 30 → false, hours > 15 → true → HALF_TIME + nh_ccap_service_level: HALF_TIME + +- name: Case 10, zero hours per week, part-time. + period: 2025-01 + input: + people: + person1: + childcare_hours_per_week: 0 + households: + household: + members: [person1] + state_code: NH + output: + # 0 > 30 → false, 0 > 15 → false → default PART_TIME + nh_ccap_service_level: PART_TIME + +- name: Case 11, 14 hours per week, part-time. + period: 2025-01 + input: + people: + person1: + childcare_hours_per_week: 14 + households: + household: + members: [person1] + state_code: NH + output: + # 14 > 30 → false, 14 > 15 → false → default PART_TIME + nh_ccap_service_level: PART_TIME + +- name: Case 12, 29 hours per week, half-time. + period: 2025-01 + input: + people: + person1: + childcare_hours_per_week: 29 + households: + household: + members: [person1] + state_code: NH + output: + # 29 > 30 → false, 29 > 15 → true → HALF_TIME + nh_ccap_service_level: HALF_TIME diff --git a/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_activity_eligible.py b/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_activity_eligible.py new file mode 100644 index 00000000000..47f466557be --- /dev/null +++ b/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_activity_eligible.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class nh_ccap_activity_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for New Hampshire CCAP based on activity requirements" + definition_period = MONTH + defined_for = StateCode.NH + reference = "https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.07" + + def formula(spm_unit, period, parameters): + 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) + is_employed = hours_worked > 0 + is_student = person("is_full_time_student", period.this_year) + is_disabled = person("is_disabled", period.this_year) + individually_eligible = is_employed | is_student | is_disabled + return spm_unit.sum(is_head_or_spouse & ~individually_eligible) == 0 diff --git a/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_eligible.py b/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_eligible.py new file mode 100644 index 00000000000..566bc3347dc --- /dev/null +++ b/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_eligible.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class nh_ccap_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for New Hampshire Child Care Scholarship Program" + definition_period = MONTH + defined_for = StateCode.NH + reference = "https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.07" + + def formula(spm_unit, period, parameters): + has_eligible_child = add(spm_unit, period, ["nh_ccap_eligible_child"]) > 0 + income_eligible = spm_unit("nh_ccap_income_eligible", period) + asset_eligible = spm_unit("is_ccdf_asset_eligible", period.this_year) + activity_eligible = spm_unit("nh_ccap_activity_eligible", period) + return has_eligible_child & income_eligible & asset_eligible & activity_eligible diff --git a/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_eligible_child.py b/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_eligible_child.py new file mode 100644 index 00000000000..ff981efb690 --- /dev/null +++ b/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_eligible_child.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class nh_ccap_eligible_child(Variable): + value_type = bool + entity = Person + label = "Eligible child for New Hampshire Child Care Scholarship Program" + definition_period = MONTH + defined_for = StateCode.NH + reference = "https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.07" + + def formula(person, period, parameters): + p = parameters(period).gov.states.nh.dhhs.ccap.eligibility + age = person("monthly_age", period) + is_disabled = person("is_disabled", period.this_year) + age_limit = where(is_disabled, p.disabled_child_age_limit, p.child_age_limit) + age_eligible = age < age_limit + is_dependent = person("is_tax_unit_dependent", period.this_year) + immigration_eligible = person( + "nh_ccap_immigration_status_eligible_person", period + ) + return age_eligible & is_dependent & immigration_eligible diff --git a/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_immigration_status_eligible_person.py b/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_immigration_status_eligible_person.py new file mode 100644 index 00000000000..3392795325e --- /dev/null +++ b/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_immigration_status_eligible_person.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class nh_ccap_immigration_status_eligible_person(Variable): + value_type = bool + entity = Person + label = "Eligible person for New Hampshire Child Care Scholarship Program based on immigration status" + definition_period = MONTH + defined_for = StateCode.NH + reference = "https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.09" + + def formula(person, period, parameters): + p = parameters(period).gov.states.nh.dhhs.ccap + immigration_status = person("immigration_status", period) + immigration_status_str = immigration_status.decode_to_str() + return np.isin( + immigration_status_str, + p.eligibility.qualified_immigration_statuses, + ) diff --git a/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_income_eligible.py b/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_income_eligible.py new file mode 100644 index 00000000000..73fb8f6a27e --- /dev/null +++ b/policyengine_us/variables/gov/states/nh/dhhs/ccap/eligibility/nh_ccap_income_eligible.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class nh_ccap_income_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Income eligible for New Hampshire Child Care Scholarship Program" + definition_period = MONTH + defined_for = StateCode.NH + reference = "https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.06" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.nh.dhhs.ccap.income + countable_income = spm_unit("nh_ccap_countable_income", period) + # He-C 6910.06(b): gross income <= 85% SMI + smi = spm_unit("hhs_smi", period) + income_limit = smi * p.income_limit_smi_rate + income_test = countable_income <= income_limit + # He-C 6910.06(a)(1): TANF recipients automatically qualify + tanf_eligible = spm_unit("is_tanf_enrolled", period) + return income_test | tanf_eligible diff --git a/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap.py b/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap.py new file mode 100644 index 00000000000..764e9143d2f --- /dev/null +++ b/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap.py @@ -0,0 +1,42 @@ +from policyengine_us.model_api import * + + +class nh_ccap(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "New Hampshire Child Care Scholarship Program benefit amount" + definition_period = MONTH + defined_for = "nh_ccap_eligible" + reference = "https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.17" + + def formula(spm_unit, period, parameters): + person = spm_unit.members + weeks_per_month = WEEKS_IN_YEAR / MONTHS_IN_YEAR + + # Per-child weekly rate (includes disability supplement) + weekly_rate = person("nh_ccap_payment_rate", period) + disability_supplement = person("nh_ccap_disability_supplement", period) + total_weekly_rate = weekly_rate + disability_supplement + + # Per-child pre-subsidy weekly expense + annual_expense = person("pre_subsidy_childcare_expenses", period.this_year) + weekly_expense = annual_expense / WEEKS_IN_YEAR + + # He-C 6910.17(e): payment = min(charge, rate) - cost share + capped_rate = min_(weekly_expense, total_weekly_rate) + + # He-C 6910.18(f): cost share divided equally among eligible children + is_eligible_child = person("nh_ccap_eligible_child", period) + n_eligible_children = add(spm_unit, period, ["nh_ccap_eligible_child"]) + family_cost_share = spm_unit("nh_ccap_cost_share", period) + per_child_cost_share = np.zeros_like(family_cost_share) + mask = n_eligible_children > 0 + per_child_cost_share[mask] = family_cost_share[mask] / n_eligible_children[mask] + per_child_cost_share_broadcast = spm_unit.project(per_child_cost_share) + + per_child_weekly_payment = max_(capped_rate - per_child_cost_share_broadcast, 0) + per_child_monthly_payment = ( + per_child_weekly_payment * weeks_per_month * is_eligible_child + ) + return spm_unit.sum(per_child_monthly_payment) diff --git a/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_child_age_category.py b/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_child_age_category.py new file mode 100644 index 00000000000..4bb2edefceb --- /dev/null +++ b/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_child_age_category.py @@ -0,0 +1,37 @@ +from policyengine_us.model_api import * + + +class NHCCAPChildAgeCategory(Enum): + INFANT = "Infant (0-17 months)" + TODDLER = "Toddler (18-35 months)" + PRESCHOOL = "Preschool (36-78 months)" + SCHOOL_AGE = "School Age (79-155 months)" + + +class nh_ccap_child_age_category(Variable): + value_type = Enum + entity = Person + possible_values = NHCCAPChildAgeCategory + default_value = NHCCAPChildAgeCategory.INFANT + definition_period = MONTH + defined_for = StateCode.NH + label = "New Hampshire Child Care Scholarship Program child age category" + reference = "https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.17" + + def formula(person, period, parameters): + p = parameters(period).gov.states.nh.dhhs.ccap.age_category + age_months = person("age", period.this_year) * MONTHS_IN_YEAR + + return select( + [ + age_months < p.infant_max_months, + age_months < p.toddler_max_months, + age_months < p.preschool_max_months, + ], + [ + NHCCAPChildAgeCategory.INFANT, + NHCCAPChildAgeCategory.TODDLER, + NHCCAPChildAgeCategory.PRESCHOOL, + ], + default=NHCCAPChildAgeCategory.SCHOOL_AGE, + ) diff --git a/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_cost_share.py b/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_cost_share.py new file mode 100644 index 00000000000..e4fc7b2e1d7 --- /dev/null +++ b/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_cost_share.py @@ -0,0 +1,34 @@ +from policyengine_us.model_api import * + + +class nh_ccap_cost_share(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "New Hampshire Child Care Scholarship Program weekly family cost share" + definition_period = MONTH + defined_for = StateCode.NH + reference = "https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.18" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.nh.dhhs.ccap.cost_share + countable_income = spm_unit("nh_ccap_countable_income", period) + fpg = spm_unit("spm_unit_fpg", period) + weeks_per_month = WEEKS_IN_YEAR / MONTHS_IN_YEAR + + # He-C 6910.18, Table 6910.19: stepped cost share + step_1_threshold = fpg * p.step_1_fpg_rate + step_2_threshold = fpg * p.step_2_fpg_rate + + step_3_weekly = countable_income * p.step_3_rate / weeks_per_month + return select( + [ + countable_income <= step_1_threshold, + countable_income <= step_2_threshold, + ], + [ + 0, + p.step_2_amount, + ], + default=step_3_weekly, + ) diff --git a/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_countable_income.py b/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_countable_income.py new file mode 100644 index 00000000000..ee286b25658 --- /dev/null +++ b/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_countable_income.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class nh_ccap_countable_income(Variable): + value_type = float + entity = SPMUnit + label = "New Hampshire Child Care Scholarship Program countable income" + definition_period = MONTH + unit = USD + defined_for = StateCode.NH + reference = "https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.06" + + adds = "gov.states.nh.dhhs.ccap.income.countable_income.sources" diff --git a/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_provider_type.py b/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_provider_type.py new file mode 100644 index 00000000000..3e07af52642 --- /dev/null +++ b/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_provider_type.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class NHCCAPProviderType(Enum): + LICENSED_CENTER = "Licensed child care center" + LICENSED_FAMILY = "Licensed family child care home" + LICENSE_EXEMPT_IN_HOME = "License-exempt in-home provider" + LICENSE_EXEMPT_CENTER = "License-exempt child care center" + + +class nh_ccap_provider_type(Variable): + value_type = Enum + entity = Person + possible_values = NHCCAPProviderType + default_value = NHCCAPProviderType.LICENSED_CENTER + definition_period = MONTH + defined_for = StateCode.NH + label = "New Hampshire Child Care Scholarship Program provider type" + reference = "https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.17" diff --git a/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_service_level.py b/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_service_level.py new file mode 100644 index 00000000000..1ab5a35d6b3 --- /dev/null +++ b/policyengine_us/variables/gov/states/nh/dhhs/ccap/nh_ccap_service_level.py @@ -0,0 +1,34 @@ +from policyengine_us.model_api import * + + +class NHCCAPServiceLevel(Enum): + FULL_TIME = "Full-time" + HALF_TIME = "Half-time" + PART_TIME = "Part-time" + + +class nh_ccap_service_level(Variable): + value_type = Enum + entity = Person + possible_values = NHCCAPServiceLevel + default_value = NHCCAPServiceLevel.FULL_TIME + definition_period = MONTH + defined_for = StateCode.NH + label = "New Hampshire Child Care Scholarship Program service level" + reference = "https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.07" + + def formula(person, period, parameters): + p = parameters(period).gov.states.nh.dhhs.ccap.service_level + hours = person("childcare_hours_per_week", period.this_year) + + return select( + [ + hours > p.full_time_hours, + hours > p.half_time_hours, + ], + [ + NHCCAPServiceLevel.FULL_TIME, + NHCCAPServiceLevel.HALF_TIME, + ], + default=NHCCAPServiceLevel.PART_TIME, + ) diff --git a/policyengine_us/variables/gov/states/nh/dhhs/ccap/payment/nh_ccap_disability_supplement.py b/policyengine_us/variables/gov/states/nh/dhhs/ccap/payment/nh_ccap_disability_supplement.py new file mode 100644 index 00000000000..e44fc70847f --- /dev/null +++ b/policyengine_us/variables/gov/states/nh/dhhs/ccap/payment/nh_ccap_disability_supplement.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class nh_ccap_disability_supplement(Variable): + value_type = float + entity = Person + unit = USD + label = "New Hampshire Child Care Scholarship Program weekly disability supplement" + definition_period = MONTH + defined_for = "nh_ccap_eligible_child" + reference = "https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.17" + + def formula(person, period, parameters): + p = parameters(period).gov.states.nh.dhhs.ccap.payment + is_disabled = person("is_disabled", period.this_year) + service_level = person("nh_ccap_service_level", period) + supplement = p.disability_supplement.amount[service_level] + return is_disabled * supplement diff --git a/policyengine_us/variables/gov/states/nh/dhhs/ccap/payment/nh_ccap_payment_rate.py b/policyengine_us/variables/gov/states/nh/dhhs/ccap/payment/nh_ccap_payment_rate.py new file mode 100644 index 00000000000..db76887ab97 --- /dev/null +++ b/policyengine_us/variables/gov/states/nh/dhhs/ccap/payment/nh_ccap_payment_rate.py @@ -0,0 +1,41 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.nh.dhhs.ccap.nh_ccap_provider_type import ( + NHCCAPProviderType, +) + + +class nh_ccap_payment_rate(Variable): + value_type = float + entity = Person + unit = USD + label = "New Hampshire Child Care Scholarship Program weekly payment rate" + definition_period = MONTH + defined_for = "nh_ccap_eligible_child" + reference = "https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.17" + + def formula(person, period, parameters): + p = parameters(period).gov.states.nh.dhhs.ccap.payment + provider_type = person("nh_ccap_provider_type", period) + age_category = person("nh_ccap_child_age_category", period) + service_level = person("nh_ccap_service_level", period) + + licensed_center_rate = p.rates.licensed_center[age_category][service_level] + licensed_family_rate = p.rates.licensed_family[age_category][service_level] + # He-C 6910.17(c): exempt in-home = 70% of licensed family rate + exempt_in_home_rate = licensed_family_rate * p.exempt_in_home_rate + # He-C 6910.17(d): exempt center = 50% of licensed center rate + exempt_center_rate = licensed_center_rate * p.exempt_center_rate + + return select( + [ + provider_type == NHCCAPProviderType.LICENSED_CENTER, + provider_type == NHCCAPProviderType.LICENSED_FAMILY, + provider_type == NHCCAPProviderType.LICENSE_EXEMPT_IN_HOME, + ], + [ + licensed_center_rate, + licensed_family_rate, + exempt_in_home_rate, + ], + default=exempt_center_rate, + ) diff --git a/policyengine_us/variables/gov/states/nh/dhhs/nh_child_care_subsidies.py b/policyengine_us/variables/gov/states/nh/dhhs/nh_child_care_subsidies.py new file mode 100644 index 00000000000..bda0e10d3f5 --- /dev/null +++ b/policyengine_us/variables/gov/states/nh/dhhs/nh_child_care_subsidies.py @@ -0,0 +1,12 @@ +from policyengine_us.model_api import * + + +class nh_child_care_subsidies(Variable): + value_type = float + entity = SPMUnit + label = "New Hampshire child care subsidies" + unit = USD + definition_period = YEAR + defined_for = StateCode.NH + reference = "https://www.law.cornell.edu/regulations/new-hampshire/title-He/subtitle-He-C/chapter-He-C-6900/part-He-C-6910" + adds = ["nh_ccap"] diff --git a/uv.lock b/uv.lock index efec4d8555d..7adaf13620b 100644 --- a/uv.lock +++ b/uv.lock @@ -1492,7 +1492,7 @@ wheels = [ [[package]] name = "policyengine-us" -version = "1.592.1" +version = "1.598.0" source = { editable = "." } dependencies = [ { name = "microdf-python" },