From a62d7d203ca2b41c54304c7789646acded95960b Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 9 Mar 2026 10:33:03 -0400 Subject: [PATCH 1/5] Initialize RI CCAP implementation From 982d6752854309a3c2a7125cbf2aa71c0dcaf2b6 Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 9 Mar 2026 11:40:07 -0400 Subject: [PATCH 2/5] Implement Rhode Island CCAP (ref #7738) Co-Authored-By: Claude Opus 4.6 --- .../dhs/ccap/age_group/center/infant_max.yaml | 11 + .../ccap/age_group/center/toddler_max.yaml | 11 + .../age_group/family/infant_toddler_max.yaml | 13 + .../ri/dhs/ccap/age_threshold/child.yaml | 11 + .../ccap/age_threshold/disabled_child.yaml | 11 + .../gov/states/ri/dhs/ccap/assets/limit.yaml | 11 + .../states/ri/dhs/ccap/assets/sources.yaml | 18 + .../gov/states/ri/dhs/ccap/copay/rate.yaml | 30 ++ .../ccap/income/countable_income/sources.yaml | 38 ++ .../income/fpl_rate/initial_eligibility.yaml | 11 + .../ccap/income/fpl_rate/transitional.yaml | 11 + .../ccap/qualified_immigration_statuses.yaml | 19 + .../gov/states/ri/dhs/ccap/rates/center.yaml | 200 ++++++++ .../gov/states/ri/dhs/ccap/rates/exempt.yaml | 132 +++++ .../gov/states/ri/dhs/ccap/rates/family.yaml | 160 ++++++ .../ccap/time_authorization/thresholds.yaml | 28 ++ .../ri/dhs/ccap/copay/ri_ccap_copay.yaml | 145 ++++++ .../ccap/copay/ri_ccap_fpl_copay_rate.yaml | 120 +++++ .../ri/dhs/ccap/edge_cases/ri_ccap.yaml | 312 ++++++++++++ .../edge_cases/ri_ccap_asset_eligible.yaml | 42 ++ .../ri/dhs/ccap/edge_cases/ri_ccap_copay.yaml | 68 +++ .../dhs/ccap/edge_cases/ri_ccap_eligible.yaml | 130 +++++ .../edge_cases/ri_ccap_eligible_child.yaml | 150 ++++++ .../edge_cases/ri_ccap_fpl_copay_rate.yaml | 146 ++++++ .../edge_cases/ri_ccap_income_eligible.yaml | 206 ++++++++ .../ri_ccap_maximum_weekly_benefit.yaml | 193 ++++++++ .../edge_cases/ri_ccap_time_category.yaml | 46 ++ .../eligibility/ri_ccap_asset_eligible.yaml | 77 +++ .../ccap/eligibility/ri_ccap_eligible.yaml | 128 +++++ .../eligibility/ri_ccap_eligible_child.yaml | 159 ++++++ ...cap_immigration_status_eligible_child.yaml | 129 +++++ .../eligibility/ri_ccap_income_eligible.yaml | 140 ++++++ .../gov/states/ri/dhs/ccap/integration.yaml | 422 ++++++++++++++++ .../gov/states/ri/dhs/ccap/ri_ccap.yaml | 213 ++++++++ .../ri/dhs/ccap/ri_ccap_center_age_group.yaml | 100 ++++ .../ri/dhs/ccap/ri_ccap_family_age_group.yaml | 85 ++++ .../ccap/ri_ccap_maximum_weekly_benefit.yaml | 286 +++++++++++ .../ri/dhs/ccap/ri_ccap_time_category.yaml | 135 +++++ .../states/ri/dhs/ccap/copay/ri_ccap_copay.py | 26 + .../dhs/ccap/copay/ri_ccap_fpl_copay_rate.py | 18 + .../eligibility/ri_ccap_asset_eligible.py | 15 + .../dhs/ccap/eligibility/ri_ccap_eligible.py | 23 + .../eligibility/ri_ccap_eligible_child.py | 22 + ..._ccap_immigration_status_eligible_child.py | 19 + .../eligibility/ri_ccap_income_eligible.py | 24 + .../gov/states/ri/dhs/ccap/ri_ccap.py | 23 + .../gov/states/ri/dhs/ccap/ri_ccap_assets.py | 13 + .../ri/dhs/ccap/ri_ccap_center_age_group.py | 37 ++ .../ri/dhs/ccap/ri_ccap_countable_income.py | 13 + .../states/ri/dhs/ccap/ri_ccap_enrolled.py | 9 + .../ri/dhs/ccap/ri_ccap_family_age_group.py | 37 ++ .../ccap/ri_ccap_maximum_weekly_benefit.py | 45 ++ .../ri/dhs/ccap/ri_ccap_provider_type.py | 18 + .../states/ri/dhs/ccap/ri_ccap_star_rating.py | 20 + .../states/ri/dhs/ccap/ri_ccap_step_rating.py | 19 + .../ri/dhs/ccap/ri_ccap_time_category.py | 24 + .../ri/dhs/ccap/ri_child_care_subsidies.py | 11 + .../expense/childcare/childcare_expenses.py | 2 +- sources/working_references.md | 460 ++++++++++++++++++ 59 files changed, 5024 insertions(+), 1 deletion(-) create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/age_group/center/infant_max.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/age_group/center/toddler_max.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/age_group/family/infant_toddler_max.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/age_threshold/child.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/age_threshold/disabled_child.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/assets/limit.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/assets/sources.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/copay/rate.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/income/countable_income/sources.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/income/fpl_rate/initial_eligibility.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/income/fpl_rate/transitional.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/qualified_immigration_statuses.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/rates/center.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/rates/exempt.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/rates/family.yaml create mode 100644 policyengine_us/parameters/gov/states/ri/dhs/ccap/time_authorization/thresholds.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/copay/ri_ccap_copay.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/copay/ri_ccap_fpl_copay_rate.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_asset_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_copay.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_eligible_child.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_fpl_copay_rate.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_income_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_maximum_weekly_benefit.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_time_category.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_asset_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_immigration_status_eligible_child.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_income_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/integration.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_center_age_group.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_family_age_group.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_maximum_weekly_benefit.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_time_category.yaml create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/copay/ri_ccap_copay.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/copay/ri_ccap_fpl_copay_rate.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_asset_eligible.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_immigration_status_eligible_child.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_income_eligible.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_assets.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_center_age_group.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_countable_income.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_enrolled.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_family_age_group.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_maximum_weekly_benefit.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_provider_type.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_star_rating.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_step_rating.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_time_category.py create mode 100644 policyengine_us/variables/gov/states/ri/dhs/ccap/ri_child_care_subsidies.py create mode 100644 sources/working_references.md diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_group/center/infant_max.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_group/center/infant_max.yaml new file mode 100644 index 00000000000..e5c32790d1a --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_group/center/infant_max.yaml @@ -0,0 +1,11 @@ +description: Rhode Island defines the licensed center infant age group as children younger than this age under the Child Care Assistance Program. +values: + 2025-07-01: 2 + +metadata: + unit: year + period: year + label: Rhode Island CCAP licensed center infant age maximum + reference: + - title: RI DHS CCAP Licensed Center Child Care Weekly Rates, Effective July 1, 2025 + href: https://dhs.ri.gov/media/9356/download?language=en diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_group/center/toddler_max.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_group/center/toddler_max.yaml new file mode 100644 index 00000000000..a2af5bb9415 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_group/center/toddler_max.yaml @@ -0,0 +1,11 @@ +description: Rhode Island defines the licensed center toddler age group as children younger than this age under the Child Care Assistance Program. +values: + 2025-07-01: 3 + +metadata: + unit: year + period: year + label: Rhode Island CCAP licensed center toddler age maximum + reference: + - title: RI DHS CCAP Licensed Center Child Care Weekly Rates, Effective July 1, 2025 + href: https://dhs.ri.gov/media/9356/download?language=en diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_group/family/infant_toddler_max.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_group/family/infant_toddler_max.yaml new file mode 100644 index 00000000000..4172796308b --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_group/family/infant_toddler_max.yaml @@ -0,0 +1,13 @@ +description: Rhode Island defines the licensed family and exempt infant/toddler age group as children younger than this age under the Child Care Assistance Program. +values: + 2024-07-01: 3 + +metadata: + unit: year + period: year + label: Rhode Island CCAP licensed family infant/toddler age maximum + reference: + - title: RI DHS CCAP Licensed Family Child Care Weekly Rates, Effective July 1, 2024 + href: https://dhs.ri.gov/media/7481/download?language=en + - title: RI DHS CCAP Licensed Exempt Child Care Weekly Rates, Effective January 1, 2022 + href: https://dhs.ri.gov/media/3556/download?language=en diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_threshold/child.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_threshold/child.yaml new file mode 100644 index 00000000000..9039e2345a7 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_threshold/child.yaml @@ -0,0 +1,11 @@ +description: Rhode Island limits the Child Care Assistance Program to children younger than this age. +values: + 2020-01-01: 13 + +metadata: + unit: year + period: year + label: Rhode Island CCAP child age threshold + reference: + - title: 218-RICR-20-00-4, Section 4.3.1.A.1 + href: https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.3.1 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_threshold/disabled_child.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_threshold/disabled_child.yaml new file mode 100644 index 00000000000..88c4f918731 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_threshold/disabled_child.yaml @@ -0,0 +1,11 @@ +description: Rhode Island limits the Child Care Assistance Program to disabled children younger than this age. +values: + 2020-01-01: 18 + +metadata: + unit: year + period: year + label: Rhode Island CCAP disabled child age threshold + reference: + - title: 218-RICR-20-00-4, Section 4.3.1.A.1 + href: https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.3.1 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/assets/limit.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/assets/limit.yaml new file mode 100644 index 00000000000..37fc58de8d3 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/assets/limit.yaml @@ -0,0 +1,11 @@ +description: Rhode Island limits assets to this amount under the Child Care Assistance Program. +values: + 2020-01-01: 1_000_000 + +metadata: + unit: currency-USD + period: year + label: Rhode Island CCAP asset limit + reference: + - title: 218-RICR-20-00-4, Section 4.6.1.B + href: https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.6.1 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/assets/sources.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/assets/sources.yaml new file mode 100644 index 00000000000..9524b3b7830 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/assets/sources.yaml @@ -0,0 +1,18 @@ +description: Rhode Island counts these asset sources under the Child Care Assistance Program. +values: + 2020-01-01: + - spm_unit_cash_assets + # Assets include vehicles (excl. primary), real estate (excl. primary + # residence), cash, bank accounts, investments. + # Assets exclude educational savings, retirement accounts, joint + # accounts with non-household adults. + # assessed_property_value is person-level; not included because + # it includes primary residence which is excluded. + +metadata: + unit: list + period: year + label: Rhode Island CCAP asset sources + reference: + - title: 218-RICR-20-00-4, Section 4.6.1.B + href: https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.6.1 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/copay/rate.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/copay/rate.yaml new file mode 100644 index 00000000000..f8246173764 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/copay/rate.yaml @@ -0,0 +1,30 @@ +description: Rhode Island sets this co-share percentage of gross income under the Child Care Assistance Program. +metadata: + type: single_amount + threshold_unit: /1 + amount_unit: /1 + period: year + label: Rhode Island CCAP co-share rate by FPL ratio + reference: + - title: 218-RICR-20-00-4, Section 4.6.1.C + href: https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.6.1 + - title: RI DHS CCAP Co-Pay Chart effective 02/15/2026 + href: https://dhs.ri.gov/media/10606/download?language=en + +brackets: + - threshold: + 2020-01-01: 0 + amount: + 2020-01-01: 0 + - threshold: + 2020-01-01: 1.0001 + amount: + 2020-01-01: 0.02 + - threshold: + 2020-01-01: 1.2501 + amount: + 2020-01-01: 0.05 + - threshold: + 2020-01-01: 1.5001 + amount: + 2020-01-01: 0.07 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/income/countable_income/sources.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/income/countable_income/sources.yaml new file mode 100644 index 00000000000..7e6904f1016 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/income/countable_income/sources.yaml @@ -0,0 +1,38 @@ +description: Rhode Island counts these income sources under the Child Care Assistance Program. +values: + 2020-01-01: + - employment_income + - self_employment_income + - social_security_retirement + - ssi + - dividend_income + - interest_income + - rental_income + - pension_income + - veterans_benefits + - military_retirement_pay + - unemployment_compensation + - workers_compensation + - alimony_income + - child_support_received + # The following are counted per 218-RICR-20-00-4, Section 4.2, + # Definition 30 (Income) but have no matching variables: + # - adoption_subsidy + # - strike_benefits + # - royalties + # - temporary_disability_insurance + # - in-kind assistance + # - non-citizen sponsor income + # - room and board income + # - cash payouts for waiving health insurance + # - foster care payments when child in unit + # - VA educational benefits (separate from veterans_benefits) + # - Americorps payments (non-VISTA) + +metadata: + unit: list + period: year + label: Rhode Island CCAP countable income sources + reference: + - title: 218-RICR-20-00-4, Section 4.2, Definition 30 (Income) + href: https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.2 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/income/fpl_rate/initial_eligibility.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/income/fpl_rate/initial_eligibility.yaml new file mode 100644 index 00000000000..b1d9fdbc55b --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/income/fpl_rate/initial_eligibility.yaml @@ -0,0 +1,11 @@ +description: Rhode Island limits the Child Care Assistance Program to new applicants with income at or below this share of the federal poverty level. +values: + 2020-01-01: 2.61 + +metadata: + unit: /1 + period: year + label: Rhode Island CCAP initial eligibility FPL rate + reference: + - title: 218-RICR-20-00-4, Section 4.6.1.A + href: https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.6.1 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/income/fpl_rate/transitional.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/income/fpl_rate/transitional.yaml new file mode 100644 index 00000000000..4ddab21c720 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/income/fpl_rate/transitional.yaml @@ -0,0 +1,11 @@ +description: Rhode Island limits the Child Care Assistance Program to enrolled families with income at or below this share of the federal poverty level. +values: + 2020-01-01: 3 + +metadata: + unit: /1 + period: year + label: Rhode Island CCAP transitional eligibility FPL rate + reference: + - title: 218-RICR-20-00-4, Section 4.6.1.A.1 + href: https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.6.1 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/qualified_immigration_statuses.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/qualified_immigration_statuses.yaml new file mode 100644 index 00000000000..30d15c6677d --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/qualified_immigration_statuses.yaml @@ -0,0 +1,19 @@ +description: Rhode Island limits the Child Care Assistance Program to children of these immigration statuses. +values: + 2020-01-01: + - CITIZEN + - LEGAL_PERMANENT_RESIDENT + - REFUGEE + - ASYLEE + - DEPORTATION_WITHHELD + - CUBAN_HAITIAN_ENTRANT + - CONDITIONAL_ENTRANT + - PAROLED_ONE_YEAR + +metadata: + unit: list + period: year + label: Rhode Island CCAP qualified immigration statuses + reference: + - title: 218-RICR-20-00-4, Section 4.3.1.A.4 + href: https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.3.1 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/rates/center.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/rates/center.yaml new file mode 100644 index 00000000000..49c8abca01b --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/rates/center.yaml @@ -0,0 +1,200 @@ +description: Rhode Island provides these weekly reimbursement rates for licensed child care centers under the Child Care Assistance Program. +metadata: + period: week + unit: currency-USD + label: Rhode Island CCAP licensed center weekly rates + breakdown: + - ri_ccap_time_category + - ri_ccap_star_rating + - ri_ccap_center_age_group + reference: + - title: RI DHS CCAP Licensed Center Child Care Weekly Rates, Effective July 1, 2025 + href: https://dhs.ri.gov/media/9356/download?language=en + +FULL_TIME: + STAR_1: + INFANT: + 2025-07-01: 334 + TODDLER: + 2025-07-01: 278 + PRESCHOOL: + 2025-07-01: 236 + SCHOOL_AGE: + 2025-07-01: 210 + STAR_2: + INFANT: + 2025-07-01: 341 + TODDLER: + 2025-07-01: 284 + PRESCHOOL: + 2025-07-01: 247 + SCHOOL_AGE: + 2025-07-01: 215 + STAR_3: + INFANT: + 2025-07-01: 355 + TODDLER: + 2025-07-01: 296 + PRESCHOOL: + 2025-07-01: 255 + SCHOOL_AGE: + 2025-07-01: 231 + STAR_4: + INFANT: + 2025-07-01: 364 + TODDLER: + 2025-07-01: 303 + PRESCHOOL: + 2025-07-01: 263 + SCHOOL_AGE: + 2025-07-01: 250 + STAR_5: + INFANT: + 2025-07-01: 378 + TODDLER: + 2025-07-01: 315 + PRESCHOOL: + 2025-07-01: 273 + SCHOOL_AGE: + 2025-07-01: 263 + +THREE_QUARTER_TIME: + STAR_1: + INFANT: + 2025-07-01: 250.50 + TODDLER: + 2025-07-01: 208.50 + PRESCHOOL: + 2025-07-01: 177 + SCHOOL_AGE: + 2025-07-01: 157.50 + STAR_2: + INFANT: + 2025-07-01: 255.75 + TODDLER: + 2025-07-01: 213 + PRESCHOOL: + 2025-07-01: 185.25 + SCHOOL_AGE: + 2025-07-01: 161.25 + STAR_3: + INFANT: + 2025-07-01: 266.25 + TODDLER: + 2025-07-01: 222 + PRESCHOOL: + 2025-07-01: 191.25 + SCHOOL_AGE: + 2025-07-01: 173.25 + STAR_4: + INFANT: + 2025-07-01: 273 + TODDLER: + 2025-07-01: 227.25 + PRESCHOOL: + 2025-07-01: 197.25 + SCHOOL_AGE: + 2025-07-01: 187.50 + STAR_5: + INFANT: + 2025-07-01: 283.50 + TODDLER: + 2025-07-01: 236.25 + PRESCHOOL: + 2025-07-01: 204.75 + SCHOOL_AGE: + 2025-07-01: 197.25 + +HALF_TIME: + STAR_1: + INFANT: + 2025-07-01: 167 + TODDLER: + 2025-07-01: 139 + PRESCHOOL: + 2025-07-01: 118 + SCHOOL_AGE: + 2025-07-01: 105 + STAR_2: + INFANT: + 2025-07-01: 170.50 + TODDLER: + 2025-07-01: 142 + PRESCHOOL: + 2025-07-01: 123.50 + SCHOOL_AGE: + 2025-07-01: 107.50 + STAR_3: + INFANT: + 2025-07-01: 177.50 + TODDLER: + 2025-07-01: 148 + PRESCHOOL: + 2025-07-01: 127.50 + SCHOOL_AGE: + 2025-07-01: 115.50 + STAR_4: + INFANT: + 2025-07-01: 182 + TODDLER: + 2025-07-01: 151.50 + PRESCHOOL: + 2025-07-01: 131.50 + SCHOOL_AGE: + 2025-07-01: 125 + STAR_5: + INFANT: + 2025-07-01: 189 + TODDLER: + 2025-07-01: 157.50 + PRESCHOOL: + 2025-07-01: 136.50 + SCHOOL_AGE: + 2025-07-01: 131.50 + +QUARTER_TIME: + STAR_1: + INFANT: + 2025-07-01: 83.50 + TODDLER: + 2025-07-01: 69.50 + PRESCHOOL: + 2025-07-01: 59 + SCHOOL_AGE: + 2025-07-01: 52.50 + STAR_2: + INFANT: + 2025-07-01: 85.25 + TODDLER: + 2025-07-01: 71 + PRESCHOOL: + 2025-07-01: 61.75 + SCHOOL_AGE: + 2025-07-01: 53.75 + STAR_3: + INFANT: + 2025-07-01: 88.75 + TODDLER: + 2025-07-01: 74 + PRESCHOOL: + 2025-07-01: 63.75 + SCHOOL_AGE: + 2025-07-01: 57.75 + STAR_4: + INFANT: + 2025-07-01: 91 + TODDLER: + 2025-07-01: 75.75 + PRESCHOOL: + 2025-07-01: 65.75 + SCHOOL_AGE: + 2025-07-01: 62.50 + STAR_5: + INFANT: + 2025-07-01: 94.50 + TODDLER: + 2025-07-01: 78.75 + PRESCHOOL: + 2025-07-01: 68.25 + SCHOOL_AGE: + 2025-07-01: 65.75 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/rates/exempt.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/rates/exempt.yaml new file mode 100644 index 00000000000..19e3eb21153 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/rates/exempt.yaml @@ -0,0 +1,132 @@ +description: Rhode Island provides these weekly reimbursement rates for license-exempt child care under the Child Care Assistance Program. +metadata: + period: week + unit: currency-USD + label: Rhode Island CCAP license-exempt weekly rates + breakdown: + - ri_ccap_time_category + - ri_ccap_step_rating + - ri_ccap_family_age_group + reference: + - title: RI DHS CCAP Licensed Exempt Child Care Weekly Rates, Effective January 1, 2022 + href: https://dhs.ri.gov/media/3556/download?language=en + +FULL_TIME: + STEP_1: + INFANT_TODDLER: + 2022-01-01: 100.96 + PRESCHOOL: + 2022-01-01: 59.91 + SCHOOL_AGE: + 2022-01-01: 58.80 + STEP_2: + INFANT_TODDLER: + 2022-01-01: 101.95 + PRESCHOOL: + 2022-01-01: 60.49 + SCHOOL_AGE: + 2022-01-01: 59.38 + STEP_3: + INFANT_TODDLER: + 2022-01-01: 102.94 + PRESCHOOL: + 2022-01-01: 61.09 + SCHOOL_AGE: + 2022-01-01: 59.97 + STEP_4: + INFANT_TODDLER: + 2022-01-01: 103.96 + PRESCHOOL: + 2022-01-01: 61.68 + SCHOOL_AGE: + 2022-01-01: 60.53 + +THREE_QUARTER_TIME: + STEP_1: + INFANT_TODDLER: + 2022-01-01: 75.72 + PRESCHOOL: + 2022-01-01: 44.93 + SCHOOL_AGE: + 2022-01-01: 44.10 + STEP_2: + INFANT_TODDLER: + 2022-01-01: 76.46 + PRESCHOOL: + 2022-01-01: 45.37 + SCHOOL_AGE: + 2022-01-01: 44.53 + STEP_3: + INFANT_TODDLER: + 2022-01-01: 77.21 + PRESCHOOL: + 2022-01-01: 45.83 + SCHOOL_AGE: + 2022-01-01: 44.97 + STEP_4: + INFANT_TODDLER: + 2022-01-01: 77.96 + PRESCHOOL: + 2022-01-01: 46.26 + SCHOOL_AGE: + 2022-01-01: 45.40 + +HALF_TIME: + STEP_1: + INFANT_TODDLER: + 2022-01-01: 50.48 + PRESCHOOL: + 2022-01-01: 29.95 + SCHOOL_AGE: + 2022-01-01: 29.40 + STEP_2: + INFANT_TODDLER: + 2022-01-01: 50.98 + PRESCHOOL: + 2022-01-01: 30.26 + SCHOOL_AGE: + 2022-01-01: 29.69 + STEP_3: + INFANT_TODDLER: + 2022-01-01: 51.48 + PRESCHOOL: + 2022-01-01: 30.54 + SCHOOL_AGE: + 2022-01-01: 29.98 + STEP_4: + INFANT_TODDLER: + 2022-01-01: 51.98 + PRESCHOOL: + 2022-01-01: 30.84 + SCHOOL_AGE: + 2022-01-01: 30.28 + +QUARTER_TIME: + STEP_1: + INFANT_TODDLER: + 2022-01-01: 25.24 + PRESCHOOL: + 2022-01-01: 14.71 + SCHOOL_AGE: + 2022-01-01: 14.70 + STEP_2: + INFANT_TODDLER: + 2022-01-01: 25.49 + PRESCHOOL: + 2022-01-01: 15.11 + SCHOOL_AGE: + 2022-01-01: 14.85 + STEP_3: + INFANT_TODDLER: + 2022-01-01: 25.74 + PRESCHOOL: + 2022-01-01: 15.28 + SCHOOL_AGE: + 2022-01-01: 14.99 + STEP_4: + INFANT_TODDLER: + 2022-01-01: 25.98 + PRESCHOOL: + 2022-01-01: 15.42 + SCHOOL_AGE: + 2022-01-01: 15.13 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/rates/family.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/rates/family.yaml new file mode 100644 index 00000000000..0adda51c479 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/rates/family.yaml @@ -0,0 +1,160 @@ +description: Rhode Island provides these weekly reimbursement rates for licensed family child care under the Child Care Assistance Program. +metadata: + period: week + unit: currency-USD + label: Rhode Island CCAP licensed family weekly rates + breakdown: + - ri_ccap_time_category + - ri_ccap_star_rating + - ri_ccap_family_age_group + reference: + - title: RI DHS CCAP Licensed Family Child Care Weekly Rates, Effective July 1, 2024 + href: https://dhs.ri.gov/media/7481/download?language=en + +FULL_TIME: + STAR_1: + INFANT_TODDLER: + 2024-07-01: 262.66 + PRESCHOOL: + 2024-07-01: 220.63 + SCHOOL_AGE: + 2024-07-01: 194.37 + STAR_2: + INFANT_TODDLER: + 2024-07-01: 266.86 + PRESCHOOL: + 2024-07-01: 231.14 + SCHOOL_AGE: + 2024-07-01: 199.62 + STAR_3: + INFANT_TODDLER: + 2024-07-01: 270.02 + PRESCHOOL: + 2024-07-01: 239.54 + SCHOOL_AGE: + 2024-07-01: 215.38 + STAR_4: + INFANT_TODDLER: + 2024-07-01: 273.16 + PRESCHOOL: + 2024-07-01: 251.10 + SCHOOL_AGE: + 2024-07-01: 236.40 + STAR_5: + INFANT_TODDLER: + 2024-07-01: 276.31 + PRESCHOOL: + 2024-07-01: 262.66 + SCHOOL_AGE: + 2024-07-01: 246.90 + +THREE_QUARTER_TIME: + STAR_1: + INFANT_TODDLER: + 2024-07-01: 196.99 + PRESCHOOL: + 2024-07-01: 165.47 + SCHOOL_AGE: + 2024-07-01: 145.78 + STAR_2: + INFANT_TODDLER: + 2024-07-01: 200.14 + PRESCHOOL: + 2024-07-01: 173.35 + SCHOOL_AGE: + 2024-07-01: 149.71 + STAR_3: + INFANT_TODDLER: + 2024-07-01: 202.51 + PRESCHOOL: + 2024-07-01: 179.66 + SCHOOL_AGE: + 2024-07-01: 161.54 + STAR_4: + INFANT_TODDLER: + 2024-07-01: 204.87 + PRESCHOOL: + 2024-07-01: 188.33 + SCHOOL_AGE: + 2024-07-01: 177.30 + STAR_5: + INFANT_TODDLER: + 2024-07-01: 207.23 + PRESCHOOL: + 2024-07-01: 196.99 + SCHOOL_AGE: + 2024-07-01: 185.18 + +HALF_TIME: + STAR_1: + INFANT_TODDLER: + 2024-07-01: 131.33 + PRESCHOOL: + 2024-07-01: 110.32 + SCHOOL_AGE: + 2024-07-01: 97.19 + STAR_2: + INFANT_TODDLER: + 2024-07-01: 133.43 + PRESCHOOL: + 2024-07-01: 115.57 + SCHOOL_AGE: + 2024-07-01: 99.81 + STAR_3: + INFANT_TODDLER: + 2024-07-01: 135.01 + PRESCHOOL: + 2024-07-01: 119.77 + SCHOOL_AGE: + 2024-07-01: 107.69 + STAR_4: + INFANT_TODDLER: + 2024-07-01: 136.58 + PRESCHOOL: + 2024-07-01: 125.55 + SCHOOL_AGE: + 2024-07-01: 118.20 + STAR_5: + INFANT_TODDLER: + 2024-07-01: 138.15 + PRESCHOOL: + 2024-07-01: 131.33 + SCHOOL_AGE: + 2024-07-01: 123.45 + +QUARTER_TIME: + STAR_1: + INFANT_TODDLER: + 2024-07-01: 65.66 + PRESCHOOL: + 2024-07-01: 55.16 + SCHOOL_AGE: + 2024-07-01: 48.59 + STAR_2: + INFANT_TODDLER: + 2024-07-01: 66.71 + PRESCHOOL: + 2024-07-01: 57.78 + SCHOOL_AGE: + 2024-07-01: 49.90 + STAR_3: + INFANT_TODDLER: + 2024-07-01: 67.50 + PRESCHOOL: + 2024-07-01: 59.89 + SCHOOL_AGE: + 2024-07-01: 53.85 + STAR_4: + INFANT_TODDLER: + 2024-07-01: 68.29 + PRESCHOOL: + 2024-07-01: 62.78 + SCHOOL_AGE: + 2024-07-01: 59.10 + STAR_5: + INFANT_TODDLER: + 2024-07-01: 69.08 + PRESCHOOL: + 2024-07-01: 65.66 + SCHOOL_AGE: + 2024-07-01: 61.73 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/time_authorization/thresholds.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/time_authorization/thresholds.yaml new file mode 100644 index 00000000000..b95932ac21d --- /dev/null +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/time_authorization/thresholds.yaml @@ -0,0 +1,28 @@ +description: Rhode Island sets these time authorization levels based on weekly child care hours under the Child Care Assistance Program. +metadata: + type: single_amount + threshold_unit: hour + amount_unit: /1 + period: year + label: Rhode Island CCAP time authorization thresholds + reference: + - title: 218-RICR-20-00-4, Section 4.7.1.A.2 + href: https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.7.1 + +brackets: + - threshold: + 2020-01-01: 0 + amount: + 2020-01-01: 3 + - threshold: + 2020-01-01: 10 + amount: + 2020-01-01: 2 + - threshold: + 2020-01-01: 20 + amount: + 2020-01-01: 1 + - threshold: + 2020-01-01: 30 + amount: + 2020-01-01: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/copay/ri_ccap_copay.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/copay/ri_ccap_copay.yaml new file mode 100644 index 00000000000..576014d1adc --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/copay/ri_ccap_copay.yaml @@ -0,0 +1,145 @@ +# 2025 FPG family of 3: 15_650 + 5_500 * 2 = 26_650 + +- name: Case 1, income at 200 percent FPL with 7 percent copay. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 53_300 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # FPL ratio = 53,300 / 26,650 = 2.0 -> 7% rate + # copay = 53,300 * 0.07 = 3,731 + ri_ccap_copay: 3_731 + +- name: Case 2, TANF enrolled family pays zero copay. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_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: RI + output: + # TANF enrolled -> exempt from copay -> $0 + ri_ccap_copay: 0 + +- name: Case 3, housing insecure family pays zero copay. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 35_000 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: RI + is_homeless: true + output: + # housing insecure -> exempt from copay -> $0 + ri_ccap_copay: 0 + +- name: Case 4, income at 110 percent FPL with 2 percent copay. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 29_315 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # FPL ratio = 29,315 / 26,650 = 1.1 -> 2% rate + # copay = 29,315 * 0.02 = 586.30 + ri_ccap_copay: 586.30 + +- name: Case 5, income at or below 100 percent FPL pays zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # FPL ratio = 20,000 / 26,650 = 0.75 -> 0% rate + # copay = 20,000 * 0 = 0 + ri_ccap_copay: 0 + +- name: Case 6, income at 130 percent FPL with 5 percent copay. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 34_645 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # FPL ratio = 34,645 / 26,650 = 1.3 -> 5% rate + # copay = 34,645 * 0.05 = 1,732.25 + ri_ccap_copay: 1_732.25 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/copay/ri_ccap_fpl_copay_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/copay/ri_ccap_fpl_copay_rate.yaml new file mode 100644 index 00000000000..6ab912d1444 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/copay/ri_ccap_fpl_copay_rate.yaml @@ -0,0 +1,120 @@ +# 2025 FPG family of 3: 15_650 + 5_500 * 2 = 26_650 +# Copay rate brackets by FPL ratio: +# 0 to 1.0 -> 0% +# 1.0001 to 1.25 -> 2% +# 1.2501 to 1.5 -> 5% +# 1.5001+ -> 7% + +- name: Case 1, income at 0 percent FPL. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # FPL ratio = 0 / 26,650 = 0 -> 0% + ri_ccap_fpl_copay_rate: 0 + +- name: Case 2, income at 100 percent FPL. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 26_650 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # FPL ratio = 26,650 / 26,650 = 1.0 -> 0% (at or below 100%) + ri_ccap_fpl_copay_rate: 0 + +- name: Case 3, income at 110 percent FPL. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 29_315 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # FPL ratio = 29,315 / 26,650 = 1.1 -> 2% + ri_ccap_fpl_copay_rate: 0.02 + +- name: Case 4, income at 130 percent FPL. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 34_645 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # FPL ratio = 34,645 / 26,650 = 1.3 -> 5% + ri_ccap_fpl_copay_rate: 0.05 + +- name: Case 5, income at 200 percent FPL. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 53_300 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # FPL ratio = 53,300 / 26,650 = 2.0 -> 7% + ri_ccap_fpl_copay_rate: 0.07 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap.yaml new file mode 100644 index 00000000000..6ec15132e3b --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap.yaml @@ -0,0 +1,312 @@ +# Edge cases for ri_ccap (top-level benefit) +# 2025 FPG family of 2: 21_150 +# benefit = min(max(pre_subsidy_childcare_expenses - copay, 0), max_weekly_benefit * 52) + +- name: Case 1, multiple children different providers aggregated. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 25_000 + immigration_status: CITIZEN + person2: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_3 + person3: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: false + childcare_hours_per_week: 20 + ri_ccap_provider_type: LICENSED_FAMILY + ri_ccap_star_rating: STAR_2 + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + spm_unit_pre_subsidy_childcare_expenses: 20_000 + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # FPG family of 3: 26_650 + # FPL ratio = 25_000 / 26_650 = 0.9381 -> 0% copay + # copay = 0 + # child1: Center FT Star 3 Infant = $355/wk + # child2: Family 3QT Star 2 Preschool = $173.35/wk + # max annual = (355 + 173.35) * 52 = 528.35 * 52 = 27_474.20 + # uncapped = max(20_000 - 0, 0) = 20_000 + # benefit = min(20_000, 27_474.72) = 20_000 + ri_ccap: 20_000 + +- name: Case 2, TANF enrolled with high income bypasses income test. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 100_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: false + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + is_tanf_enrolled: true + spm_unit_pre_subsidy_childcare_expenses: 5_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # TANF enrolled -> categorically eligible, $0 copay + # Center FT Star 1 Preschool = $236/wk + # max annual = 236 * 52 = 12_272 + # uncapped = max(5_000 - 0, 0) = 5_000 + # benefit = min(5_000, 12_272) = 5_000 + ri_ccap: 5_000 + +- name: Case 3, housing insecure with moderate income gets zero copay. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 45_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: false + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 10_000 + households: + household: + members: [person1, person2] + state_code: RI + is_homeless: true + output: + # FPG family of 2: 21_150 + # 261% = 55_201.50, income 45_000 <= 55_201.50 -> eligible + # Housing insecure -> $0 copay + # Center FT Star 1 Preschool = $236/wk + # max annual = 236 * 52 = 12_272 + # uncapped = max(10_000 - 0, 0) = 10_000 + # benefit = min(10_000, 12_272) = 10_000 + ri_ccap: 10_000 + +- name: Case 4, enrolled family between 261 and 300 percent FPL. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 55_500 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: false + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + ri_ccap_enrolled: true + spm_unit_pre_subsidy_childcare_expenses: 12_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # FPG family of 2: 21_150 + # 261% = 55_201.50, 300% = 63_450 + # enrolled: 55_500 <= 63_450 -> eligible + # FPL ratio = 55_500 / 21_150 = 2.6241 -> 7% copay + # copay = 55_500 * 0.07 = 3_885 + # Center FT Star 1 Preschool = $236/wk + # max annual = 236 * 52 = 12_272 + # uncapped = max(12_000 - 3_885, 0) = 8_115 + # benefit = min(8_115, 12_272) = 8_115 + ri_ccap: 8_115 + +- name: Case 5, non-enrolled between 261 and 300 percent gets zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 55_500 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: false + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 12_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # not enrolled: 55_500 > 55_201.50 (261%) -> ineligible -> $0 + ri_ccap: 0 + +- name: Case 6, expenses exactly equal to max annual rate. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 15_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: false + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + # max annual = 236 * 52 = 12_272 + spm_unit_pre_subsidy_childcare_expenses: 12_272 + households: + household: + members: [person1, person2] + state_code: RI + output: + # FPL ratio = 15_000 / 21_150 = 0.709 -> 0% copay + # copay = 0 + # uncapped = max(12_272 - 0, 0) = 12_272 + # max annual = 12_272 + # benefit = min(12_272, 12_272) = 12_272 + ri_ccap: 12_272 + +- name: Case 7, quarter time care with low expenses. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: false + childcare_hours_per_week: 5 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 4_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # FPL ratio = 20_000 / 21_150 = 0.946 -> 0% copay + # copay = 0 + # Center QT Star 1 Preschool = $59/wk + # max annual = 59 * 52 = 3_068 + # uncapped = max(4_000 - 0, 0) = 4_000 + # benefit = min(4_000, 3_068) = 3_068 + ri_ccap: 3_068 + +- name: Case 8, disabled teenager with license exempt care. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + employment_income: 30_000 + immigration_status: CITIZEN + person2: + age: 17 + is_tax_unit_dependent: true + is_disabled: true + immigration_status: CITIZEN + is_in_k12_school: true + childcare_hours_per_week: 25 + ri_ccap_provider_type: LICENSE_EXEMPT + ri_ccap_step_rating: STEP_3 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 5_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # disabled, age 17 < 18 -> eligible child + # FPG family of 2: 21_150 + # FPL ratio = 30_000 / 21_150 = 1.4184 -> 5% copay + # copay = 30_000 * 0.05 = 1_500 + # Exempt 3QT Step 3 School Age = $44.97/wk + # max annual = 44.97 * 52 = 2_338.44 + # uncapped = max(5_000 - 1_500, 0) = 3_500 + # benefit = min(3_500, 2_338.44) = 2_338.44 + ri_ccap: 2_338.44 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_asset_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_asset_eligible.yaml new file mode 100644 index 00000000000..b4a0b5f4d8f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_asset_eligible.yaml @@ -0,0 +1,42 @@ +# Edge cases for ri_ccap_asset_eligible +# Asset limit: $1,000,000 + +- name: Case 1, assets one cent below limit. + period: 2025 + input: + people: + person1: + age: 30 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_cash_assets: 999_999.99 + households: + household: + members: [person1, person2] + state_code: RI + output: + # 999_999.99 <= 1_000_000 -> eligible + ri_ccap_asset_eligible: true + +- name: Case 2, assets above limit. + period: 2025 + input: + people: + person1: + age: 30 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_cash_assets: 1_000_001 + households: + household: + members: [person1, person2] + state_code: RI + output: + # 1_000_001 > 1_000_000 -> ineligible + ri_ccap_asset_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_copay.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_copay.yaml new file mode 100644 index 00000000000..96e525d93ba --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_copay.yaml @@ -0,0 +1,68 @@ +# Edge cases for ri_ccap_copay +# 2025 FPG family of 2: 21_150 +# Tests TANF + homeless overlap, zero income + +- name: Case 1, TANF enrolled and housing insecure overlap both give zero copay. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 40_000 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + is_tanf_enrolled: true + households: + household: + members: [person1, person2] + state_code: RI + is_homeless: true + output: + # Both TANF enrolled and housing insecure -> $0 copay + ri_ccap_copay: 0 + +- name: Case 2, zero income gives zero copay. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # income 0 -> FPL ratio 0 -> 0% rate -> copay = 0 * 0 = 0 + ri_ccap_copay: 0 + +- name: Case 3, very high income at 7 percent rate. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 55_000 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # FPL ratio = 55_000 / 21_150 = 2.6005 -> 7% rate + # copay = 55_000 * 0.07 = 3_850 + ri_ccap_copay: 3_850 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_eligible.yaml new file mode 100644 index 00000000000..b8c347f5842 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_eligible.yaml @@ -0,0 +1,130 @@ +# Edge cases for ri_ccap_eligible +# Tests categorical eligibility, TANF + homeless overlap, degenerate cases + +- name: Case 1, TANF enrolled bypasses income and asset tests. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 100_000 + immigration_status: CITIZEN + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + is_tanf_enrolled: true + spm_unit_cash_assets: 2_000_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # Income 100k > 261% FPL and assets 2M > 1M limit + # But TANF enrolled -> categorically eligible (bypasses both tests) + ri_ccap_eligible: true + +- name: Case 2, TANF enrolled still needs eligible child. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + is_tanf_enrolled: true + households: + household: + members: [person1] + state_code: RI + output: + # TANF enrolled but no child -> has_eligible_child = false -> ineligible + ri_ccap_eligible: false + +- name: Case 3, single adult without child is ineligible. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 10_000 + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_eligible: false + +- name: Case 4, income eligible but assets ineligible. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_cash_assets: 1_500_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # income ok, but assets 1.5M > 1M -> ineligible + ri_ccap_eligible: false + +- name: Case 5, assets eligible but income ineligible. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 60_000 + immigration_status: CITIZEN + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # FPG family of 2: 21_150 + # 261% FPL = 55_201.50 + # income 60_000 > 55_201.50 -> ineligible + ri_ccap_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_eligible_child.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_eligible_child.yaml new file mode 100644 index 00000000000..3cb5a0b6888 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_eligible_child.yaml @@ -0,0 +1,150 @@ +# Edge cases for ri_ccap_eligible_child +# Child age threshold: < 13 +# Disabled child age threshold: < 18 + +- name: Case 1, child age 12 is last eligible year. + period: 2025 + input: + people: + person1: + age: 40 + person2: + age: 12 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # age 12 < 13 -> eligible + ri_ccap_eligible_child: [false, true] + +- name: Case 2, non-disabled child age 13 is ineligible. + period: 2025 + input: + people: + person1: + age: 40 + person2: + age: 13 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # age 13 not < 13 -> ineligible + ri_ccap_eligible_child: [false, false] + +- name: Case 3, disabled child age 17 is last eligible year. + period: 2025 + input: + people: + person1: + age: 45 + person2: + age: 17 + is_tax_unit_dependent: true + is_disabled: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # disabled, age 17 < 18 -> eligible + ri_ccap_eligible_child: [false, true] + +- name: Case 4, disabled child age 18 is ineligible. + period: 2025 + input: + people: + person1: + age: 45 + person2: + age: 18 + is_tax_unit_dependent: true + is_disabled: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # disabled, age 18 not < 18 -> ineligible + ri_ccap_eligible_child: [false, false] + +- name: Case 5, disabled child age 13 is still eligible. + period: 2025 + input: + people: + person1: + age: 40 + person2: + age: 13 + is_tax_unit_dependent: true + is_disabled: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # disabled, age 13 < 18 -> eligible (uses disabled threshold) + ri_ccap_eligible_child: [false, true] + +- name: Case 6, age 0 infant is eligible. + period: 2025 + input: + people: + person1: + age: 25 + person2: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # age 0 < 13 -> eligible + ri_ccap_eligible_child: [false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_fpl_copay_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_fpl_copay_rate.yaml new file mode 100644 index 00000000000..b7252bbafea --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_fpl_copay_rate.yaml @@ -0,0 +1,146 @@ +# Edge cases for ri_ccap_fpl_copay_rate +# Copay rate brackets by FPL ratio: +# 0 to 1.0 -> 0% +# 1.0001 to 1.25 -> 2% +# 1.2501 to 1.5 -> 5% +# 1.5001+ -> 7% +# +# 2025 FPG family of 2: 21_150 +# Exact bracket boundaries: +# 100% FPL = 21_150 +# 100.01% FPL = 21_150 * 1.0001 = 21_152.115 +# 125% FPL = 26_437.50 +# 125.01% FPL = 21_150 * 1.2501 = 26_439.615 +# 150% FPL = 31_725 +# 150.01% FPL = 21_150 * 1.5001 = 31_727.115 + +- name: Case 1, income at exactly 100.01 percent FPL gets 2 percent rate. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + # income = 21_150 * 1.0001 = 21_152.115 + # This is at the 1.0001 threshold + employment_income: 21_152.115 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # FPL ratio = 21_152.115 / 21_150 = 1.0001 -> 2% + ri_ccap_fpl_copay_rate: 0.02 + +- name: Case 2, income one cent below 100.01 percent FPL gets 0 percent rate. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + # income just below 1.0001 threshold + employment_income: 21_152 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # FPL ratio = 21_152 / 21_150 = 1.0000946... < 1.0001 -> 0% + ri_ccap_fpl_copay_rate: 0 + +- name: Case 3, income at exactly 125 percent FPL gets 2 percent rate. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 26_437.50 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # FPL ratio = 26_437.50 / 21_150 = 1.25 -> still 2% (< 1.2501) + ri_ccap_fpl_copay_rate: 0.02 + +- name: Case 4, income at exactly 125.01 percent FPL gets 5 percent rate. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + # income = 21_150 * 1.2501 = 26_439.615 + employment_income: 26_439.615 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # FPL ratio = 26_439.615 / 21_150 = 1.2501 -> 5% + ri_ccap_fpl_copay_rate: 0.05 + +- name: Case 5, income at exactly 150 percent FPL gets 5 percent rate. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 31_725 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # FPL ratio = 31_725 / 21_150 = 1.5 -> still 5% (< 1.5001) + ri_ccap_fpl_copay_rate: 0.05 + +- name: Case 6, income at exactly 150.01 percent FPL gets 7 percent rate. + period: 2025 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + # income = 21_150 * 1.5001 = 31_727.115 + employment_income: 31_727.115 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # FPL ratio = 31_727.115 / 21_150 = 1.5001 -> 7% + ri_ccap_fpl_copay_rate: 0.07 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_income_eligible.yaml new file mode 100644 index 00000000000..f0c72d301bc --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_income_eligible.yaml @@ -0,0 +1,206 @@ +# Edge cases for ri_ccap_income_eligible +# 2025 FPG (Contiguous US): +# Family of 1: 15_650 +# Family of 2: 21_150 +# Family of 3: 26_650 +# 261% FPL (family of 2): 21_150 * 2.61 = 55_201.50 +# 300% FPL (family of 2): 21_150 * 3.00 = 63_450.00 + +- name: Case 1, new applicant income below 261 percent FPL. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 55_000 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # 55_000 <= ~55_201 (261% of 21_150) -> eligible + ri_ccap_income_eligible: true + +- name: Case 2, new applicant income above 261 percent FPL. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 55_500 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # 55_500 > ~55_201 (261% of 21_150) -> ineligible + ri_ccap_income_eligible: false + +- name: Case 3, new applicant income well below 261 percent FPL. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 55_100 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # 55_100 <= ~55_201 -> eligible + ri_ccap_income_eligible: true + +- name: Case 4, enrolled family income exactly at 300 percent FPL. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 63_450 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + ri_ccap_enrolled: true + households: + household: + members: [person1, person2] + state_code: RI + output: + # enrolled: 63_450 <= 63_450 -> eligible (at boundary) + ri_ccap_income_eligible: true + +- name: Case 5, enrolled family income one cent above 300 percent FPL. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 63_450.01 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + ri_ccap_enrolled: true + households: + household: + members: [person1, person2] + state_code: RI + output: + # enrolled: 63_450.01 > 63_450 -> ineligible + ri_ccap_income_eligible: false + +- name: Case 6, enrolled family income one cent below 300 percent FPL. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 63_449.99 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + ri_ccap_enrolled: true + households: + household: + members: [person1, person2] + state_code: RI + output: + # enrolled: 63_449.99 <= 63_450 -> eligible + ri_ccap_income_eligible: true + +- name: Case 7, enrolled family exactly at 261 percent FPL uses transitional limit. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 55_201.50 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + ri_ccap_enrolled: true + households: + household: + members: [person1, person2] + state_code: RI + output: + # enrolled: 55_201.50 <= 63_450 (300% FPL limit) -> eligible + ri_ccap_income_eligible: true + +- name: Case 8, non-enrolled between 261 and 300 percent is ineligible. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 55_202 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + ri_ccap_enrolled: false + households: + household: + members: [person1, person2] + state_code: RI + output: + # not enrolled: 55_202 > 55_201.50 (261% FPL) -> ineligible + ri_ccap_income_eligible: false + +- name: Case 9, large family of 8 at 261 percent FPL. + period: 2025 + input: + people: + person1: + age: 35 + # FPG family of 8: 15_650 + 5_500 * 7 = 54_150 + # 261% = 54_150 * 2.61 = 141_331.50 + employment_income: 141_331.50 + person2: + age: 10 + person3: + age: 8 + person4: + age: 6 + person5: + age: 4 + person6: + age: 3 + person7: + age: 1 + person8: + age: 38 + spm_units: + spm_unit: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + households: + household: + members: [person1, person2, person3, person4, person5, person6, person7, person8] + state_code: RI + output: + # 141_331.50 <= 141_331.50 -> eligible + ri_ccap_income_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_maximum_weekly_benefit.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_maximum_weekly_benefit.yaml new file mode 100644 index 00000000000..727751e2738 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_maximum_weekly_benefit.yaml @@ -0,0 +1,193 @@ +# Edge cases for ri_ccap_maximum_weekly_benefit +# Tests rate lookup at time category boundaries + +- name: Case 1, center full time star 1 school age with exactly 30 hours. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 7 + is_in_k12_school: true + childcare_hours_per_week: 30 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # 30 hrs -> FULL_TIME, Center FT Star 1 School Age = $210 + ri_ccap_maximum_weekly_benefit: [0, 210] + +- name: Case 2, center three quarter time star 1 school age with exactly 29 hours. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 7 + is_in_k12_school: true + childcare_hours_per_week: 29 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # 29 hrs -> THREE_QUARTER_TIME, Center 3QT Star 1 School Age = $157.50 + ri_ccap_maximum_weekly_benefit: [0, 157.50] + +- name: Case 3, center half time star 1 school age with exactly 19 hours. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 7 + is_in_k12_school: true + childcare_hours_per_week: 19 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # 19 hrs -> HALF_TIME, Center HT Star 1 School Age = $105 + ri_ccap_maximum_weekly_benefit: [0, 105] + +- name: Case 4, center half time star 1 school age with exactly 10 hours. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 7 + is_in_k12_school: true + childcare_hours_per_week: 10 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # 10 hrs -> HALF_TIME, Center HT Star 1 School Age = $105 + ri_ccap_maximum_weekly_benefit: [0, 105] + +- name: Case 5, center quarter time star 1 school age with exactly 9 hours. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 7 + is_in_k12_school: true + childcare_hours_per_week: 9 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # 9 hrs -> QUARTER_TIME, Center QT Star 1 School Age = $52.50 + ri_ccap_maximum_weekly_benefit: [0, 52.50] + +- name: Case 6, licensed family full time star 1 school age. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 7 + is_in_k12_school: true + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_FAMILY + ri_ccap_star_rating: STAR_1 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Family FT Star 1 School Age = $194.37 + ri_ccap_maximum_weekly_benefit: [0, 194.37] + +- name: Case 7, license exempt full time step 4 infant toddler. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 1 + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSE_EXEMPT + ri_ccap_step_rating: STEP_4 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Exempt FT Step 4 Infant/Toddler = $103.96 + ri_ccap_maximum_weekly_benefit: [0, 103.96] + +- name: Case 8, center full time star 5 school age highest star. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 7 + is_in_k12_school: true + childcare_hours_per_week: 40 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Center FT Star 5 School Age = $263 + ri_ccap_maximum_weekly_benefit: [0, 263] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_time_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_time_category.yaml new file mode 100644 index 00000000000..8bbff1cd936 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_time_category.yaml @@ -0,0 +1,46 @@ +# Edge cases for ri_ccap_time_category +# Time authorization thresholds: +# 0-9 hrs -> QUARTER_TIME +# 10-19 hrs -> HALF_TIME +# 20-29 hrs -> THREE_QUARTER_TIME +# 30+ hrs -> FULL_TIME + +- name: Case 1, boundary at 19 hours is half time. + period: 2025 + input: + people: + person1: + childcare_hours_per_week: 19 + households: + household: + members: [person1] + state_code: RI + output: + # 19 < 20 -> HALF_TIME + ri_ccap_time_category: HALF_TIME + +- name: Case 2, exactly 1 hour is quarter time. + period: 2025 + input: + people: + person1: + childcare_hours_per_week: 1 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_time_category: QUARTER_TIME + +- name: Case 3, very high hours still full time. + period: 2025 + input: + people: + person1: + childcare_hours_per_week: 60 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_time_category: FULL_TIME diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_asset_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_asset_eligible.yaml new file mode 100644 index 00000000000..8ec3755a310 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_asset_eligible.yaml @@ -0,0 +1,77 @@ +- name: Case 1, assets below limit. + period: 2025 + input: + people: + person1: + age: 30 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_cash_assets: 500_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # 500,000 <= 1,000,000 -> eligible + ri_ccap_asset_eligible: true + +- name: Case 2, assets exactly at limit. + period: 2025 + input: + people: + person1: + age: 30 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_cash_assets: 1_000_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # 1,000,000 <= 1,000,000 -> eligible + ri_ccap_asset_eligible: true + +- name: Case 3, assets above limit. + period: 2025 + input: + people: + person1: + age: 30 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_cash_assets: 1_000_001 + households: + household: + members: [person1, person2] + state_code: RI + output: + # 1,000,001 > 1,000,000 -> ineligible + ri_ccap_asset_eligible: false + +- name: Case 4, zero assets. + period: 2025 + input: + people: + person1: + age: 30 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + ri_ccap_asset_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible.yaml new file mode 100644 index 00000000000..2770c1e0f1c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible.yaml @@ -0,0 +1,128 @@ +# 2025 FPG family of 3: 15_650 + 5_500 * 2 = 26_650 +# 261% FPL = 69_556.50 + +- name: Case 1, eligible family with child under 13 and low income. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 30_000 + immigration_status: CITIZEN + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + ri_ccap_eligible: true + +- name: Case 2, ineligible due to income above 261 percent FPL. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 70_000 + immigration_status: CITIZEN + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # 2025 FPG family of 2: 15_650 + 5_500 = 21_150 + # 261% FPL = 21_150 * 2.61 = 55_201.50 + # income 70,000 > 55,201.50 -> ineligible + ri_ccap_eligible: false + +- name: Case 3, ineligible with no eligible child. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: RI + output: + # no child in unit -> no eligible child -> ineligible + ri_ccap_eligible: false + +- name: Case 4, ineligible due to assets above limit. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_cash_assets: 1_500_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + ri_ccap_eligible: false + +- name: Case 5, ineligible when child is undocumented. + period: 2025 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: UNDOCUMENTED + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + ri_ccap_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.yaml new file mode 100644 index 00000000000..f7b833fdf0a --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.yaml @@ -0,0 +1,159 @@ +- name: Case 1, child under 13 who is a citizen and dependent. + period: 2025 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + ri_ccap_eligible_child: [false, true] + +- name: Case 2, child age 13 ineligible without disability. + period: 2025 + input: + people: + person1: + age: 35 + person2: + age: 13 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + ri_ccap_eligible_child: [false, false] + +- name: Case 3, disabled child age 15 eligible. + period: 2025 + input: + people: + person1: + age: 40 + person2: + age: 15 + is_tax_unit_dependent: true + is_disabled: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + ri_ccap_eligible_child: [false, true] + +- name: Case 4, disabled child age 18 ineligible. + period: 2025 + input: + people: + person1: + age: 45 + person2: + age: 18 + is_tax_unit_dependent: true + is_disabled: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + ri_ccap_eligible_child: [false, false] + +- name: Case 5, child who is not a dependent is ineligible. + period: 2025 + input: + people: + person1: + age: 30 + person2: + age: 8 + is_tax_unit_dependent: false + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + ri_ccap_eligible_child: [false, false] + +- name: Case 6, undocumented child ineligible. + period: 2025 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: UNDOCUMENTED + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + ri_ccap_eligible_child: [false, false] + +- name: Case 7, adult is never an eligible child. + period: 2025 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1] + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_eligible_child: [false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_immigration_status_eligible_child.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_immigration_status_eligible_child.yaml new file mode 100644 index 00000000000..d185edb0909 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_immigration_status_eligible_child.yaml @@ -0,0 +1,129 @@ +- name: Case 1, citizen child is eligible. + period: 2025 + input: + people: + person1: + immigration_status: CITIZEN + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_immigration_status_eligible_child: [true] + +- name: Case 2, legal permanent resident child is eligible. + period: 2025 + input: + people: + person1: + immigration_status: LEGAL_PERMANENT_RESIDENT + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_immigration_status_eligible_child: [true] + +- name: Case 3, refugee child is eligible. + period: 2025 + input: + people: + person1: + immigration_status: REFUGEE + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_immigration_status_eligible_child: [true] + +- name: Case 4, asylee child is eligible. + period: 2025 + input: + people: + person1: + immigration_status: ASYLEE + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_immigration_status_eligible_child: [true] + +- name: Case 5, undocumented child is not eligible. + period: 2025 + input: + people: + person1: + immigration_status: UNDOCUMENTED + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_immigration_status_eligible_child: [false] + +- name: Case 6, DACA child is not eligible. + period: 2025 + input: + people: + person1: + immigration_status: DACA + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_immigration_status_eligible_child: [false] + +- name: Case 7, Cuban Haitian entrant child is eligible. + period: 2025 + input: + people: + person1: + immigration_status: CUBAN_HAITIAN_ENTRANT + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_immigration_status_eligible_child: [true] + +- name: Case 8, conditional entrant child is eligible. + period: 2025 + input: + people: + person1: + immigration_status: CONDITIONAL_ENTRANT + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_immigration_status_eligible_child: [true] + +- name: Case 9, paroled for one year child is eligible. + period: 2025 + input: + people: + person1: + immigration_status: PAROLED_ONE_YEAR + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_immigration_status_eligible_child: [true] + +- name: Case 10, TPS child is not eligible. + period: 2025 + input: + people: + person1: + immigration_status: TPS + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_immigration_status_eligible_child: [false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_income_eligible.yaml new file mode 100644 index 00000000000..9199285fd43 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_income_eligible.yaml @@ -0,0 +1,140 @@ +# 2025 FPG family of 3 (contiguous US): 15_650 + 5_500 * 2 = 26_650 +# 261% FPL = 26_650 * 2.61 = 69_556.50 +# 300% FPL = 26_650 * 3.00 = 79_950.00 + +- name: Case 1, new applicant income below 261 percent FPL. + period: 2025 + absolute_error_margin: 0 + input: + people: + person1: + age: 30 + employment_income: 50_000 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # income 50,000 <= 69,556.50 (261% of 26,650) -> eligible + ri_ccap_income_eligible: true + +- name: Case 2, new applicant income above 261 percent FPL. + period: 2025 + absolute_error_margin: 0 + input: + people: + person1: + age: 30 + employment_income: 70_000 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # income 70,000 > 69,556.50 (261% of 26,650) -> ineligible + ri_ccap_income_eligible: false + +- name: Case 3, enrolled family income between 261 and 300 percent FPL. + period: 2025 + absolute_error_margin: 0 + input: + people: + person1: + age: 30 + employment_income: 75_000 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + ri_ccap_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # enrolled: income 75,000 <= 79,950 (300% of 26,650) -> eligible + ri_ccap_income_eligible: true + +- name: Case 4, enrolled family income above 300 percent FPL. + period: 2025 + absolute_error_margin: 0 + input: + people: + person1: + age: 30 + employment_income: 80_000 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + ri_ccap_enrolled: true + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # enrolled: income 80,000 > 79,950 (300% of 26,650) -> ineligible + ri_ccap_income_eligible: false + +- name: Case 5, non-enrolled family between 261 and 300 percent FPL. + period: 2025 + absolute_error_margin: 0 + input: + people: + person1: + age: 30 + employment_income: 75_000 + person2: + age: 5 + person3: + age: 3 + spm_units: + spm_unit: + members: [person1, person2, person3] + ri_ccap_enrolled: false + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # not enrolled: income 75,000 > 69,556.50 (261% of 26,650) -> ineligible + ri_ccap_income_eligible: false + +- name: Case 6, zero income family is eligible. + period: 2025 + absolute_error_margin: 0 + input: + people: + person1: + age: 30 + person2: + age: 5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + ri_ccap_income_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/integration.yaml new file mode 100644 index 00000000000..698bd033458 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/integration.yaml @@ -0,0 +1,422 @@ +# RI CCAP Integration Tests +# 2025 FPG (Contiguous US): +# first_person = 15_650, additional = 5_500 +# Family of 2: 21_150 +# Family of 3: 26_650 +# Family of 4: 32_150 + +- name: Case 1, basic eligible family with licensed center care. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 35 + employment_income: 40_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: false + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_3 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 13_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # === Eligibility === + # Child age 4 < 13 -> age eligible + # Citizen -> immigration eligible + # Dependent -> eligible child + ri_ccap_eligible_child: [false, true] + + # FPG family of 2: 21_150 + # Income 40,000, 261% FPL = 21_150 * 2.61 = 55_201.50 + # 40,000 <= 55,201.50 -> income eligible + ri_ccap_income_eligible: true + + # Assets default 0 <= 1,000,000 -> asset eligible + ri_ccap_asset_eligible: true + + ri_ccap_eligible: true + + # === Copay === + # FPL ratio = 40,000 / 21,150 = 1.8913 -> 7% copay + ri_ccap_fpl_copay_rate: 0.07 + # copay = 40,000 * 0.07 = 2,800 + ri_ccap_copay: 2_800 + + # === Provider rates === + # Center age: 4 years, not in school -> PRESCHOOL + ri_ccap_center_age_group: [PRESCHOOL, PRESCHOOL] + # Parent: 0 hrs/wk -> QUARTER_TIME; Child: 35 hrs/wk -> FULL_TIME + ri_ccap_time_category: [QUARTER_TIME, FULL_TIME] + # Center FT Star 3 Preschool = $255 + ri_ccap_maximum_weekly_benefit: [0, 255] + + # === Benefit === + # max annual = 255 * 52 = 13,260 + # uncapped = max(13,000 - 2,800, 0) = 10,200 + # benefit = min(10,200, 13,260) = 10,200 + ri_ccap: 10_200 + +- name: Case 2, low income family with zero copay. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + employment_income: 18_000 + immigration_status: CITIZEN + person2: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_2 + person3: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: false + childcare_hours_per_week: 30 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_2 + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + spm_unit_pre_subsidy_childcare_expenses: 25_000 + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # === Eligibility === + ri_ccap_eligible_child: [false, true, true] + + # FPG family of 3: 26,650 + # 18,000 <= 26,650 * 2.61 = 69,556.50 -> eligible + ri_ccap_income_eligible: true + ri_ccap_asset_eligible: true + ri_ccap_eligible: true + + # === Copay === + # FPL ratio = 18,000 / 26,650 = 0.6754 -> 0% copay + ri_ccap_fpl_copay_rate: 0 + ri_ccap_copay: 0 + + # === Provider rates === + # child1 (age 1): INFANT center group, FT Star 2 = $341 + # child2 (age 5, not in school): PRESCHOOL center group, FT Star 2 = $247 + ri_ccap_center_age_group: [PRESCHOOL, INFANT, PRESCHOOL] + # Parent: 0 hrs/wk -> QUARTER_TIME; Children: FT + ri_ccap_time_category: [QUARTER_TIME, FULL_TIME, FULL_TIME] + ri_ccap_maximum_weekly_benefit: [0, 341, 247] + + # === Benefit === + # max annual per child: 341*52 = 17,732 + 247*52 = 12,844 = 30,576 + # uncapped = max(25,000 - 0, 0) = 25,000 + # benefit = min(25,000, 30,576) = 25,000 + ri_ccap: 25_000 + +- name: Case 3, enrolled family at transitional FPL level. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 32 + employment_income: 72_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: LEGAL_PERMANENT_RESIDENT + is_in_k12_school: false + childcare_hours_per_week: 25 + ri_ccap_provider_type: LICENSED_FAMILY + ri_ccap_star_rating: STAR_4 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + ri_ccap_enrolled: true + spm_unit_pre_subsidy_childcare_expenses: 10_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # === Eligibility === + ri_ccap_eligible_child: [false, true] + + # FPG family of 2: 21,150 + # 261% = 55,201.50, 300% = 63,450 + # 72,000 > 55,201.50 but enrolled, so use 300% + # 72,000 > 63,450 -> ineligible even for transitional + ri_ccap_income_eligible: false + + ri_ccap_asset_eligible: true + ri_ccap_eligible: false + + # === Benefit === + # Not eligible -> 0 + ri_ccap: 0 + +- name: Case 4, enrolled family within transitional range. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 32 + employment_income: 60_000 + immigration_status: CITIZEN + person2: + age: 3 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: false + childcare_hours_per_week: 25 + ri_ccap_provider_type: LICENSED_FAMILY + ri_ccap_star_rating: STAR_4 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + ri_ccap_enrolled: true + spm_unit_pre_subsidy_childcare_expenses: 10_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # === Eligibility === + ri_ccap_eligible_child: [false, true] + + # FPG family of 2: 21,150 + # 300% = 63,450 + # enrolled: 60,000 <= 63,450 -> eligible + ri_ccap_income_eligible: true + ri_ccap_asset_eligible: true + ri_ccap_eligible: true + + # === Copay === + # FPL ratio = 60,000 / 21,150 = 2.8369 -> 7% copay + ri_ccap_fpl_copay_rate: 0.07 + # copay = 60,000 * 0.07 = 4,200 + ri_ccap_copay: 4_200 + + # === Provider rates === + # age 3, not in school -> PRESCHOOL family group + ri_ccap_family_age_group: [PRESCHOOL, PRESCHOOL] + # Parent: 0 hrs/wk -> QUARTER_TIME; Child: 25 hrs -> THREE_QUARTER_TIME + ri_ccap_time_category: [QUARTER_TIME, THREE_QUARTER_TIME] + # Family 3QT Star 4 Preschool = $188.33 + ri_ccap_maximum_weekly_benefit: [0, 188.33] + + # === Benefit === + # max annual = 188.33 * 52 = 9,793.16 + # uncapped = max(10,000 - 4,200, 0) = 5,800 + # benefit = min(5,800, 9,793.16) = 5,800 + ri_ccap: 5_800 + +- name: Case 5, housing insecure family with license exempt care. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 25 + employment_income: 35_000 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: REFUGEE + childcare_hours_per_week: 15 + ri_ccap_provider_type: LICENSE_EXEMPT + ri_ccap_step_rating: STEP_2 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 3_000 + households: + household: + members: [person1, person2] + state_code: RI + is_homeless: true + output: + # === Eligibility === + ri_ccap_eligible_child: [false, true] + ri_ccap_immigration_status_eligible_child: [true, true] + + # FPG family of 2: 21,150 + # 35,000 <= 55,201.50 (261%) -> eligible + ri_ccap_income_eligible: true + ri_ccap_asset_eligible: true + ri_ccap_eligible: true + + # === Copay === + # Housing insecure -> $0 copay + ri_ccap_copay: 0 + + # === Provider rates === + # Parent: not in school -> PRESCHOOL; Child age 2 -> INFANT_TODDLER + ri_ccap_family_age_group: [PRESCHOOL, INFANT_TODDLER] + # Parent: 0 hrs/wk -> QUARTER_TIME; Child: 15 hrs -> HALF_TIME + ri_ccap_time_category: [QUARTER_TIME, HALF_TIME] + # Exempt HT Step 2 Infant/Toddler = $50.98 + ri_ccap_maximum_weekly_benefit: [0, 50.98] + + # === Benefit === + # max annual = 50.98 * 52 = 2,650.96 + # uncapped = max(3,000 - 0, 0) = 3,000 + # benefit = min(3,000, 2,650.96) = 2,650.96 + ri_ccap: 2_650.96 + +- name: Case 6, disabled teenager with family day care. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 45 + employment_income: 45_000 + immigration_status: CITIZEN + person2: + age: 15 + is_tax_unit_dependent: true + is_disabled: true + immigration_status: CITIZEN + is_in_k12_school: true + childcare_hours_per_week: 20 + ri_ccap_provider_type: LICENSED_FAMILY + ri_ccap_star_rating: STAR_3 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 8_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # === Eligibility === + # age 15 < 18 (disabled threshold) -> age eligible + ri_ccap_eligible_child: [false, true] + + # FPG family of 2: 21,150 + # 45,000 <= 55,201.50 -> income eligible + ri_ccap_income_eligible: true + ri_ccap_asset_eligible: true + ri_ccap_eligible: true + + # === Copay === + # FPL ratio = 45,000 / 21,150 = 2.1277 -> 7% copay + ri_ccap_fpl_copay_rate: 0.07 + # copay = 45,000 * 0.07 = 3,150 + ri_ccap_copay: 3_150 + + # === Provider rates === + # Parent: not in school -> PRESCHOOL; Child age 15, in school -> SCHOOL_AGE + ri_ccap_family_age_group: [PRESCHOOL, SCHOOL_AGE] + # Parent: 0 hrs/wk -> QUARTER_TIME; Child: 20 hrs -> THREE_QUARTER_TIME + ri_ccap_time_category: [QUARTER_TIME, THREE_QUARTER_TIME] + # Family 3QT Star 3 School Age = $161.54 + ri_ccap_maximum_weekly_benefit: [0, 161.54] + + # === Benefit === + # max annual = 161.54 * 52 = 8,400.08 + # uncapped = max(8,000 - 3,150, 0) = 4,850 + # benefit = min(4,850, 8,400.08) = 4,850 + ri_ccap: 4_850 + +- name: Case 7, two children with different provider types. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 30_000 + immigration_status: CITIZEN + person2: + age: 1 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_4 + person3: + age: 8 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: true + childcare_hours_per_week: 10 + ri_ccap_provider_type: LICENSE_EXEMPT + ri_ccap_step_rating: STEP_1 + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + spm_unit_pre_subsidy_childcare_expenses: 15_000 + households: + household: + members: [person1, person2, person3] + state_code: RI + output: + # === Eligibility === + ri_ccap_eligible_child: [false, true, true] + + # FPG family of 3: 26,650 + # 30,000 <= 69,556.50 -> eligible + ri_ccap_income_eligible: true + ri_ccap_eligible: true + + # === Copay === + # FPL ratio = 30,000 / 26,650 = 1.1257 -> 2% copay + ri_ccap_fpl_copay_rate: 0.02 + # copay = 30,000 * 0.02 = 600 + ri_ccap_copay: 600 + + # === Provider rates === + # child1 (age 1): Center FT Star 4 Infant = $364 + # child2 (age 8, in school): Exempt HT Step 1 School Age = $29.40 + ri_ccap_center_age_group: [PRESCHOOL, INFANT, SCHOOL_AGE] + # Parent: 0 hrs/wk -> QUARTER_TIME; child1: 35 hrs -> FULL_TIME; child2: 10 hrs -> HALF_TIME + ri_ccap_time_category: [QUARTER_TIME, FULL_TIME, HALF_TIME] + ri_ccap_maximum_weekly_benefit: [0, 364, 29.40] + + # === Benefit === + # max annual = (364 + 29.40) * 52 = 393.40 * 52 = 20,456.80 + # uncapped = max(15,000 - 600, 0) = 14,400 + # benefit = min(14,400, 20,456.80) = 14,400 + ri_ccap: 14_400 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap.yaml new file mode 100644 index 00000000000..d7f6fbb72d6 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap.yaml @@ -0,0 +1,213 @@ +# ri_ccap: SPMUnit, float, YEAR +# benefit = min(max(pre_subsidy_childcare_expenses - copay, 0), max_weekly_benefit * 52) +# 2025 FPG family of 3: 15_650 + 5_500 * 2 = 26_650 + +- name: Case 1, basic eligible family with childcare expenses. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 30_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: false + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 12_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # FPG family of 2: 15_650 + 5_500 = 21_150 + # FPL ratio = 30_000 / 21_150 = 1.4184 -> 5% copay rate + # copay = 30_000 * 0.05 = 1_500 + # max weekly = $236 (Center FT Star 1 Preschool) + # max annual = 236 * 52 = 12_272 + # uncapped = max(12_000 - 1_500, 0) = 10_500 + # benefit = min(10_500, 12_272) = 10_500 + ri_ccap: 10_500 + +- name: Case 2, ineligible family gets zero. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 70_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 12_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # income 70,000 > 261% FPL of 21,150 = 55,201.50 -> ineligible + ri_ccap: 0 + +- name: Case 3, benefit capped at maximum annual rate. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 15_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: false + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 20_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # FPG family of 2: 21_150 + # FPL ratio = 15_000 / 21_150 = 0.709 -> 0% copay rate + # copay = 0 + # max weekly = $236 (Center FT Star 1 Preschool) + # max annual = 236 * 52 = 12_272 + # uncapped = max(20_000 - 0, 0) = 20_000 + # benefit = min(20_000, 12_272) = 12_272 + ri_ccap: 12_272 + +- name: Case 4, zero childcare expenses gives zero benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 0 + households: + household: + members: [person1, person2] + state_code: RI + output: + ri_ccap: 0 + +- name: Case 5, TANF enrolled gets zero copay and full subsidy. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 15_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: false + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 10_000 + is_tanf_enrolled: true + households: + household: + members: [person1, person2] + state_code: RI + output: + # TANF enrolled -> copay = 0 + # max weekly = $236 (Center FT Star 1 Preschool) + # max annual = 236 * 52 = 12_272 + # uncapped = max(10_000 - 0, 0) = 10_000 + # benefit = min(10_000, 12_272) = 10_000 + ri_ccap: 10_000 + +- name: Case 6, copay exceeds expenses gives zero benefit. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 50_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + is_in_k12_school: false + childcare_hours_per_week: 5 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_pre_subsidy_childcare_expenses: 2_000 + households: + household: + members: [person1, person2] + state_code: RI + output: + # FPG family of 2: 21_150 + # FPL ratio = 50_000 / 21_150 = 2.364 -> 7% copay rate + # copay = 50_000 * 0.07 = 3_500 + # uncapped = max(2_000 - 3_500, 0) = 0 + # benefit = 0 + ri_ccap: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_center_age_group.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_center_age_group.yaml new file mode 100644 index 00000000000..6cfecfe3691 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_center_age_group.yaml @@ -0,0 +1,100 @@ +# Center age groups: +# Infant: age < 2 +# Toddler: age 2 (i.e., age < 3) +# Preschool: age 3+ and not in K-12 school +# School Age: in K-12 school + +- name: Case 1, infant age 1. + period: 2025 + input: + people: + person1: + age: 1 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_center_age_group: INFANT + +- name: Case 2, toddler age 2. + period: 2025 + input: + people: + person1: + age: 2 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_center_age_group: TODDLER + +- name: Case 3, preschool age 4 not in school. + period: 2025 + input: + people: + person1: + age: 4 + is_in_k12_school: false + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_center_age_group: PRESCHOOL + +- name: Case 4, school age child in K-12. + period: 2025 + input: + people: + person1: + age: 7 + is_in_k12_school: true + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_center_age_group: SCHOOL_AGE + +- name: Case 5, preschool age 3 not in school. + period: 2025 + input: + people: + person1: + age: 3 + is_in_k12_school: false + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_center_age_group: PRESCHOOL + +- name: Case 6, age 5 in school is school age. + period: 2025 + input: + people: + person1: + age: 5 + is_in_k12_school: true + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_center_age_group: SCHOOL_AGE + +- name: Case 7, age 0 is infant. + period: 2025 + input: + people: + person1: + age: 0 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_center_age_group: INFANT diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_family_age_group.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_family_age_group.yaml new file mode 100644 index 00000000000..b392fe09316 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_family_age_group.yaml @@ -0,0 +1,85 @@ +# Family/Exempt age groups: +# Infant/Toddler: age < 3 +# Preschool: age 3+ and not in K-12 school +# School Age: in K-12 school + +- name: Case 1, infant toddler age 1. + period: 2025 + input: + people: + person1: + age: 1 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_family_age_group: INFANT_TODDLER + +- name: Case 2, infant toddler age 2. + period: 2025 + input: + people: + person1: + age: 2 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_family_age_group: INFANT_TODDLER + +- name: Case 3, preschool age 4 not in school. + period: 2025 + input: + people: + person1: + age: 4 + is_in_k12_school: false + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_family_age_group: PRESCHOOL + +- name: Case 4, school age child in K-12. + period: 2025 + input: + people: + person1: + age: 7 + is_in_k12_school: true + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_family_age_group: SCHOOL_AGE + +- name: Case 5, preschool age 3 not in school. + period: 2025 + input: + people: + person1: + age: 3 + is_in_k12_school: false + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_family_age_group: PRESCHOOL + +- name: Case 6, age 0 is infant toddler. + period: 2025 + input: + people: + person1: + age: 0 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_family_age_group: INFANT_TODDLER diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_maximum_weekly_benefit.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_maximum_weekly_benefit.yaml new file mode 100644 index 00000000000..b9c7cac85f8 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_maximum_weekly_benefit.yaml @@ -0,0 +1,286 @@ +# Tests for ri_ccap_maximum_weekly_benefit +# Rates effective: center July 2025, family July 2024, exempt Jan 2022 +# Person-level variable; parent output is 0 (default), child gets rate + +- name: Case 1, licensed center full time star 1 preschool. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + is_in_k12_school: false + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_1 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Center FT Star 1 Preschool = $236 + ri_ccap_maximum_weekly_benefit: [0, 236] + +- name: Case 2, licensed center full time star 5 infant. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 1 + childcare_hours_per_week: 40 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Center FT Star 5 Infant = $378 + ri_ccap_maximum_weekly_benefit: [0, 378] + +- name: Case 3, licensed center three quarter time star 3 toddler. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 2 + childcare_hours_per_week: 25 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_3 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Center 3QT Star 3 Toddler = $222.00 + ri_ccap_maximum_weekly_benefit: [0, 222] + +- name: Case 4, licensed center half time star 4 school age. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 8 + is_in_k12_school: true + childcare_hours_per_week: 15 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_4 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Center HT Star 4 School Age = $125.00 + ri_ccap_maximum_weekly_benefit: [0, 125] + +- name: Case 5, licensed family full time star 2 infant toddler. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 1 + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSED_FAMILY + ri_ccap_star_rating: STAR_2 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Family FT Star 2 Infant/Toddler = $266.86 + ri_ccap_maximum_weekly_benefit: [0, 266.86] + +- name: Case 6, licensed family quarter time star 4 preschool. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + is_in_k12_school: false + childcare_hours_per_week: 5 + ri_ccap_provider_type: LICENSED_FAMILY + ri_ccap_star_rating: STAR_4 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Family QT Star 4 Preschool = $62.78 + ri_ccap_maximum_weekly_benefit: [0, 62.78] + +- name: Case 7, licensed family three quarter time star 5 school age. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 8 + is_in_k12_school: true + childcare_hours_per_week: 22 + ri_ccap_provider_type: LICENSED_FAMILY + ri_ccap_star_rating: STAR_5 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Family 3QT Star 5 School Age = $185.18 + ri_ccap_maximum_weekly_benefit: [0, 185.18] + +- name: Case 8, license exempt full time step 1 infant toddler. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 2 + childcare_hours_per_week: 35 + ri_ccap_provider_type: LICENSE_EXEMPT + ri_ccap_step_rating: STEP_1 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Exempt FT Step 1 Infant/Toddler = $100.96 + ri_ccap_maximum_weekly_benefit: [0, 100.96] + +- name: Case 9, license exempt half time step 3 preschool. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 4 + is_in_k12_school: false + childcare_hours_per_week: 12 + ri_ccap_provider_type: LICENSE_EXEMPT + ri_ccap_step_rating: STEP_3 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Exempt HT Step 3 Preschool = $30.54 + ri_ccap_maximum_weekly_benefit: [0, 30.54] + +- name: Case 10, license exempt quarter time step 4 school age. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 8 + is_in_k12_school: true + childcare_hours_per_week: 5 + ri_ccap_provider_type: LICENSE_EXEMPT + ri_ccap_step_rating: STEP_4 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Exempt QT Step 4 School Age = $15.13 + ri_ccap_maximum_weekly_benefit: [0, 15.13] + +- name: Case 11, licensed center quarter time star 2 infant. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 1 + childcare_hours_per_week: 8 + ri_ccap_provider_type: LICENSED_CENTER + ri_ccap_star_rating: STAR_2 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Center QT Star 2 Infant = $85.25 + ri_ccap_maximum_weekly_benefit: [0, 85.25] + +- name: Case 12, license exempt three quarter time step 2 school age. + period: 2025 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + person2: + age: 7 + is_in_k12_school: true + childcare_hours_per_week: 22 + ri_ccap_provider_type: LICENSE_EXEMPT + ri_ccap_step_rating: STEP_2 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: RI + output: + # Exempt 3QT Step 2 School Age = $44.53 + ri_ccap_maximum_weekly_benefit: [0, 44.53] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_time_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_time_category.yaml new file mode 100644 index 00000000000..aa2a29cb91e --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/ri_ccap_time_category.yaml @@ -0,0 +1,135 @@ +# Time authorization thresholds: +# 0-9 hrs -> QUARTER_TIME (enum index 4) +# 10-19 hrs -> HALF_TIME (enum index 3) +# 20-29 hrs -> THREE_QUARTER_TIME (enum index 2) +# 30+ hrs -> FULL_TIME (enum index 1) + +- name: Case 1, full time 35 hours per week. + period: 2025 + input: + people: + person1: + childcare_hours_per_week: 35 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_time_category: FULL_TIME + +- name: Case 2, full time exactly 30 hours per week. + period: 2025 + input: + people: + person1: + childcare_hours_per_week: 30 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_time_category: FULL_TIME + +- name: Case 3, three quarter time 25 hours per week. + period: 2025 + input: + people: + person1: + childcare_hours_per_week: 25 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_time_category: THREE_QUARTER_TIME + +- name: Case 4, three quarter time exactly 20 hours per week. + period: 2025 + input: + people: + person1: + childcare_hours_per_week: 20 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_time_category: THREE_QUARTER_TIME + +- name: Case 5, half time 15 hours per week. + period: 2025 + input: + people: + person1: + childcare_hours_per_week: 15 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_time_category: HALF_TIME + +- name: Case 6, half time exactly 10 hours per week. + period: 2025 + input: + people: + person1: + childcare_hours_per_week: 10 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_time_category: HALF_TIME + +- name: Case 7, quarter time 5 hours per week. + period: 2025 + input: + people: + person1: + childcare_hours_per_week: 5 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_time_category: QUARTER_TIME + +- name: Case 8, quarter time zero hours per week. + period: 2025 + input: + people: + person1: + childcare_hours_per_week: 0 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_time_category: QUARTER_TIME + +- name: Case 9, boundary at 29 hours is three quarter time. + period: 2025 + input: + people: + person1: + childcare_hours_per_week: 29 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_time_category: THREE_QUARTER_TIME + +- name: Case 10, boundary at 9 hours is quarter time. + period: 2025 + input: + people: + person1: + childcare_hours_per_week: 9 + households: + household: + members: [person1] + state_code: RI + output: + ri_ccap_time_category: QUARTER_TIME diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/copay/ri_ccap_copay.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/copay/ri_ccap_copay.py new file mode 100644 index 00000000000..0323abaa88d --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/copay/ri_ccap_copay.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class ri_ccap_copay(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "Rhode Island CCAP family co-payment" + definition_period = YEAR + defined_for = StateCode.RI + reference = ( + "https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.6.1", + "https://dhs.ri.gov/media/10606/download?language=en", + ) + + def formula(spm_unit, period, parameters): + # RI Works recipients and housing insecure families pay $0. + is_tanf_enrolled = spm_unit("is_tanf_enrolled", period) + is_homeless = spm_unit.household("is_homeless", period) + exempt_from_copay = is_tanf_enrolled | is_homeless + + copay_rate = spm_unit("ri_ccap_fpl_copay_rate", period) + countable_income = spm_unit("ri_ccap_countable_income", period) + copay = countable_income * copay_rate + + return where(exempt_from_copay, 0, copay) diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/copay/ri_ccap_fpl_copay_rate.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/copay/ri_ccap_fpl_copay_rate.py new file mode 100644 index 00000000000..a3e34746981 --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/copay/ri_ccap_fpl_copay_rate.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class ri_ccap_fpl_copay_rate(Variable): + value_type = float + entity = SPMUnit + label = "Rhode Island CCAP co-share rate based on FPL level" + definition_period = YEAR + unit = "/1" + defined_for = StateCode.RI + reference = "https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.6.1" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ri.dhs.ccap.copay + countable_income = spm_unit("ri_ccap_countable_income", period) + fpg = spm_unit("spm_unit_fpg", period) + fpl_ratio = where(fpg > 0, countable_income / fpg, 0) + return p.rate.calc(fpl_ratio) diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_asset_eligible.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_asset_eligible.py new file mode 100644 index 00000000000..0c3f1718e6a --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_asset_eligible.py @@ -0,0 +1,15 @@ +from policyengine_us.model_api import * + + +class ri_ccap_asset_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Rhode Island CCAP based on assets" + definition_period = YEAR + defined_for = StateCode.RI + reference = "https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.6.1" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ri.dhs.ccap.assets + assets = spm_unit("ri_ccap_assets", period) + return assets <= p.limit diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible.py new file mode 100644 index 00000000000..aa9785bb2f3 --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class ri_ccap_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Rhode Island CCAP" + definition_period = YEAR + defined_for = StateCode.RI + reference = ( + "https://rules.sos.ri.gov/regulations/part/218-20-00-4", + "https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.5", + ) + + def formula(spm_unit, period, parameters): + has_eligible_child = add(spm_unit, period, ["ri_ccap_eligible_child"]) > 0 + income_eligible = spm_unit("ri_ccap_income_eligible", period) + asset_eligible = spm_unit("ri_ccap_asset_eligible", period) + # RI Works (TANF) recipients are categorically eligible. + ri_works_categorical = spm_unit("is_tanf_enrolled", period) + return has_eligible_child & ( + (income_eligible & asset_eligible) | ri_works_categorical + ) diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.py new file mode 100644 index 00000000000..8642c1bb19b --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class ri_ccap_eligible_child(Variable): + value_type = bool + entity = Person + label = "Eligible child for Rhode Island CCAP" + definition_period = YEAR + defined_for = StateCode.RI + reference = "https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.3.1" + + def formula(person, period, parameters): + p = parameters(period).gov.states.ri.dhs.ccap.age_threshold + age = person("age", period) + is_disabled = person("is_disabled", period) + age_limit = where(is_disabled, p.disabled_child, p.child) + age_eligible = age < age_limit + is_dependent = person("is_tax_unit_dependent", period) + immigration_eligible = person( + "ri_ccap_immigration_status_eligible_child", period + ) + return age_eligible & is_dependent & immigration_eligible diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_immigration_status_eligible_child.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_immigration_status_eligible_child.py new file mode 100644 index 00000000000..bed3cc8c881 --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_immigration_status_eligible_child.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class ri_ccap_immigration_status_eligible_child(Variable): + value_type = bool + entity = Person + label = "Eligible child for Rhode Island CCAP based on immigration status" + definition_period = YEAR + defined_for = StateCode.RI + reference = "https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.3.1" + + def formula(person, period, parameters): + p = parameters(period).gov.states.ri.dhs.ccap + immigration_status = person("immigration_status", period) + immigration_status_str = immigration_status.decode_to_str() + return np.isin( + immigration_status_str, + p.qualified_immigration_statuses, + ) diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_income_eligible.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_income_eligible.py new file mode 100644 index 00000000000..6613f654acb --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_income_eligible.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class ri_ccap_income_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Rhode Island CCAP based on income" + definition_period = YEAR + defined_for = StateCode.RI + reference = "https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.6.1" + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ri.dhs.ccap.income.fpl_rate + countable_income = spm_unit("ri_ccap_countable_income", period) + fpg = spm_unit("spm_unit_fpg", period) + enrolled = spm_unit("ri_ccap_enrolled", period) + initial_limit = fpg * p.initial_eligibility + transitional_limit = fpg * p.transitional + income_limit = where( + enrolled, + transitional_limit, + initial_limit, + ) + return countable_income <= income_limit diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap.py new file mode 100644 index 00000000000..2112b534a58 --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class ri_ccap(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "Rhode Island CCAP benefit amount" + definition_period = YEAR + defined_for = "ri_ccap_eligible" + reference = "https://rules.sos.ri.gov/regulations/part/218-20-00-4" + + def formula(spm_unit, period, parameters): + copay = spm_unit("ri_ccap_copay", period) + maximum_weekly_benefit = add( + spm_unit, period, ["ri_ccap_maximum_weekly_benefit"] + ) + maximum_annual_benefit = maximum_weekly_benefit * WEEKS_IN_YEAR + pre_subsidy_childcare_expenses = spm_unit( + "spm_unit_pre_subsidy_childcare_expenses", period + ) + uncapped = max_(pre_subsidy_childcare_expenses - copay, 0) + return min_(uncapped, maximum_annual_benefit) diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_assets.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_assets.py new file mode 100644 index 00000000000..ce14683a7c0 --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_assets.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class ri_ccap_assets(Variable): + value_type = float + entity = SPMUnit + label = "Rhode Island CCAP countable assets" + definition_period = YEAR + unit = USD + defined_for = StateCode.RI + reference = "https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.6.1" + + adds = "gov.states.ri.dhs.ccap.assets.sources" diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_center_age_group.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_center_age_group.py new file mode 100644 index 00000000000..d073b9de8e2 --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_center_age_group.py @@ -0,0 +1,37 @@ +from policyengine_us.model_api import * + + +class RICCAPCenterAgeGroup(Enum): + INFANT = "Infant" + TODDLER = "Toddler" + PRESCHOOL = "Preschool" + SCHOOL_AGE = "School Age" + + +class ri_ccap_center_age_group(Variable): + value_type = Enum + entity = Person + possible_values = RICCAPCenterAgeGroup + default_value = RICCAPCenterAgeGroup.PRESCHOOL + definition_period = YEAR + label = "Rhode Island CCAP licensed center age group" + defined_for = StateCode.RI + reference = "https://dhs.ri.gov/media/9356/download?language=en" + + def formula(person, period, parameters): + p = parameters(period).gov.states.ri.dhs.ccap.age_group.center + age = person("age", period) + is_in_school = person("is_in_k12_school", period) + return select( + [ + age < p.infant_max, + age < p.toddler_max, + ~is_in_school, + ], + [ + RICCAPCenterAgeGroup.INFANT, + RICCAPCenterAgeGroup.TODDLER, + RICCAPCenterAgeGroup.PRESCHOOL, + ], + default=RICCAPCenterAgeGroup.SCHOOL_AGE, + ) diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_countable_income.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_countable_income.py new file mode 100644 index 00000000000..d64e8a05892 --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_countable_income.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class ri_ccap_countable_income(Variable): + value_type = float + entity = SPMUnit + label = "Rhode Island CCAP countable income" + definition_period = YEAR + unit = USD + defined_for = StateCode.RI + reference = "https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.2" + + adds = "gov.states.ri.dhs.ccap.income.countable_income.sources" diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_enrolled.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_enrolled.py new file mode 100644 index 00000000000..3486f624f4f --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_enrolled.py @@ -0,0 +1,9 @@ +from policyengine_us.model_api import * + + +class ri_ccap_enrolled(Variable): + value_type = bool + entity = SPMUnit + definition_period = YEAR + label = "Whether the family is currently enrolled in Rhode Island CCAP" + defined_for = StateCode.RI diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_family_age_group.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_family_age_group.py new file mode 100644 index 00000000000..664da7ed709 --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_family_age_group.py @@ -0,0 +1,37 @@ +from policyengine_us.model_api import * + + +class RICCAPFamilyAgeGroup(Enum): + INFANT_TODDLER = "Infant/Toddler" + PRESCHOOL = "Preschool" + SCHOOL_AGE = "School Age" + + +class ri_ccap_family_age_group(Variable): + value_type = Enum + entity = Person + possible_values = RICCAPFamilyAgeGroup + default_value = RICCAPFamilyAgeGroup.PRESCHOOL + definition_period = YEAR + label = "Rhode Island CCAP licensed family and exempt age group" + defined_for = StateCode.RI + reference = ( + "https://dhs.ri.gov/media/7481/download?language=en", + "https://dhs.ri.gov/media/3556/download?language=en", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ri.dhs.ccap.age_group.family + age = person("age", period) + is_in_school = person("is_in_k12_school", period) + return select( + [ + age < p.infant_toddler_max, + ~is_in_school, + ], + [ + RICCAPFamilyAgeGroup.INFANT_TODDLER, + RICCAPFamilyAgeGroup.PRESCHOOL, + ], + default=RICCAPFamilyAgeGroup.SCHOOL_AGE, + ) diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_maximum_weekly_benefit.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_maximum_weekly_benefit.py new file mode 100644 index 00000000000..3230c03b644 --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_maximum_weekly_benefit.py @@ -0,0 +1,45 @@ +from policyengine_us.model_api import * +from policyengine_us.variables.gov.states.ri.dhs.ccap.ri_ccap_provider_type import ( + RICCAPProviderType, +) + + +class ri_ccap_maximum_weekly_benefit(Variable): + value_type = float + entity = Person + unit = USD + label = "Rhode Island CCAP maximum weekly benefit per child" + definition_period = YEAR + defined_for = "ri_ccap_eligible_child" + reference = ( + "https://dhs.ri.gov/media/9356/download?language=en", + "https://dhs.ri.gov/media/7481/download?language=en", + "https://dhs.ri.gov/media/3556/download?language=en", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ri.dhs.ccap.rates + provider_type = person("ri_ccap_provider_type", period) + time_category = person("ri_ccap_time_category", period) + + center_age = person("ri_ccap_center_age_group", period) + star_rating = person("ri_ccap_star_rating", period) + center_rate = p.center[time_category][star_rating][center_age] + + family_age = person("ri_ccap_family_age_group", period) + family_rate = p.family[time_category][star_rating][family_age] + + step_rating = person("ri_ccap_step_rating", period) + exempt_rate = p.exempt[time_category][step_rating][family_age] + + return select( + [ + provider_type == RICCAPProviderType.LICENSED_CENTER, + provider_type == RICCAPProviderType.LICENSED_FAMILY, + ], + [ + center_rate, + family_rate, + ], + default=exempt_rate, + ) diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_provider_type.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_provider_type.py new file mode 100644 index 00000000000..cba31e97281 --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_provider_type.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class RICCAPProviderType(Enum): + LICENSED_CENTER = "Licensed Center" + LICENSED_FAMILY = "Licensed Family" + LICENSE_EXEMPT = "License Exempt" + + +class ri_ccap_provider_type(Variable): + value_type = Enum + entity = Person + possible_values = RICCAPProviderType + default_value = RICCAPProviderType.LICENSED_CENTER + definition_period = YEAR + label = "Rhode Island CCAP child care provider type" + defined_for = StateCode.RI + reference = "https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.7.1" diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_star_rating.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_star_rating.py new file mode 100644 index 00000000000..c3c4ad230df --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_star_rating.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class RICCAPStarRating(Enum): + STAR_1 = "1 Star" + STAR_2 = "2 Stars" + STAR_3 = "3 Stars" + STAR_4 = "4 Stars" + STAR_5 = "5 Stars" + + +class ri_ccap_star_rating(Variable): + value_type = Enum + entity = Person + possible_values = RICCAPStarRating + default_value = RICCAPStarRating.STAR_1 + definition_period = YEAR + label = "Rhode Island CCAP provider star rating" + defined_for = StateCode.RI + reference = "https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.7.1" diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_step_rating.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_step_rating.py new file mode 100644 index 00000000000..316e416a98a --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_step_rating.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class RICCAPStepRating(Enum): + STEP_1 = "Step 1" + STEP_2 = "Step 2" + STEP_3 = "Step 3" + STEP_4 = "Step 4" + + +class ri_ccap_step_rating(Variable): + value_type = Enum + entity = Person + possible_values = RICCAPStepRating + default_value = RICCAPStepRating.STEP_1 + definition_period = YEAR + label = "Rhode Island CCAP license-exempt provider step rating" + defined_for = StateCode.RI + reference = "https://dhs.ri.gov/media/3556/download?language=en" diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_time_category.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_time_category.py new file mode 100644 index 00000000000..eaf3ae984aa --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_ccap_time_category.py @@ -0,0 +1,24 @@ +from policyengine_us.model_api import * + + +class RICCAPTimeCategory(Enum): + FULL_TIME = "Full Time" + THREE_QUARTER_TIME = "Three Quarter Time" + HALF_TIME = "Half Time" + QUARTER_TIME = "Quarter Time" + + +class ri_ccap_time_category(Variable): + value_type = Enum + entity = Person + possible_values = RICCAPTimeCategory + default_value = RICCAPTimeCategory.FULL_TIME + definition_period = YEAR + label = "Rhode Island CCAP time authorization category" + defined_for = StateCode.RI + reference = "https://rules.sos.ri.gov/regulations/part/218-20-00-4#4.7.1" + + def formula(person, period, parameters): + hours = person("childcare_hours_per_week", period) + p = parameters(period).gov.states.ri.dhs.ccap.time_authorization + return p.thresholds.calc(hours) diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_child_care_subsidies.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_child_care_subsidies.py new file mode 100644 index 00000000000..b2dbd31ffa6 --- /dev/null +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/ri_child_care_subsidies.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class ri_child_care_subsidies(Variable): + value_type = float + entity = SPMUnit + label = "Rhode Island child care subsidies" + unit = USD + definition_period = YEAR + defined_for = StateCode.RI + adds = ["ri_ccap"] diff --git a/policyengine_us/variables/household/expense/childcare/childcare_expenses.py b/policyengine_us/variables/household/expense/childcare/childcare_expenses.py index d0771598c7d..f6972610c73 100644 --- a/policyengine_us/variables/household/expense/childcare/childcare_expenses.py +++ b/policyengine_us/variables/household/expense/childcare/childcare_expenses.py @@ -13,7 +13,7 @@ def formula(spm_unit, period, parameters): spm_unit, period, ["pre_subsidy_childcare_expenses"] ) # States where we model childcare subsidies. - STATES_WITH_CHILD_CARE_SUBSIDIES = ["CA", "CO", "NE", "MA"] + STATES_WITH_CHILD_CARE_SUBSIDIES = ["CA", "CO", "NE", "MA", "RI"] subsidy_variables = [ i.lower() + "_child_care_subsidies" for i in STATES_WITH_CHILD_CARE_SUBSIDIES diff --git a/sources/working_references.md b/sources/working_references.md new file mode 100644 index 00000000000..d3172437d4a --- /dev/null +++ b/sources/working_references.md @@ -0,0 +1,460 @@ +# Rhode Island CCAP (Child Care Assistance Program) - Working References + +## Program Overview + +**Official Name**: Starting RIght Child Care Assistance Program (CCAP) +**Administering Agency**: Rhode Island Department of Human Services (DHS), Office of Child Care (OCC) +**Authorizing Statute**: R.I. Gen. Laws Section 42-12-23; R.I. Gen. Laws Chapter 40-6.2; R.I. Gen. Laws Section 40-5.2-20 +**Regulation**: 218-RICR-20-00-4 (Child Care Assistance Program Rules and Regulations) + +--- + +## 1. Primary Regulatory Sources + +### 1a. 218-RICR-20-00-4 - CCAP Rules and Regulations (CURRENT) + +- **URL**: https://dhs.ri.gov/media/9236/download?language=en +- **Local PDF**: `/tmp/ri-ccap-regs-9236.txt` (pdftotext extraction, 78 pages) +- **Status**: Current active regulation +- **Key sections**: + - Section 4.1: General Provisions, Authority (R.I. Gen. Laws Section 42-12-23) + - Section 4.2: Definitions (financial unit, income, excluded income, family share, etc.) + - Section 4.3: Eligibility and Authorization of Services (general eligibility requirements) + - Section 4.4: Applying for Child Care Assistance (application processing) + - Section 4.5: Criteria for RI Works CCAP Eligibility (TANF pathway) + - Section 4.6: Criteria for Income Eligibility (income-eligible families) + - Section 4.7: Authorization of Child Care Services (FT/3QT/HT/QT) + - Section 4.8: Enrollment for CCAP Authorized Services + - Section 4.9: Notices, Rights and Duties + - Section 4.10: Improper Payments + - Section 4.11: Child Care Provider Guide + - Section 4.12: CCAP Maximum Weekly Reimbursement Rates + +### 1b. Rhode Island Secretary of State Regulations Portal + +- **URL**: https://rules.sos.ri.gov/Regulations/part/218-20-00-4?reg_id=8807 +- **Description**: Official regulations database entry for 218-RICR-20-00-4 + +### 1c. Cornell LII - Section 4.3 (Eligibility) + +- **URL**: https://www.law.cornell.edu/regulations/rhode-island/218-RICR-20-00-4.3 +- **Description**: Eligibility and Authorization of Services section + +--- + +## 2. Eligibility Requirements + +### 2a. Income Eligibility Thresholds (218-RICR-20-00-4, Section 4.6.1.A) + +| Category | FPL Threshold | Notes | +|----------|--------------|-------| +| Initial Eligibility | <= 261% FPL | New applicants | +| Transitional Child Care | 261% - 300% FPL | At recertification only, for families already receiving CCAP | +| Exit Threshold | > 300% FPL | Benefits terminate | +| 85% SMI | Reporting trigger | Families must report if income exceeds 85% SMI during cert period | + +### 2b. Age Requirements (Section 4.3.1.A.1) + +- Child must be at least **6 weeks old** (changed from 1 week) and **under age 13** +- Exception: Children 13-18 with documented physical/mental disability incapable of self-care +- Children turning 13 during certification period remain eligible until age 14 or redetermination + +### 2c. Activity Requirements (Section 4.6.2) + +- **Employment**: Minimum 20 hours/week average per month, earning at least state/federal minimum wage +- **Education/Training**: Minimum 20 hours/week average per month in approved program +- **College**: Minimum 7 credits at CCRI, RIC, or URI (7 credits x 3 need hours = 21 hours) +- **Two-parent homes**: Both parents must individually meet the 20-hour requirement +- **Job Search**: Temporary 3-month authorization at three-quarter time (TQT) + +### 2d. Residency and Citizenship (Section 4.3.1.A.3-4) + +- Parent(s) and children must be Rhode Island residents +- Child must be US citizen or qualified immigrant (no 5-year waiting period) +- Parent applying is NOT required to provide proof of citizenship + +### 2e. Asset Test (Section 4.6.1.B) + +- Family assets must not exceed **$1,000,000** +- Assets include: vehicles (excl. primary), real estate (excl. primary residence), cash, bank accounts, investments +- Assets exclude: educational savings, retirement accounts, joint accounts with non-household adults (with documentation) +- Self-declaration is acceptable verification unless near limit + +### 2f. Child Support Cooperation (Section 4.3.2) + +- Must cooperate with Office of Child Support Services (OCSS) +- Good cause exceptions available (domestic violence, etc.) +- Non-cooperation results in denial for that child only + +### 2g. Certification Period + +- Minimum **24 months** (changed from 12 months throughout the regulation) + +--- + +## 3. Income Definitions + +### 3a. Countable Income (Section 4.2, Definition 30/29) + +Includes: +- Gross wages, salary, commissions, tips, bonuses +- Adjusted gross income from self-employment +- Social Security (RSDI) +- Supplemental Security Income (SSI) +- Dividends, interest +- Income from estates/trusts +- Adjusted gross rental income +- Adjusted gross room and board income +- Public assistance payments +- Unemployment compensation +- Temporary Disability Insurance (TDI) +- Workers' compensation +- Government/military retirement, private pensions, annuities +- Cash payouts for waiving employer health insurance +- Adoption subsidies +- Alimony +- Child support payments +- Regular contributions from persons not in household +- Royalties +- Strike benefits +- VA Compensation, VA Educational Benefits, Spousal/Dependent Allowances, Military Allotments +- Americorps payments (NOT Americorps/VISTA) +- Foster care payments (when child IS in assistance unit) +- In-kind assistance +- Non-citizen sponsor income + +### 3b. Excluded Income (Section 4.2, Definition 23/22) + +Includes: +- USDA donated foods +- Relocation assistance (42 U.S.C. Sections 4601-4655) +- Undergraduate student financial aid +- Indian tribe per capita payments +- Nutrition Program for the Elderly benefits +- Foster grandparent/senior volunteer payments +- Child Nutrition Act benefits +- Housing Allowance Program payments +- Indian tribe receipts (Pub. Law 94-114) +- Alaska Native Claims Settlement Act payments +- Foster care payments (when child NOT in assistance unit) +- SNAP benefits +- Government rent/housing subsidies +- Home energy assistance +- College work study income +- Earned income of dependent children in financial unit +- WIOA stipends, earned income, reimbursements +- EITC refunds and advance payments +- Loans/grants for non-living costs +- SSA PASS and IRWE program payments +- Income of parents with whom teen parent resides +- Section 8 utility payment +- Veterans Aid and Attendant Allowances +- Americorps/VISTA payments (note: Americorps non-VISTA IS counted) +- RI Works cash assistance payments +- Veterans Disability Pension payments + +### 3c. Income Calculation Method (Section 4.6.1.A.c) + +- **Prospective budgeting** is used +- Weekly income converted to monthly using **4.3333 weeks per month** +- Income estimate valid between determinations and following reported changes +- Self-employment income calculated per RI Works Program Rules (Section 2.15.4) + +--- + +## 4. Family Co-Share (Co-Payment) Schedule + +### 4a. Co-Share Levels (Section 4.6.1.C, effective 02/15/2026) + +| Level | FPL Range | % of Gross Income | +|-------|-----------|-------------------| +| 0 | <= 100% FPL | 0% (no family share) | +| 1 | > 100% to <= 125% FPL | 2% | +| 2 | > 125% to <= 150% FPL | 5% | +| 3 | > 150% to <= 261% FPL | 7% | +| 4 (Transitional) | > 261% to <= 300% FPL | 7% | + +**Source PDF**: https://dhs.ri.gov/media/10606/download?language=en +**Local screenshots**: `/tmp/ri-ccap-copay-chart-2026-page-1.png`, `/tmp/ri-ccap-copay-chart-2026-page-2.png` + +### 4b. 2026 Annual FPL Thresholds by Family Size + +| Family Size | Level 0 (<= 100%) | Level 1 (100-125%) | Level 2 (125-150%) | Level 3 (150-261%) | Level 4 Transitional (261-300%) | +|------------|-------------------|-------------------|-------------------|-------------------|-------------------------------| +| 2 | $21,640 | $27,050 | $32,460 | $56,480 | $64,920 | +| 3 | $27,320 | $34,150 | $40,980 | $71,305 | $81,960 | +| 4 | $33,000 | $41,250 | $49,500 | $86,130 | $99,000 | +| 5 | $38,680 | $48,350 | $58,020 | $100,955 | $116,040 | +| 6 | $44,360 | $55,450 | $66,540 | $115,780 | $133,080 | +| 7 | $50,040 | $62,550 | $75,060 | $130,604 | $150,120 | +| 8 | $55,720 | $69,650 | $83,580 | $145,429 | $167,160 | +| 9 | $61,400 | $76,750 | $92,100 | $160,254 | $184,200 | +| 10 | $67,080 | $83,850 | $100,620 | $175,079 | $201,240 | +| 11 | $72,760 | $90,950 | $109,140 | $189,904 | $218,280 | +| 12 | $78,440 | $98,050 | $117,660 | $204,728 | $235,320 | +| 13 | $84,120 | $105,150 | $126,180 | $219,553 | $252,360 | +| 14 | $89,800 | $112,250 | $134,700 | $234,378 | $269,400 | +| 15 | $95,480 | $119,350 | $143,220 | $249,203 | $286,440 | + +*Add $5,680 for each additional person over 15* + +### 4c. Co-Share Rules (Section 4.6.1.C) + +- **One co-payment per family** regardless of number of children enrolled +- Co-share assigned to the **youngest eligible child** (highest rate child) +- Co-share only distributed among providers when it exceeds the rate for youngest child +- RI Works recipients: **$0 co-payment** (Section 4.5.4.A.1) +- Housing insecure families: **$0 co-payment** (Section 4.5.4.B) +- Loco-parentis RI Works applicants not included in RI Works payment: assessed based on Family Cost Sharing Requirement + +--- + +## 5. Provider Reimbursement Rates + +### 5a. Licensed Child Care Center Weekly Rates (Effective July 1, 2025) + +**Source PDF**: https://dhs.ri.gov/media/9356/download?language=en +**Local screenshot**: `/tmp/ri-ccap-center-rates-2025-page-1.png` + +**Full Time (30+ hours/week)** + +| Age Category | Star 1 | Star 2 | Star 3 | Star 4 | Star 5 | +|-------------|--------|--------|--------|--------|--------| +| Infant | $334.00 | $341.00 | $355.00 | $364.00 | $378.00 | +| Toddler | $278.00 | $284.00 | $296.00 | $303.00 | $315.00 | +| Preschool | $236.00 | $247.00 | $255.00 | $263.00 | $273.00 | +| School Age | $210.00 | $215.00 | $231.00 | $250.00 | $263.00 | + +**Three Quarter Time (20-29 hours/week)** + +| Age Category | Star 1 | Star 2 | Star 3 | Star 4 | Star 5 | +|-------------|--------|--------|--------|--------|--------| +| Infant | $250.50 | $255.75 | $266.25 | $273.00 | $283.50 | +| Toddler | $208.50 | $213.00 | $222.00 | $227.25 | $236.25 | +| Preschool | $177.00 | $185.25 | $191.25 | $197.25 | $204.75 | +| School Age | $157.50 | $161.25 | $173.25 | $187.50 | $197.25 | + +**Half Time (10-19 hours/week)** + +| Age Category | Star 1 | Star 2 | Star 3 | Star 4 | Star 5 | +|-------------|--------|--------|--------|--------|--------| +| Infant | $167.00 | $170.50 | $177.50 | $182.00 | $189.00 | +| Toddler | $139.00 | $142.00 | $148.00 | $151.50 | $157.50 | +| Preschool | $118.00 | $123.50 | $127.50 | $131.50 | $136.50 | +| School Age | $105.00 | $107.50 | $115.50 | $125.00 | $131.50 | + +**Quarter Time (0-9 hours/week)** + +| Age Category | Star 1 | Star 2 | Star 3 | Star 4 | Star 5 | +|-------------|--------|--------|--------|--------|--------| +| Infant | $83.50 | $85.25 | $88.75 | $91.00 | $94.50 | +| Toddler | $69.50 | $71.00 | $74.00 | $75.75 | $78.75 | +| Preschool | $59.00 | $61.75 | $63.75 | $65.75 | $68.25 | +| School Age | $52.50 | $53.75 | $57.75 | $62.50 | $65.75 | + +**Age Categories (Centers, July 2025)**: +- Infant: 6 weeks up to 18 months +- Toddler: 18 months up to 3 years +- Preschool: 3 years up to 1st grade entry (includes ALL Kindergarten) +- School Age: 1st grade up to 13 years + +### 5b. Licensed Family Child Care Weekly Rates (Effective July 1, 2024) + +**Source PDF**: https://dhs.ri.gov/media/7481/download?language=en +**Local screenshot**: `/tmp/ri-ccap-family-rates-page-1.png` + +**Full Time (30+ hours/week)** + +| Age Category | Star 1 | Star 2 | Star 3 | Star 4 | Star 5 | +|-------------|--------|--------|--------|--------|--------| +| Infant/Toddler | $262.66 | $266.86 | $270.02 | $273.16 | $276.31 | +| Preschool | $220.63 | $231.14 | $239.54 | $251.10 | $262.66 | +| School Age | $194.37 | $199.62 | $215.38 | $236.40 | $246.90 | + +**Three Quarter Time (20-29 hours/week)** + +| Age Category | Star 1 | Star 2 | Star 3 | Star 4 | Star 5 | +|-------------|--------|--------|--------|--------|--------| +| Infant/Toddler | $196.99 | $200.14 | $202.51 | $204.87 | $207.23 | +| Preschool | $165.47 | $173.35 | $179.66 | $188.33 | $196.99 | +| School Age | $145.78 | $149.71 | $161.54 | $177.30 | $185.18 | + +**Half Time (10-19 hours/week)** + +| Age Category | Star 1 | Star 2 | Star 3 | Star 4 | Star 5 | +|-------------|--------|--------|--------|--------|--------| +| Infant/Toddler | $131.33 | $133.43 | $135.01 | $136.58 | $138.15 | +| Preschool | $110.32 | $115.57 | $119.77 | $125.55 | $131.33 | +| School Age | $97.19 | $99.81 | $107.69 | $118.20 | $123.45 | + +**Quarter Time (0-9 hours/week)** + +| Age Category | Star 1 | Star 2 | Star 3 | Star 4 | Star 5 | +|-------------|--------|--------|--------|--------|--------| +| Infant/Toddler | $65.66 | $66.71 | $67.50 | $68.29 | $69.08 | +| Preschool | $55.16 | $57.78 | $59.89 | $62.78 | $65.66 | +| School Age | $48.59 | $49.90 | $53.85 | $59.10 | $61.73 | + +**Age Categories (Family, July 2024)** - combined Infant/Toddler: +- Infant/Toddler: 1 week up to 3 years +- Preschool: 3 years up to 1st grade entry (includes ALL Kindergarten) +- School Age: 1st grade up to 13 years + +### 5c. Licensed Exempt Child Care Weekly Rates (Effective January 1, 2022) + +**Source PDF**: https://dhs.ri.gov/media/3556/download?language=en +**Local screenshot**: `/tmp/ri-ccap-exempt-rates-page-1.png` + +**Full Time (30+ hours/week)** + +| Age Category | Step 1 | Step 2 | Step 3 | Step 4 | +|-------------|--------|--------|--------|--------| +| Infant/Toddler | $100.96 | $101.95 | $102.94 | $103.96 | +| Preschool | $59.91 | $60.49 | $61.09 | $61.68 | +| School Age | $58.80 | $59.38 | $59.97 | $60.53 | + +**Three Quarter Time (20-29 hours/week)** + +| Age Category | Step 1 | Step 2 | Step 3 | Step 4 | +|-------------|--------|--------|--------|--------| +| Infant/Toddler | $75.72 | $76.46 | $77.21 | $77.96 | +| Preschool | $44.93 | $45.37 | $45.83 | $46.26 | +| School Age | $44.10 | $44.53 | $44.97 | $45.40 | + +**Half Time (10-19 hours/week)** + +| Age Category | Step 1 | Step 2 | Step 3 | Step 4 | +|-------------|--------|--------|--------|--------| +| Infant/Toddler | $50.48 | $50.98 | $51.48 | $51.98 | +| Preschool | $29.95 | $30.26 | $30.54 | $30.84 | +| School Age | $29.40 | $29.69 | $29.98 | $30.28 | + +**Quarter Time (0-9 hours/week)** + +| Age Category | Step 1 | Step 2 | Step 3 | Step 4 | +|-------------|--------|--------|--------|--------| +| Infant/Toddler | $25.24 | $25.49 | $25.74 | $25.98 | +| Preschool | $14.71 | $15.11 | $15.28 | $15.42 | +| School Age | $14.70 | $14.85 | $14.99 | $15.13 | + +**Notes**: License exempt providers use "Step" ratings (1-4) instead of "Star" ratings (1-5). + +--- + +## 6. Authorization Levels (Section 4.7.1.A.2) + +| Authorization | Hours per Week | +|--------------|---------------| +| Full Time (FT) | 30 or more hours | +| Three Quarter Time (3QT) | 20 to 29 hours | +| Half Time (HT) | 10 to 19 hours | +| Quarter Time (QT) | Less than 10 hours | + +- Up to 1 hour per day may be added for travel time to/from child care +- Additional travel time allowed with documented need + +--- + +## 7. Benefit Calculation + +### Formula + +``` +CCAP Subsidy = Provider Weekly Rate - Family Co-Share (weekly amount) +``` + +Where: +- **Provider Weekly Rate** = CCAP Established Schedule of Maximum Weekly Rates for the provider's type, QRIS star rating, child's age category, and authorized time +- **Family Co-Share** = Percentage of gross countable income based on FPL level (0%, 2%, 5%, or 7%), divided by number of weeks +- Family pays **one co-share** regardless of number of children +- Co-share assigned to **youngest eligible child** (highest-rate child) +- DHS pays the provider the rate minus the family share +- If family share exceeds the rate for the youngest child, remainder distributed to other providers + +### Income Conversion + +- Weekly income x 4.3333 = Monthly income (for prospective budgeting) +- Annual FPL thresholds provided in co-pay chart + +--- + +## 8. Special Provisions + +### 8a. Transitional Child Care (Section 4.6.1.A.1) + +- Families already receiving CCAP whose income rises above 261% FPL may continue at 7% co-share up to 300% FPL +- Determined at recertification +- New applicants above 261% FPL are NOT eligible for transitional +- If income later falls below 261%, transitional ends and regular CCAP can be applied for + +### 8b. Job Search (Section 4.6.4.A.42) + +- Temporary 3-month authorization at Three Quarter Time +- Limited to one 3-month period per 24-month cert period +- Maximum two 3-month periods total per household per lifetime + +### 8c. Non-Temporary Change in Status (Section 4.6.4.A.3) + +- 3-month grace period to resume work/training +- Same level of coverage maintained during grace period + +### 8d. Short-Term Special Approval (Section 4.6.4.A.5) + +- Up to 6 months extension for serious health condition +- May be extended once for additional 6 months (12 months max) + +### 8e. RI Works Pathway (Section 4.5) + +- RI Works (TANF) recipients eligible for fully-subsidized CCAP ($0 co-payment) +- Must have approved employment plan +- Two-parent homes: both parents need approved employment plans + +--- + +## 9. Source Documents Index + +| # | Document | URL | Effective Date | Local File | +|---|----------|-----|---------------|------------| +| 1 | 218-RICR-20-00-4 (Full Regulation) | [DHS](https://dhs.ri.gov/media/9236/download?language=en) | Current | `/tmp/ri-ccap-regs-9236.txt` | +| 2 | CCAP 2026 Family Income Co-Pay Chart | [DHS](https://dhs.ri.gov/media/10606/download?language=en) | 02/15/2026 | `/tmp/ri-ccap-copay-chart-2026.pdf` | +| 3 | Licensed Center Weekly Rates July 2025 | [DHS](https://dhs.ri.gov/media/9356/download?language=en) | 07/01/2025 | `/tmp/ri-ccap-center-rates-2025.pdf` | +| 4 | Licensed Family Weekly Rates July 2024 | [DHS](https://dhs.ri.gov/media/7481/download?language=en) | 07/01/2024 | `/tmp/ri-ccap-family-rates.pdf` | +| 5 | Licensed Exempt Weekly Rates Jan 2022 | [DHS](https://dhs.ri.gov/media/3556/download?language=en) | 01/01/2022 | `/tmp/ri-ccap-exempt-rates.pdf` | +| 6 | CCAP Eligibility Page | [DHS](https://dhs.ri.gov/programs-and-services/child-care/child-care-assistance-program-ccap/ccap-family-eligibility-how) | N/A | N/A | +| 7 | CCAP Provider Rates Page | [DHS](https://dhs.ri.gov/programs-and-services/child-care/child-care-providers-staff-resources/ccap-provider-rates-financial) | N/A | N/A | +| 8 | CCAP Program Overview Flyer (2025) | [DHS](https://dhs.ri.gov/media/8766/download?language=en) | N/A | `/tmp/ri-ccap-doc-8766.txt` | +| 9 | CCAP Program Overview Flyer (2026) | [DHS](https://dhs.ri.gov/media/8846/download?language=en) | N/A | `/tmp/ri-ccap-doc-8846.txt` | +| 10 | RI Gen. Laws Ch. 40-6.2 (Justia) | [Justia](https://law.justia.com/codes/rhode-island/title-40/chapter-40-6-2/) | 2024 | N/A | +| 11 | FFY 2025-2027 CCDF State Plan | [DHS](https://dhs.ri.gov/media/7311/download?language=en) | 2025-2027 | N/A | +| 12 | CCDF Family Income Eligibility by State | [ACF](https://acf.gov/sites/default/files/documents/occ/CCDF-Family-Income-Eligibility-Levels-by-State.pdf) | Jan 2025 | N/A | +| 13 | CCDF Family Co-Payments by State | [ACF](https://acf.gov/sites/default/files/documents/occ/CCDF-Family-Co-Payments-by-State.pdf) | Jan 2025 | N/A | + +### 300 DPI Screenshots + +| Document | Screenshot Path | +|----------|----------------| +| Center Rates 2025 (p1) | `/tmp/ri-ccap-center-rates-2025-page-1.png` | +| Co-Pay Chart 2026 (p1 - Annual) | `/tmp/ri-ccap-copay-chart-2026-page-1.png` | +| Co-Pay Chart 2026 (p2 - Monthly) | `/tmp/ri-ccap-copay-chart-2026-page-2.png` | +| Family Rates 2024 (p1) | `/tmp/ri-ccap-family-rates-page-1.png` | +| Exempt Rates 2022 (p1) | `/tmp/ri-ccap-exempt-rates-page-1.png` | + +--- + +## 10. Key Implementation Notes + +1. **No income deductions**: RI CCAP uses **gross countable income** with no earned income disregards or deductions. The only adjustments are excluded income types (Section 4.2, Definition 23/22) and self-employment AGI calculation. + +2. **Provider rate dimensions**: Rates vary by 3 dimensions: + - Provider type (center, family, exempt) + - QRIS star/step rating (1-5 for licensed, 1-4 for exempt) + - Child age category (infant, toddler, preschool, school-age -- note centers split infant/toddler in 2025) + - Time authorization (FT, 3QT, HT, QT) + +3. **Family size**: Determined by the "financial unit" = dependent children (applicant and non-applicant) + parent(s) + legal spouse(s) of parent(s) living in same household. + +4. **One co-pay per family**: Regardless of number of children, only one co-payment is assessed. + +5. **Prospective budgeting**: Income projected forward from application/last change; weekly x 4.3333 = monthly. + +6. **2026 FPL base**: Family of 2 = $21,640; increments of $5,680 per additional person (derived from FPL chart). From 80b59a29cd430dd4f1bcabc9ef3a63fe4e950660 Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 9 Mar 2026 11:41:06 -0400 Subject: [PATCH 3/5] Add changelog fragment for RI CCAP Co-Authored-By: Claude Opus 4.6 --- changelog.d/ri-ccap.added.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/ri-ccap.added.md diff --git a/changelog.d/ri-ccap.added.md b/changelog.d/ri-ccap.added.md new file mode 100644 index 00000000000..15427b5e3dd --- /dev/null +++ b/changelog.d/ri-ccap.added.md @@ -0,0 +1 @@ +Add Rhode Island Child Care Assistance Program (CCAP). From 985beabf641d79f22c50fe2ffec248e2caeb0f7b Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 9 Mar 2026 12:05:25 -0400 Subject: [PATCH 4/5] Review-fix round 1: fix disabled child age operator and add missing SSDI/survivors income - disabled_child.yaml: keep value at 18 (matches law), fix formula to use <= instead of < - sources.yaml: add social_security_disability and social_security_survivors (RSDI) - Update tests for corrected disabled child age boundary Co-Authored-By: Claude Opus 4.6 --- .../dhs/ccap/age_threshold/disabled_child.yaml | 2 +- .../ccap/income/countable_income/sources.yaml | 2 ++ .../ccap/edge_cases/ri_ccap_eligible_child.yaml | 16 ++++++++-------- .../ccap/eligibility/ri_ccap_eligible_child.yaml | 4 ++-- .../ccap/eligibility/ri_ccap_eligible_child.py | 5 +++-- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_threshold/disabled_child.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_threshold/disabled_child.yaml index 88c4f918731..d00e123db4e 100644 --- a/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_threshold/disabled_child.yaml +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/age_threshold/disabled_child.yaml @@ -1,4 +1,4 @@ -description: Rhode Island limits the Child Care Assistance Program to disabled children younger than this age. +description: Rhode Island limits the Child Care Assistance Program to disabled children up through this age. values: 2020-01-01: 18 diff --git a/policyengine_us/parameters/gov/states/ri/dhs/ccap/income/countable_income/sources.yaml b/policyengine_us/parameters/gov/states/ri/dhs/ccap/income/countable_income/sources.yaml index 7e6904f1016..718a1dd10f4 100644 --- a/policyengine_us/parameters/gov/states/ri/dhs/ccap/income/countable_income/sources.yaml +++ b/policyengine_us/parameters/gov/states/ri/dhs/ccap/income/countable_income/sources.yaml @@ -4,6 +4,8 @@ values: - employment_income - self_employment_income - social_security_retirement + - social_security_disability + - social_security_survivors - ssi - dividend_income - interest_income diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_eligible_child.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_eligible_child.yaml index 3cb5a0b6888..d1551ffbb4b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_eligible_child.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/edge_cases/ri_ccap_eligible_child.yaml @@ -1,6 +1,6 @@ # Edge cases for ri_ccap_eligible_child # Child age threshold: < 13 -# Disabled child age threshold: < 18 +# Disabled child age threshold: <= 18 - name: Case 1, child age 12 is last eligible year. period: 2025 @@ -50,14 +50,14 @@ # age 13 not < 13 -> ineligible ri_ccap_eligible_child: [false, false] -- name: Case 3, disabled child age 17 is last eligible year. +- name: Case 3, disabled child age 18 is last eligible year. period: 2025 input: people: person1: age: 45 person2: - age: 17 + age: 18 is_tax_unit_dependent: true is_disabled: true immigration_status: CITIZEN @@ -72,17 +72,17 @@ members: [person1, person2] state_code: RI output: - # disabled, age 17 < 18 -> eligible + # disabled, age 18 <= 18 -> eligible ri_ccap_eligible_child: [false, true] -- name: Case 4, disabled child age 18 is ineligible. +- name: Case 4, disabled child age 19 is ineligible. period: 2025 input: people: person1: age: 45 person2: - age: 18 + age: 19 is_tax_unit_dependent: true is_disabled: true immigration_status: CITIZEN @@ -97,7 +97,7 @@ members: [person1, person2] state_code: RI output: - # disabled, age 18 not < 18 -> ineligible + # disabled, age 19 not <= 18 -> ineligible ri_ccap_eligible_child: [false, false] - name: Case 5, disabled child age 13 is still eligible. @@ -122,7 +122,7 @@ members: [person1, person2] state_code: RI output: - # disabled, age 13 < 18 -> eligible (uses disabled threshold) + # disabled, age 13 <= 18 -> eligible (uses disabled threshold) ri_ccap_eligible_child: [false, true] - name: Case 6, age 0 infant is eligible. diff --git a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.yaml b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.yaml index f7b833fdf0a..8be4d9701cc 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.yaml @@ -68,7 +68,7 @@ output: ri_ccap_eligible_child: [false, true] -- name: Case 4, disabled child age 18 ineligible. +- name: Case 4, disabled child age 18 eligible (up through 18). period: 2025 input: people: @@ -90,7 +90,7 @@ members: [person1, person2] state_code: RI output: - ri_ccap_eligible_child: [false, false] + ri_ccap_eligible_child: [false, true] - name: Case 5, child who is not a dependent is ineligible. period: 2025 diff --git a/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.py b/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.py index 8642c1bb19b..2e288cc46ce 100644 --- a/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.py +++ b/policyengine_us/variables/gov/states/ri/dhs/ccap/eligibility/ri_ccap_eligible_child.py @@ -13,8 +13,9 @@ def formula(person, period, parameters): p = parameters(period).gov.states.ri.dhs.ccap.age_threshold age = person("age", period) is_disabled = person("is_disabled", period) - age_limit = where(is_disabled, p.disabled_child, p.child) - age_eligible = age < age_limit + # Non-disabled: "under thirteen (13)" -> age < 13 + # Disabled: "up through eighteen (18)" -> age <= 18 + age_eligible = where(is_disabled, age <= p.disabled_child, age < p.child) is_dependent = person("is_tax_unit_dependent", period) immigration_eligible = person( "ri_ccap_immigration_status_eligible_child", period From f8a36c84b0471fd1fb75aa3f22ac90ac64a5a72a Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 9 Mar 2026 12:16:41 -0400 Subject: [PATCH 5/5] Add lessons from Rhode Island CCAP implementation Co-Authored-By: Claude Opus 4.6 --- lessons/agent-lessons.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 lessons/agent-lessons.md diff --git a/lessons/agent-lessons.md b/lessons/agent-lessons.md new file mode 100644 index 00000000000..1c1cf0e4279 --- /dev/null +++ b/lessons/agent-lessons.md @@ -0,0 +1,16 @@ +# Agent Lessons Learned + +Accumulated from /encode-policy-v2 and /backdate-program runs across all contributors. +Loaded by implementation agents on future runs. + +## New Lessons from Rhode Island CCAP (2026-03-09) + +### PARAMETER +- When a regulation references a composite benefit acronym (e.g., "RSDI" = Retirement + Survivors + Disability Insurance), enumerate and include ALL component income types in the sources list; do not map the acronym to only its most common component. +- **Rules as code**: Parameter values MUST match the legal text exactly. If the law says "up through eighteen (18)", the parameter value is 18 — never adjust it to 19 to compensate for a wrong comparison operator. Fix the formula operator (`<=` vs `<`) instead. Parameters store what the law says; formulas encode the logic. + +### TEST +- When tests were written to match a buggy parameter or formula, fixing the root cause requires a sweep of ALL test files that reference the affected variable; stale expected outputs silently mask regressions. + +### FORMULA +- When a review finding identifies a boundary operator mismatch (strict `<` vs inclusive `<=`) against regulation text, resolve it before approving; boundary bugs affect exactly one threshold-value row and are invisible in typical test cases that avoid exact boundaries.