From 159c6e12e5a3812e324c04efb190e7756fc739b5 Mon Sep 17 00:00:00 2001 From: Ziming Date: Thu, 14 May 2026 22:41:13 -0400 Subject: [PATCH 01/17] Scaffold AR CCAP implementation From ddaca54ff5564a5531a2034e6e1bb20fb80481c1 Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 15 May 2026 01:21:47 -0400 Subject: [PATCH 02/17] Implement Arkansas School Readiness Assistance (SRA) Closes #8323. --- changelog.d/ar-ccap.added.md | 1 + .../activity_hours_ess_year_1.yaml | 13 + .../activity_hours_ess_year_2.yaml | 13 + .../sra/eligibility/activity_hours_li.yaml | 13 + .../ade/oec/sra/eligibility/asset_limit.yaml | 13 + .../oec/sra/eligibility/child_age_limit.yaml | 13 + .../sra/eligibility/ess_window_months.yaml | 11 + .../eligibility/ess_year_1_window_months.yaml | 11 + .../oec/sra/eligibility/income_smi_rate.yaml | 13 + .../gov/states/ar/ade/oec/sra/in_effect.yaml | 14 + .../ade/oec/sra/income/excluded_sources.yaml | 32 ++ .../states/ar/ade/oec/sra/income/sources.yaml | 40 +++ .../oec/sra/rates/age_category_months.yaml | 32 ++ .../ar/ade/oec/sra/rates/base_rate.yaml | 232 +++++++++++++ .../sra/rates/full_time_hours_threshold.yaml | 16 + .../oec/sra/rates/no_copay_smi_threshold.yaml | 13 + .../rates/partial_subsidy_smi_threshold.yaml | 13 + .../oec/sra/rates/state_share_by_tier.yaml | 79 +++++ .../sra/eligibility/ar_sra_age_eligible.yaml | 67 ++++ .../eligibility/ar_sra_asset_eligible.yaml | 65 ++++ .../eligibility/ar_sra_child_eligible.yaml | 85 +++++ .../oec/sra/eligibility/ar_sra_eligible.yaml | 144 +++++++++ .../sra/eligibility/ar_sra_ess_eligible.yaml | 122 +++++++ .../oec/sra/eligibility/ar_sra_in_effect.yaml | 91 ++++++ .../eligibility/ar_sra_income_eligible.yaml | 112 +++++++ .../ar_sra_li_activity_eligible.yaml | 113 +++++++ .../sra/income/ar_sra_countable_income.yaml | 93 ++++++ .../states/ar/ade/oec/sra/integration.yaml | 304 ++++++++++++++++++ .../oec/sra/rates/ar_sra_age_category.yaml | 60 ++++ .../oec/sra/rates/ar_sra_daily_base_rate.yaml | 226 +++++++++++++ .../ade/oec/sra/rates/ar_sra_daily_copay.yaml | 94 ++++++ .../sra/rates/ar_sra_daily_state_payment.yaml | 97 ++++++ .../ade/oec/sra/rates/ar_sra_income_tier.yaml | 88 +++++ .../ade/oec/sra/rates/ar_sra_state_share.yaml | 129 ++++++++ .../oec/sra/rates/ar_sra_time_category.yaml | 67 ++++ .../ar/ade/oec/sra/rates/ar_sra_zone.yaml | 26 ++ .../ar/ade/oec/sra/ar_child_care_subsidies.py | 11 + .../gov/states/ar/ade/oec/sra/ar_sra.py | 30 ++ .../ar/ade/oec/sra/ar_sra_age_category.py | 30 ++ .../states/ar/ade/oec/sra/ar_sra_care_type.py | 22 ++ .../ar/ade/oec/sra/ar_sra_income_tier.py | 34 ++ .../ar/ade/oec/sra/ar_sra_time_category.py | 29 ++ .../gov/states/ar/ade/oec/sra/ar_sra_zone.py | 35 ++ .../sra/eligibility/is_ar_sra_age_eligible.py | 18 ++ .../eligibility/is_ar_sra_asset_eligible.py | 17 + .../eligibility/is_ar_sra_child_eligible.py | 20 ++ .../oec/sra/eligibility/is_ar_sra_eligible.py | 25 ++ .../sra/eligibility/is_ar_sra_ess_eligible.py | 28 ++ .../eligibility/is_ar_sra_income_eligible.py | 19 ++ .../is_ar_sra_li_activity_eligible.py | 22 ++ .../oec/sra/income/ar_sra_countable_income.py | 27 ++ .../ar/ade/oec/sra/months_since_tea_exit.py | 13 + .../oec/sra/rates/ar_sra_daily_base_rate.py | 22 ++ .../ade/oec/sra/rates/ar_sra_daily_copay.py | 18 ++ .../sra/rates/ar_sra_daily_state_payment.py | 18 ++ .../ade/oec/sra/rates/ar_sra_state_share.py | 19 ++ .../ar/ade/oec/sra/was_tea_recipient.py | 13 + 57 files changed, 3025 insertions(+) create mode 100644 changelog.d/ar-ccap.added.md create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_1.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_2.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_li.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/asset_limit.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_year_1_window_months.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/excluded_sources.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/sources.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/state_share_by_tier.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_asset_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_child_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_income_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_age_category.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_time_category.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_zone.yaml create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_child_care_subsidies.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_care_type.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_time_category.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_zone.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_asset_eligible.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_child_eligible.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/months_since_tea_exit.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/was_tea_recipient.py diff --git a/changelog.d/ar-ccap.added.md b/changelog.d/ar-ccap.added.md new file mode 100644 index 00000000000..fc1f53f1bc8 --- /dev/null +++ b/changelog.d/ar-ccap.added.md @@ -0,0 +1 @@ +Add Arkansas School Readiness Assistance (SRA) child care subsidy program. diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_1.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_1.yaml new file mode 100644 index 00000000000..8c8ab1cca07 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_1.yaml @@ -0,0 +1,13 @@ +description: Arkansas requires at least one adult in an ESS Year 1 School Readiness Assistance household to engage in at least this many hours per week of work, education, or training. +values: + 2025-10-01: 20 + +metadata: + unit: hour + period: year + label: Arkansas SRA ESS Year 1 weekly activity hours + reference: + - title: FSU Procedural Manual (June 2023), Section 4.1.5.1 Employment + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16 + - title: OEC Rights & Responsibilities (Nov 2025) + href: https://dese.ade.arkansas.gov/Files/R_&_R__Nov_2025_(English)_(1)_OEC.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_2.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_2.yaml new file mode 100644 index 00000000000..ba700c3048c --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_2.yaml @@ -0,0 +1,13 @@ +description: Arkansas requires at least one adult in an ESS Year 2 School Readiness Assistance household to engage in at least this many hours per week of work, education, or training. +values: + 2025-10-01: 25 + +metadata: + unit: hour + period: year + label: Arkansas SRA ESS Year 2 weekly activity hours + reference: + - title: FSU Procedural Manual (June 2023), Section 4.1.5.1 Employment + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16 + - title: OEC Rights & Responsibilities (Nov 2025) + href: https://dese.ade.arkansas.gov/Files/R_&_R__Nov_2025_(English)_(1)_OEC.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_li.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_li.yaml new file mode 100644 index 00000000000..112f427df19 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_li.yaml @@ -0,0 +1,13 @@ +description: Arkansas requires each adult in a Low-Income School Readiness Assistance household to engage in at least this many hours per week of work, education, or training. +values: + 2025-10-01: 30 + +metadata: + unit: hour + period: year + label: Arkansas SRA Low-Income weekly activity hours + reference: + - title: FSU Procedural Manual (June 2023), Section 4.1.5.1 Employment + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16 + - title: OEC Rights & Responsibilities (Nov 2025) + href: https://dese.ade.arkansas.gov/Files/R_&_R__Nov_2025_(English)_(1)_OEC.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/asset_limit.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/asset_limit.yaml new file mode 100644 index 00000000000..95f6b79ff06 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/asset_limit.yaml @@ -0,0 +1,13 @@ +description: Arkansas limits family assets to this amount under the School Readiness Assistance program. +values: + 2025-10-01: 1_000_000 + +metadata: + unit: currency-USD + period: year + label: Arkansas SRA asset limit + reference: + - title: Arkansas CCDF Plan 2025-2027, Section 2.2.6 + href: https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=25 + - title: OEC Rights & Responsibilities (Nov 2025) + href: https://dese.ade.arkansas.gov/Files/R_&_R__Nov_2025_(English)_(1)_OEC.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit.yaml new file mode 100644 index 00000000000..1ce2537e4f1 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit.yaml @@ -0,0 +1,13 @@ +description: Arkansas limits the School Readiness Assistance program to children younger than this age. +values: + 2025-10-01: 13 + +metadata: + unit: year + period: year + label: Arkansas SRA child age limit + reference: + - title: AR ADC 016.22.8 Section 3.1.4 Eligible Child / Date of Birth + href: https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11 + - title: FSU Procedural Manual (June 2023), Section 4.1 + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=13 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml new file mode 100644 index 00000000000..3c687043b14 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml @@ -0,0 +1,11 @@ +description: Arkansas restricts the ESS School Readiness Assistance track to families within this many months of exiting Transitional Employment Assistance. +values: + 2025-10-01: 24 + +metadata: + unit: month + period: year + label: Arkansas SRA ESS post-TEA window months + reference: + - title: FSU Procedural Manual (June 2023), Section 5.4.1 + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=26 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_year_1_window_months.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_year_1_window_months.yaml new file mode 100644 index 00000000000..0e15b712cbd --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_year_1_window_months.yaml @@ -0,0 +1,11 @@ +description: Arkansas defines the Employment-Sponsored Subsidy Year 1 window as this many months after Transitional Employment Assistance exit under the School Readiness Assistance program. +values: + 2025-10-01: 12 + +metadata: + unit: month + period: year + label: Arkansas SRA ESS Year 1 window months + reference: + - title: FSU Procedural Manual (June 2023), Section 4.1.5.1 Employment + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml new file mode 100644 index 00000000000..7717509723d --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml @@ -0,0 +1,13 @@ +description: Arkansas limits gross income to this share of the state median income under the School Readiness Assistance program. +values: + 2025-10-01: 0.85 + +metadata: + unit: /1 + period: year + label: Arkansas SRA income limit SMI rate + reference: + - title: Arkansas CCDF Plan 2025-2027, Section 2.2.4 + href: https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=22 + - title: ACF CCDF Family Income Eligibility Levels by State (Jan 2025) + href: https://acf.gov/sites/default/files/documents/occ/CCDF-Family-Income-Eligibility-Levels-by-State.pdf diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml new file mode 100644 index 00000000000..321e91f8032 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml @@ -0,0 +1,14 @@ +description: Arkansas operates the School Readiness Assistance child care subsidy program if this is true. +values: + 1900-01-01: false + 2025-10-01: true + +metadata: + unit: bool + period: year + label: Arkansas SRA in effect + reference: + - title: OEC Rights & Responsibilities (Nov 2025) + href: https://dese.ade.arkansas.gov/Files/R_&_R__Nov_2025_(English)_(1)_OEC.pdf#page=1 + - title: OEC SRA Announcement Regarding Rates and Copays Effective November 1 + href: https://dese.ade.arkansas.gov/Files/OEC_SRA_Announcement_Regarding_Rates_and_Copays_Effective_November_1_OEC.pdf diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/excluded_sources.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/excluded_sources.yaml new file mode 100644 index 00000000000..5c83865c175 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/excluded_sources.yaml @@ -0,0 +1,32 @@ +description: Arkansas excludes these income sources from countable income under the School Readiness Assistance program. +values: + 2025-10-01: + # - tanf # Transitional Employment Assistance (TEA) payments + - child_support_received + - eitc # Tax refunds including EITC + # Children's SSI and Social Security are excluded; handled by the + # countable-income formula via age filter rather than by listing them. + # The following are also excluded per FSU Manual Section 4.3.3 + # but have no matching variables or do not need explicit listing: + # - Work Pays payments + # - Irregular non-recurring lump sums (Christmas bonuses, insurance, + # capital gains) + # - Earned/unearned income of children under 18 + # - Loans, grants, scholarships, work-study earnings + # - Graduate / doctoral education earnings + # - Montgomery GI Bill / VEAP educational income + # - Reimbursement of work-related expenses + # - Foster Care board payments + # - Adoption subsidy + # - HUD rental assistance value + # - Utility assistance value + # - Disaster assistance + # - Tribal income + +metadata: + unit: list + period: year + label: Arkansas SRA excluded income sources + reference: + - title: FSU Procedural Manual (June 2023), Section 4.3.3 Excluded Income + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=20 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/sources.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/sources.yaml new file mode 100644 index 00000000000..3caf431eefd --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/sources.yaml @@ -0,0 +1,40 @@ +description: Arkansas counts these income sources for adults under the School Readiness Assistance program. +values: + 2025-10-01: + - employment_income + - self_employment_income + - tip_income + - social_security_retirement + - social_security_disability + - social_security_survivors + - ssi + - unemployment_compensation + - workers_compensation + - alimony_income + - pension_income + - interest_income + - dividend_income + - rental_income + - military_retirement_pay + - veterans_benefits + # The following are counted per FSU Procedural Manual Section 4.3.1-4.3.2 + # but have no matching variables: + # - PTO and stipends (VISTA, AmeriCorps, Job Corps, OJT) + # - regular bonuses, commissions + # - armed forces pay (other than retirement) + # - piece-rate, in-kind, contractual income + # - annuities, regular contributions + # Children's SSI and Social Security are excluded; the formula filters + # contributions by age before summing. + +metadata: + unit: list + period: year + label: Arkansas SRA countable income sources + reference: + - title: FSU Procedural Manual (June 2023), Section 4.3.1 Countable Earned Income + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=19 + - title: FSU Procedural Manual (June 2023), Section 4.3.2 Countable Unearned Income + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=20 + - title: Arkansas CCDF Plan 2025-2027, Section 2.2.4(c) Income Definition + href: https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=24 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml new file mode 100644 index 00000000000..e4478691570 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml @@ -0,0 +1,32 @@ +description: Arkansas classifies children into these age categories by age in months for School Readiness Assistance rate lookup. Returned values match the integer index of the ar_sra_age_category enum (0=INFANT, 1=TODDLER, 2=PRESCHOOL, 3=SCHOOL_AGED). +# Age-category month boundaries are undocumented in Arkansas sources; +# these peer-state defaults (Infant <=17 mo, Toddler 18-35 mo, Preschool +# 36-71 mo, School-Aged 72+ mo) are flagged for future verification. + +brackets: + - threshold: + 2025-10-01: 0 + amount: + 2025-10-01: 0 # INFANT (0-17 months) + - threshold: + 2025-10-01: 18 + amount: + 2025-10-01: 1 # TODDLER (18-35 months) + - threshold: + 2025-10-01: 36 + amount: + 2025-10-01: 2 # PRESCHOOL (36-71 months) + - threshold: + 2025-10-01: 72 + amount: + 2025-10-01: 3 # SCHOOL_AGED (72+ months) + +metadata: + type: single_amount + threshold_unit: month + amount_unit: /1 + period: year + label: Arkansas SRA age category month thresholds + reference: + - title: FSU Procedural Manual (June 2023), Section 4.1 + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=13 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml new file mode 100644 index 00000000000..d522bdd701f --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml @@ -0,0 +1,232 @@ +description: Arkansas provides these daily base reimbursement rates by zone, age category, care type, and time category under the School Readiness Assistance program. +metadata: + period: day + unit: currency-USD + label: Arkansas SRA daily base rates + breakdown: + - ar_sra_zone + - ar_sra_age_category + - ar_sra_care_type + - ar_sra_time_category + reference: + - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Full Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf + - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Part Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf + - title: SRA Sliding Fee Scale with Rates and Copays - Benton/Washington Full Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf + - title: SRA Sliding Fee Scale with Rates and Copays - Benton/Washington Part Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf + +BENTON_WASHINGTON: + INFANT: + REGULAR: + FULL_TIME: + 2025-11-01: 38.00 + PART_TIME: + 2025-11-01: 19.00 + NIGHT_WEEKEND: + FULL_TIME: + 2025-11-01: 41.80 + # Part-Time has no Night/Weekend row; uses regular Part-Time rate + PART_TIME: + 2025-11-01: 19.00 + SN1: + FULL_TIME: + 2025-11-01: 38.00 + PART_TIME: + 2025-11-01: 19.00 + SN2: + FULL_TIME: + 2025-11-01: 53.20 + PART_TIME: + 2025-11-01: 26.60 + SN3: + FULL_TIME: + 2025-11-01: 53.20 + PART_TIME: + 2025-11-01: 26.60 + TODDLER: + REGULAR: + FULL_TIME: + 2025-11-01: 37.00 + PART_TIME: + 2025-11-01: 18.50 + NIGHT_WEEKEND: + FULL_TIME: + 2025-11-01: 40.70 + PART_TIME: + 2025-11-01: 18.50 + SN1: + FULL_TIME: + 2025-11-01: 37.00 + PART_TIME: + 2025-11-01: 18.50 + SN2: + FULL_TIME: + 2025-11-01: 51.80 + PART_TIME: + 2025-11-01: 25.90 + SN3: + FULL_TIME: + 2025-11-01: 51.80 + PART_TIME: + 2025-11-01: 25.90 + PRESCHOOL: + REGULAR: + FULL_TIME: + 2025-11-01: 33.00 + PART_TIME: + 2025-11-01: 16.50 + NIGHT_WEEKEND: + FULL_TIME: + 2025-11-01: 36.30 + PART_TIME: + 2025-11-01: 16.50 + SN1: + FULL_TIME: + 2025-11-01: 33.00 + PART_TIME: + 2025-11-01: 16.50 + SN2: + FULL_TIME: + 2025-11-01: 46.20 + PART_TIME: + 2025-11-01: 23.10 + SN3: + FULL_TIME: + 2025-11-01: 46.20 + PART_TIME: + 2025-11-01: 23.10 + SCHOOL_AGED: + REGULAR: + FULL_TIME: + 2025-11-01: 28.00 + PART_TIME: + 2025-11-01: 14.00 + NIGHT_WEEKEND: + FULL_TIME: + 2025-11-01: 30.80 + PART_TIME: + 2025-11-01: 14.00 + SN1: + FULL_TIME: + 2025-11-01: 28.00 + PART_TIME: + 2025-11-01: 14.00 + SN2: + FULL_TIME: + 2025-11-01: 39.20 + PART_TIME: + 2025-11-01: 19.60 + SN3: + FULL_TIME: + 2025-11-01: 39.20 + PART_TIME: + 2025-11-01: 19.60 + +STATEWIDE: + INFANT: + REGULAR: + FULL_TIME: + 2025-11-01: 36.00 + PART_TIME: + 2025-11-01: 18.00 + NIGHT_WEEKEND: + FULL_TIME: + 2025-11-01: 39.60 + PART_TIME: + 2025-11-01: 18.00 + SN1: + FULL_TIME: + 2025-11-01: 36.00 + PART_TIME: + 2025-11-01: 18.00 + SN2: + FULL_TIME: + 2025-11-01: 50.40 + PART_TIME: + 2025-11-01: 25.20 + SN3: + FULL_TIME: + 2025-11-01: 50.40 + PART_TIME: + 2025-11-01: 25.20 + TODDLER: + REGULAR: + FULL_TIME: + 2025-11-01: 35.00 + PART_TIME: + 2025-11-01: 17.50 + NIGHT_WEEKEND: + FULL_TIME: + 2025-11-01: 38.50 + PART_TIME: + 2025-11-01: 17.50 + SN1: + FULL_TIME: + 2025-11-01: 35.00 + PART_TIME: + 2025-11-01: 17.50 + SN2: + FULL_TIME: + 2025-11-01: 49.00 + PART_TIME: + 2025-11-01: 24.50 + SN3: + FULL_TIME: + 2025-11-01: 49.00 + PART_TIME: + 2025-11-01: 24.50 + PRESCHOOL: + REGULAR: + FULL_TIME: + 2025-11-01: 33.00 + PART_TIME: + 2025-11-01: 16.50 + NIGHT_WEEKEND: + FULL_TIME: + 2025-11-01: 36.30 + PART_TIME: + 2025-11-01: 16.50 + SN1: + FULL_TIME: + 2025-11-01: 33.00 + PART_TIME: + 2025-11-01: 16.50 + SN2: + FULL_TIME: + 2025-11-01: 46.20 + PART_TIME: + 2025-11-01: 23.10 + SN3: + FULL_TIME: + 2025-11-01: 46.20 + PART_TIME: + 2025-11-01: 23.10 + SCHOOL_AGED: + REGULAR: + FULL_TIME: + 2025-11-01: 28.00 + PART_TIME: + 2025-11-01: 14.00 + NIGHT_WEEKEND: + FULL_TIME: + 2025-11-01: 30.80 + PART_TIME: + 2025-11-01: 14.00 + SN1: + FULL_TIME: + 2025-11-01: 28.00 + PART_TIME: + 2025-11-01: 14.00 + SN2: + FULL_TIME: + 2025-11-01: 39.20 + PART_TIME: + 2025-11-01: 19.60 + SN3: + FULL_TIME: + 2025-11-01: 39.20 + PART_TIME: + 2025-11-01: 19.60 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml new file mode 100644 index 00000000000..0876dbc530b --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml @@ -0,0 +1,16 @@ +description: Arkansas classifies child care attendance as full-time under the School Readiness Assistance program when weekly hours meet or exceed this threshold. +# The full-time vs part-time hour cut-point is undocumented in Arkansas +# sources; this 30-hour default mirrors peer-state conventions (NH uses +# 31+ hours for FT; RI uses 30/45) and is flagged for future verification. +values: + 2025-10-01: 30 + +metadata: + unit: hour + period: year + label: Arkansas SRA full-time weekly hours threshold + reference: + - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Full Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf + - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Part Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml new file mode 100644 index 00000000000..3404231688b --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml @@ -0,0 +1,13 @@ +description: Arkansas waives the family copay under the School Readiness Assistance program for non-school-aged children whose family income is at or below this share of the state median income. +values: + 2025-11-01: 0.40 + +metadata: + unit: /1 + period: year + label: Arkansas SRA no-copay SMI threshold + reference: + - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Full Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf + - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Part Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml new file mode 100644 index 00000000000..0514291e5e2 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml @@ -0,0 +1,13 @@ +description: Arkansas classifies families in the partial-subsidy income tier under the School Readiness Assistance program when their income is above the no-copay threshold and at or below this share of the state median income; above this share families fall in the highest-copay tier. +values: + 2025-11-01: 0.60 + +metadata: + unit: /1 + period: year + label: Arkansas SRA partial-subsidy SMI threshold + reference: + - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Full Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf + - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Part Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/state_share_by_tier.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/state_share_by_tier.yaml new file mode 100644 index 00000000000..dac09797fae --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/state_share_by_tier.yaml @@ -0,0 +1,79 @@ +description: Arkansas pays this share of the daily base rate by age category, time category, and family income tier (% SMI) under the School Readiness Assistance program. +metadata: + period: day + unit: /1 + label: Arkansas SRA state-share rate by income tier + breakdown: + - ar_sra_age_category + - ar_sra_time_category + - ar_sra_income_tier + reference: + - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Full Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf + - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Part Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf + - title: SRA Sliding Fee Scale with Rates and Copays - Benton/Washington Full Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf + - title: SRA Sliding Fee Scale with Rates and Copays - Benton/Washington Part Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf + +INFANT: + FULL_TIME: + LE_40: + 2025-11-01: 1.00 + GT_40_LE_60: + 2025-11-01: 0.80 + GT_60: + 2025-11-01: 0.70 + PART_TIME: + LE_40: + 2025-11-01: 1.00 + GT_40_LE_60: + 2025-11-01: 0.70 + GT_60: + 2025-11-01: 0.60 +TODDLER: + FULL_TIME: + LE_40: + 2025-11-01: 1.00 + GT_40_LE_60: + 2025-11-01: 0.80 + GT_60: + 2025-11-01: 0.70 + PART_TIME: + LE_40: + 2025-11-01: 1.00 + GT_40_LE_60: + 2025-11-01: 0.60 + GT_60: + 2025-11-01: 0.50 +PRESCHOOL: + FULL_TIME: + LE_40: + 2025-11-01: 1.00 + GT_40_LE_60: + 2025-11-01: 0.70 + GT_60: + 2025-11-01: 0.60 + PART_TIME: + LE_40: + 2025-11-01: 1.00 + GT_40_LE_60: + 2025-11-01: 0.60 + GT_60: + 2025-11-01: 0.50 +SCHOOL_AGED: + FULL_TIME: + LE_40: + 2025-11-01: 0.80 + GT_40_LE_60: + 2025-11-01: 0.50 + GT_60: + 2025-11-01: 0.30 + PART_TIME: + LE_40: + 2025-11-01: 0.70 + GT_40_LE_60: + 2025-11-01: 0.50 + GT_60: + 2025-11-01: 0.30 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml new file mode 100644 index 00000000000..b719675538f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml @@ -0,0 +1,67 @@ +- name: Case 1, child age 5 is under 13 and age-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_tax_unit_dependent: true + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_age_eligible: [false, true] + +- name: Case 2, child age 12 at boundary is age-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 35 + person2: + age: 12 + is_tax_unit_dependent: true + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_age_eligible: [false, true] + +- name: Case 3, child age 13 is not age-eligible (strict less than). + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 40 + person2: + age: 13 + is_tax_unit_dependent: true + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_age_eligible: [false, false] + +- name: Case 4, infant age 0 is age-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + person2: + age: 0 + is_tax_unit_dependent: true + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_age_eligible: [false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_asset_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_asset_eligible.yaml new file mode 100644 index 00000000000..6d082109ccf --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_asset_eligible.yaml @@ -0,0 +1,65 @@ +# Arkansas SRA asset limit: $1,000,000 (2025-10-01). +# Comparison is `assets <= limit` (inclusive at boundary). + +- name: Case 1, assets of $500,000 are below the limit and asset-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + person2: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_assets: 500_000 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_asset_eligible: true + +- name: Case 2, assets of exactly $1,000,000 are at the limit and asset-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + person2: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_assets: 1_000_000 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_asset_eligible: true + +- name: Case 3, assets of $1,000,001 exceed the limit and are not asset-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + person2: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_assets: 1_000_001 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_asset_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_child_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_child_eligible.yaml new file mode 100644 index 00000000000..1c8fdda467c --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_child_eligible.yaml @@ -0,0 +1,85 @@ +# Eligible-child test: age < 13 AND tax-unit dependent AND immigration-eligible. + +- name: Case 1, citizen child age 5 who is a dependent is eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_child_eligible: [false, true] + +- name: Case 2, child age 13 is not age-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 35 + person2: + age: 13 + is_tax_unit_dependent: true + immigration_status: CITIZEN + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_child_eligible: [false, false] + +- name: Case 3, undocumented child is not immigration-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + person2: + age: 5 + is_tax_unit_dependent: true + immigration_status: UNDOCUMENTED + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_child_eligible: [false, false] + +- name: Case 4, refugee child age 4 is eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: REFUGEE + tax_units: + tax_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_child_eligible: [false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml new file mode 100644 index 00000000000..7b8161e41fd --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml @@ -0,0 +1,144 @@ +# Overall SRA eligibility = in_effect AND has_eligible_child AND income-eligible +# AND asset-eligible AND (LI activity OR ESS) AND state_code == AR. + +- name: Case 1, all eligibility components met under the LI track. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + weekly_hours_worked: 35 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + +- name: Case 2, household income above 85 percent SMI fails eligibility. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + weekly_hours_worked: 35 + # Well above the 85% SMI annual cap of ~$52,182 for a family of 2 + employment_income: 100_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: false + +- name: Case 3, no eligible child fails eligibility. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + weekly_hours_worked: 35 + employment_income: 20_000 + immigration_status: CITIZEN + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: false + +- name: Case 4, parent activity below LI threshold and no ESS track fails eligibility. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + weekly_hours_worked: 20 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + was_tea_recipient: false + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: false + +- name: Case 5, ESS track 20 hours per week makes household eligible even below LI threshold. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 20 + employment_income: 15_000 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + was_tea_recipient: true + months_since_tea_exit: 6 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml new file mode 100644 index 00000000000..7b9f419a475 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml @@ -0,0 +1,122 @@ +# ESS eligibility: family must have exited TEA within the 24-month window +# AND not currently receiving TEA AND meet the year-specific activity hour +# threshold (20 hr/wk Yr1, 25 hr/wk Yr2). + +- name: Case 1, post-TEA family 6 months out with 20 hours per week is ESS-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 20 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + was_tea_recipient: true + months_since_tea_exit: 6 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: true + +- name: Case 2, family currently receiving TEA is not ESS-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 25 + # Force ar_tea > 0 by setting a recipient flag below + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + was_tea_recipient: true + months_since_tea_exit: 6 + ar_tea: 200 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: false + +- name: Case 3, post-TEA family 30 months out is past the 24-month window and not ESS-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 25 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + was_tea_recipient: true + months_since_tea_exit: 30 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: false + +- name: Case 4, family that never received TEA is not ESS-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 25 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + was_tea_recipient: false + months_since_tea_exit: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: false + +- name: Case 5, ESS Year 2 family with 25 hours per week is ESS-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 25 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + was_tea_recipient: true + months_since_tea_exit: 18 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml new file mode 100644 index 00000000000..7096e74cf53 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml @@ -0,0 +1,91 @@ +# SRA program is in effect from 2025-10-01 forward. +# The in_effect parameter gates ar_sra_eligible at the top level. +# This test verifies the gate by constructing an otherwise-eligible +# household in different periods. + +- name: Case 1, period 2025-01 is before SRA effective date so household is not eligible. + period: 2025-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + weekly_hours_worked: 35 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: false + +- name: Case 2, period 2026-01 is the SRA effective date and household is eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + weekly_hours_worked: 35 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + +- name: Case 3, period 2026-01 is well within the SRA era and household is eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + weekly_hours_worked: 35 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_income_eligible.yaml new file mode 100644 index 00000000000..f13396bfaf7 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_income_eligible.yaml @@ -0,0 +1,112 @@ +# Arkansas SMI for FFY 2026 is uprated automatically in PolicyEngine. +# AR base amount at 2026-01-01 (after uprating): $95,201.95 +# Household-size adjustment for 2 persons: 0.52 + 0.16 = 0.68 +# SMI(2) annual = 95,201.95 * 0.68 = $64,737.33 +# 85% income limit annual = $64,737.33 * 0.85 = $55,026.73 + +- name: Case 1, family income at 84.9 percent SMI is income-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + # 64,737.33 * 0.849 = $54,961.99 (below 85% SMI) + employment_income: 54_961 + immigration_status: CITIZEN + person2: + age: 4 + 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: AR + output: + is_ar_sra_income_eligible: true + +- name: Case 2, family income just at 85 percent SMI is income-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + # 64,737.33 * 0.85 = $55,026.73; use 55,026.72 to avoid float32 + # round-trip precision loss during MONTH/YEAR conversion. + employment_income: 55_026.72 + immigration_status: CITIZEN + person2: + age: 4 + 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: AR + output: + is_ar_sra_income_eligible: true + +- name: Case 3, family income at 85.1 percent SMI is not income-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + # 64,737.33 * 0.851 = $55,091.46 (above 85% SMI) + employment_income: 55_092 + immigration_status: CITIZEN + person2: + age: 4 + 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: AR + output: + is_ar_sra_income_eligible: false + +- name: Case 4, family with zero income is income-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + immigration_status: CITIZEN + person2: + age: 4 + 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: AR + output: + is_ar_sra_income_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml new file mode 100644 index 00000000000..a915089fe93 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml @@ -0,0 +1,113 @@ +# LI activity requirement: each adult head/spouse must engage in +# >=30 hr/wk of work, education, or full-time study. + +- name: Case 1, single parent works 30 hours per week exactly is activity-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + weekly_hours_worked: 30 + person2: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_li_activity_eligible: true + +- name: Case 2, single parent works 29 hours per week is not activity-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + weekly_hours_worked: 29 + person2: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_li_activity_eligible: false + +- name: Case 3, single parent works 31 hours per week is activity-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + weekly_hours_worked: 31 + person2: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_li_activity_eligible: true + +- name: Case 4, two parents both at or above 30 hours per week are activity-eligible. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 32 + weekly_hours_worked: 30 + person2: + age: 30 + weekly_hours_worked: 35 + person3: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: AR + output: + is_ar_sra_li_activity_eligible: true + +- name: Case 5, two-parent household with one parent below threshold fails activity test. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 32 + weekly_hours_worked: 35 + person2: + age: 30 + weekly_hours_worked: 20 + person3: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: AR + output: + is_ar_sra_li_activity_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.yaml new file mode 100644 index 00000000000..9734368474f --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.yaml @@ -0,0 +1,93 @@ +# Arkansas SRA countable income sums the parameterized list of income +# sources across adults only; income of children (<18) is excluded. +# The variable is MONTH-defined; YEAR-period income sources (e.g., +# employment_income) are auto-divided by 12 when accessed monthly. + +- name: Case 1, parent employment income is fully counted (annual $30,000 = $2,500/month). + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + employment_income: 30_000 + person2: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + ar_sra_countable_income: 2_500 + +- name: Case 2, child SSI is excluded (annual $25,000 parent earnings = $2,083.33/month). + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + employment_income: 25_000 + person2: + age: 8 + is_tax_unit_dependent: true + ssi: 9_000 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Only parent's $25,000 annual counts; child's SSI is excluded. + # Monthly: 25,000 / 12 = $2,083.33 + ar_sra_countable_income: 2_083.33 + +- name: Case 3, two adults combine earnings (annual $40,000 = $3,333.33/month). + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 32 + employment_income: 22_000 + person2: + age: 30 + employment_income: 18_000 + person3: + age: 3 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: AR + output: + ar_sra_countable_income: 3_333.33 + +- name: Case 4, zero-income family produces zero countable income. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + person2: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + ar_sra_countable_income: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml new file mode 100644 index 00000000000..15eb8354583 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml @@ -0,0 +1,304 @@ +# Arkansas SRA integration tests +# +# Reference parameters (Nov 1, 2025 rate sheet): +# AR SMI (FFY 2026, 4-person, 2025-10-01): $90,280/year +# SMI(2)=90,280*0.68=$61,390.40; SMI(3)=90,280*0.84=$75,835.20 +# 85% income limit: SMI*0.85 +# +# Income tier brackets (% SMI): LE_40 (<=40), GT_40_LE_60 (4060) +# Daily base rates (Statewide REGULAR): Infant FT $36, Toddler FT $35, +# Preschool FT $33, School-Aged FT $28; PT half (Infant $18, Toddler $17.50, +# Preschool $16.50, School-Aged $14). +# Daily base rates (Benton/Washington REGULAR): Infant FT $38, Toddler FT $37, +# Preschool FT $33, School-Aged FT $28; PT (Infant $19, Toddler $18.50, etc.). +# State share % by (age_category, time, tier): +# Toddler/Preschool/Infant FT: 1.00 / 0.80 / 0.70 (Preschool FT mid-tier 0.70) +# School-Aged FT: 0.80 / 0.50 / 0.30 (always copay) +# +# All scenarios use childcare_attending_days_per_month = 22 (typical weekday count). +# Pre-subsidy expenses are set high enough that the state-payment cap binds. + +- name: Case 1, LI single mother, 1 toddler, full-time, Statewide. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + # 90,280 * 0.68 * 0.50 = $30,695 (50% SMI -> GT_40_LE_60 tier) + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Toddler, Statewide, FT, GT_40_LE_60: + # base = $35, share = 0.80, daily state payment = $28.00 + # monthly state payment = 28 * 22 = $616 + ar_sra: 616 + +- name: Case 2, LI two-parent, 1 infant, full-time, Benton/Washington zone. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 32 + weekly_hours_worked: 30 + # 90,280 * 0.84 * 0.80 = $60,668 (80% SMI of 3-person SMI -> GT_60 tier) + employment_income: 60_668 + immigration_status: CITIZEN + person2: + age: 30 + weekly_hours_worked: 30 + immigration_status: CITIZEN + person3: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + 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: AR + county_str: BENTON_COUNTY_AR + output: + is_ar_sra_eligible: true + # Infant, Benton/Washington, FT, GT_60: + # base = $38, share = 0.70, daily state payment = $26.60 + # monthly state payment = 26.60 * 22 = $585.20 + ar_sra: 585.20 + +- name: Case 3, LI single parent, 1 preschooler, FT, Statewide, no-copay floor at LE_40. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + # 90,280 * 0.68 * 0.35 = $21,486.66 (35% SMI -> LE_40 tier) + employment_income: 21_487 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Preschool, Statewide, FT, LE_40 (no-copay tier): + # base = $33, share = 1.00, daily state payment = $33.00 + # monthly state payment = 33 * 22 = $726 + ar_sra: 726 + +- name: Case 4, ESS Year 1 (post-TEA 6 months, 22 hr/wk), 1 toddler, FT, Statewide. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 26 + weekly_hours_worked: 22 + # 90,280 * 0.68 * 0.30 = $18,417 (30% SMI -> LE_40 tier) + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + was_tea_recipient: true + months_since_tea_exit: 6 + ar_tea: 0 + spm_unit_pre_subsidy_childcare_expenses: 20_000 + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Toddler, Statewide, FT, LE_40 (no-copay tier): + # base = $35, share = 1.00, daily state payment = $35.00 + # monthly state payment = 35 * 22 = $770 + ar_sra: 770 + +- name: Case 5, ESS Year 2 (post-TEA 18 months, 26 hr/wk), 1 toddler, FT, Statewide. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 27 + weekly_hours_worked: 26 + # 90,280 * 0.68 * 0.45 = $27,625.69 (45% SMI -> GT_40_LE_60 tier) + employment_income: 27_626 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + was_tea_recipient: true + months_since_tea_exit: 18 + ar_tea: 0 + spm_unit_pre_subsidy_childcare_expenses: 20_000 + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Toddler, Statewide, FT, GT_40_LE_60: + # base = $35, share = 0.80, daily state payment = $28.00 + # monthly state payment = 28 * 22 = $616 + ar_sra: 616 + +- name: Case 6, family income above 85 percent SMI gets zero benefit. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + weekly_hours_worked: 35 + # Well above 85% SMI annual cap + employment_income: 100_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: false + ar_sra: 0 + +- name: Case 7, AR resident in pre-SRA period gets zero benefit. + period: 2025-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + weekly_hours_worked: 35 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: false + ar_sra: 0 + +- name: Case 8, non-AR household (state_code CA) gets zero benefit despite otherwise meeting criteria. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + weekly_hours_worked: 35 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + 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: CA + output: + ar_sra: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_age_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_age_category.yaml new file mode 100644 index 00000000000..333cabb6382 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_age_category.yaml @@ -0,0 +1,60 @@ +# Age category bracket thresholds (months): +# <=17 months -> INFANT +# 18-35 months -> TODDLER +# 36-71 months -> PRESCHOOL +# 72+ months -> SCHOOL_AGED +# +# Test inputs use age in years. The formula multiplies by MONTHS_IN_YEAR +# to compare against month-based bracket thresholds. + +- name: Case 1, eight-month-old child (0.667 years) is in the INFANT category. + period: 2026-01 + input: + people: + person1: + age: 0.667 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_age_category: INFANT + +- name: Case 2, two-year-old child (24 months) is in the TODDLER category. + period: 2026-01 + input: + people: + person1: + age: 2 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_age_category: TODDLER + +- name: Case 3, four-year-old child (48 months) is in the PRESCHOOL category. + period: 2026-01 + input: + people: + person1: + age: 4 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_age_category: PRESCHOOL + +- name: Case 4, seven-year-old child (84 months) is in the SCHOOL_AGED category. + period: 2026-01 + input: + people: + person1: + age: 7 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_age_category: SCHOOL_AGED diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml new file mode 100644 index 00000000000..838183778ff --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml @@ -0,0 +1,226 @@ +# Daily base rates from rates/base_rate.yaml lookup +# Keyed by (zone, age_category, care_type, time_category). +# Care type defaults to REGULAR; verified by parameter breakdown. +# +# Selected verified values for testing (Nov 1, 2025 rate sheet): +# STATEWIDE / INFANT / REGULAR / FT = $36.00 +# STATEWIDE / TODDLER / REGULAR / FT = $35.00 +# STATEWIDE / PRESCHOOL / REGULAR / FT = $33.00 +# STATEWIDE / SCHOOL_AGED / REGULAR / FT = $28.00 +# BENTON_WASHINGTON / INFANT / REGULAR / FT = $38.00 +# BENTON_WASHINGTON / TODDLER / REGULAR / FT = $37.00 +# STATEWIDE / INFANT / REGULAR / PT = $18.00 +# BENTON_WASHINGTON / INFANT / REGULAR / PT = $19.00 + +- name: Case 1, Statewide infant full time base rate is 36.00. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 0 + childcare_hours_per_week: 40 + households: + household: + members: [person1] + county_str: PULASKI_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 36.00 + +- name: Case 2, Statewide toddler full time base rate is 35.00. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 2 + childcare_hours_per_week: 40 + households: + household: + members: [person1] + county_str: PULASKI_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 35.00 + +- name: Case 3, Statewide preschool full time base rate is 33.00. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 4 + childcare_hours_per_week: 40 + households: + household: + members: [person1] + county_str: PULASKI_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 33.00 + +- name: Case 4, Statewide school-aged full time base rate is 28.00. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 7 + childcare_hours_per_week: 40 + households: + household: + members: [person1] + county_str: PULASKI_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 28.00 + +- name: Case 5, Benton/Washington infant full time base rate is 38.00. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 0 + childcare_hours_per_week: 40 + households: + household: + members: [person1] + county_str: BENTON_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 38.00 + +- name: Case 6, Benton/Washington toddler full time base rate is 37.00. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 2 + childcare_hours_per_week: 40 + households: + household: + members: [person1] + county_str: WASHINGTON_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 37.00 + +- name: Case 7, Statewide infant part time base rate is 18.00. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 0 + childcare_hours_per_week: 20 + households: + household: + members: [person1] + county_str: PULASKI_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 18.00 + +- name: Case 8, Benton/Washington infant part time base rate is 19.00. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 0 + childcare_hours_per_week: 20 + households: + household: + members: [person1] + county_str: BENTON_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 19.00 + +- name: Case 9, Statewide infant Night/Weekend full time base rate is 39.60. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 0 + childcare_hours_per_week: 40 + ar_sra_care_type: NIGHT_WEEKEND + households: + household: + members: [person1] + county_str: PULASKI_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 39.60 + +- name: Case 10, Statewide infant SN1 full time base rate is 36.00. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 0 + childcare_hours_per_week: 40 + ar_sra_care_type: SN1 + households: + household: + members: [person1] + county_str: PULASKI_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 36.00 + +- name: Case 11, Statewide infant SN2 full time base rate is 50.40. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 0 + childcare_hours_per_week: 40 + ar_sra_care_type: SN2 + households: + household: + members: [person1] + county_str: PULASKI_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 50.40 + +- name: Case 12, Statewide infant SN3 full time base rate is 50.40. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 0 + childcare_hours_per_week: 40 + ar_sra_care_type: SN3 + households: + household: + members: [person1] + county_str: PULASKI_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 50.40 + +- name: Case 13, Statewide preschool Night/Weekend full time base rate is 36.30. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 4 + childcare_hours_per_week: 40 + ar_sra_care_type: NIGHT_WEEKEND + households: + household: + members: [person1] + county_str: PULASKI_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 36.30 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml new file mode 100644 index 00000000000..dcccc4062ce --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml @@ -0,0 +1,94 @@ +# Daily family copay per child = daily_base_rate * (1 - state_share). + +- name: Case 1, Toddler Statewide FT at LE_40 SMI has zero copay (share 1.00). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + # 30% SMI -> LE_40 tier + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + # Statewide / Toddler / REGULAR / FT base = $35.00, share = 1.00 + # daily copay = $35 * (1 - 1.00) = $0.00 + ar_sra_daily_copay: [0, 0.00] + +- name: Case 2, School-Aged Statewide FT at LE_40 SMI has positive copay (20 percent of base). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + # 30% SMI -> LE_40 tier + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + # Statewide / School-Aged / REGULAR / FT base = $28.00, share = 0.80 + # daily copay = $28 * (1 - 0.80) = $5.60 + ar_sra_daily_copay: [0, 5.60] + +- name: Case 3, Preschool Statewide FT at GT_60 SMI has copay 40 percent of base. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + # 75% SMI -> GT_60 tier + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + # Statewide / Preschool / REGULAR / FT base = $33.00, share = 0.60 + # daily copay = $33 * (1 - 0.60) = $13.20 + ar_sra_daily_copay: [0, 13.20] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml new file mode 100644 index 00000000000..6d3cf791a4b --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml @@ -0,0 +1,97 @@ +# Daily state payment per child = daily_base_rate * state_share. +# +# Arkansas SMI (2025-10-01, FFY 2026, 4-person): $90,280/year +# 2-person SPM: SMI = $61,390.40 annual + +- name: Case 1, Toddler Statewide FT at LE_40 SMI pays full base rate (no-copay). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + # 30% SMI -> LE_40 tier + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + # Statewide / Toddler / REGULAR / FT base = $35.00; share = 1.00 + # daily state payment = $35.00 * 1.00 = $35.00 + ar_sra_daily_state_payment: [0, 35.00] + +- name: Case 2, School-Aged Statewide FT at LE_40 SMI has positive copay (share 0.80). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + # 30% SMI -> LE_40 tier + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + # Statewide / School-Aged / REGULAR / FT base = $28.00; share = 0.80 + # daily state payment = $28.00 * 0.80 = $22.40 + ar_sra_daily_state_payment: [0, 22.40] + +- name: Case 3, Infant Benton/Washington FT at GT_60 SMI gets reduced share. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + # 75% SMI -> GT_60 tier + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: BENTON_COUNTY_AR + output: + # Benton/Washington / Infant / REGULAR / FT base = $38.00; share = 0.70 + # daily state payment = $38.00 * 0.70 = $26.60 + ar_sra_daily_state_payment: [0, 26.60] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml new file mode 100644 index 00000000000..73b0f7c7542 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml @@ -0,0 +1,88 @@ +# Income tiers (% SMI): +# LE_40: <= 40% SMI +# GT_40_LE_60: > 40%, <= 60% SMI +# GT_60: > 60% SMI +# +# Arkansas SMI (uprated at 2026-01-01): $95,201.95 +# 2-person SPM (parent + child): SMI = 95,201.95 * 0.68 = $64,737.33 annual + +- name: Case 1, family at 30 percent SMI is in the LE_40 tier. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + # 64,737.33 * 0.30 = $19,421.20 + employment_income: 19_421 + immigration_status: CITIZEN + person2: + age: 4 + 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: AR + output: + ar_sra_income_tier: LE_40 + +- name: Case 2, family at 50 percent SMI is in the GT_40_LE_60 tier. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + # 64,737.33 * 0.50 = $32,368.67 + employment_income: 32_369 + immigration_status: CITIZEN + person2: + age: 4 + 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: AR + output: + ar_sra_income_tier: GT_40_LE_60 + +- name: Case 3, family at 75 percent SMI is in the GT_60 tier. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + # 64,737.33 * 0.75 = $48,553.00 + employment_income: 48_553 + immigration_status: CITIZEN + person2: + age: 4 + 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: AR + output: + ar_sra_income_tier: GT_60 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.yaml new file mode 100644 index 00000000000..fa2a5967c25 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.yaml @@ -0,0 +1,129 @@ +# State payment share from rates/state_share_by_tier.yaml lookup +# Keyed by (age_category, time_category, income_tier). +# +# Examples (from parameter): +# Toddler FT LE_40 = 1.00 (no copay floor) +# Toddler FT GT_40_LE_60 = 0.80 +# Toddler FT GT_60 = 0.70 +# Preschool FT LE_40 = 1.00 +# Preschool FT GT_40_LE_60 = 0.70 +# School-Aged FT LE_40 = 0.80 (always copay) +# School-Aged FT GT_60 = 0.30 +# +# Arkansas SMI (2025-10-01, FFY 2026, 4-person): $90,280/year +# 2-person SPM: SMI = 90,280 * 0.68 = $61,390.40 annual + +- name: Case 1, toddler at 30 percent SMI gets state share 1.00 (no-copay floor). + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + # 90,280 * 0.68 * 0.30 = $18,417.12 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + ar_sra_state_share: [0, 1.00] + +- name: Case 2, preschooler at 50 percent SMI (FT) gets state share 0.70. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + # 90,280 * 0.68 * 0.50 = $30,695.20 + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Preschool FT GT_40_LE_60 = 0.70 + ar_sra_state_share: [0, 0.70] + +- name: Case 3, school-aged child at 80 percent SMI (FT) gets state share 0.30. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + # 90,280 * 0.68 * 0.80 = $49,112.32 (above 60% SMI -> GT_60 tier) + employment_income: 49_112 + immigration_status: CITIZEN + person2: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # School-Aged FT GT_60 = 0.30 + ar_sra_state_share: [0, 0.30] + +- name: Case 4, school-aged child at 30 percent SMI (FT) still has copay (share 0.80). + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + # 90,280 * 0.68 * 0.30 = $18,417.12 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # School-Aged FT LE_40 = 0.80 (school-aged always has copay) + ar_sra_state_share: [0, 0.80] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_time_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_time_category.yaml new file mode 100644 index 00000000000..92fe0e68285 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_time_category.yaml @@ -0,0 +1,67 @@ +# Time category: >=30 hr/wk -> FULL_TIME, otherwise PART_TIME. +# Threshold parameter: gov.states.ar.ade.oec.sra.rates.full_time_hours_threshold = 30 + +- name: Case 1, 30 hours per week is FULL_TIME at the threshold. + period: 2026-01 + input: + people: + person1: + childcare_hours_per_week: 30 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_time_category: FULL_TIME + +- name: Case 2, 35 hours per week is FULL_TIME. + period: 2026-01 + input: + people: + person1: + childcare_hours_per_week: 35 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_time_category: FULL_TIME + +- name: Case 3, 25 hours per week is PART_TIME. + period: 2026-01 + input: + people: + person1: + childcare_hours_per_week: 25 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_time_category: PART_TIME + +- name: Case 4, 29 hours per week is PART_TIME just below the threshold. + period: 2026-01 + input: + people: + person1: + childcare_hours_per_week: 29 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_time_category: PART_TIME + +- name: Case 5, 0 hours per week is PART_TIME. + period: 2026-01 + input: + people: + person1: + childcare_hours_per_week: 0 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_time_category: PART_TIME diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_zone.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_zone.yaml new file mode 100644 index 00000000000..f8525bd7956 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_zone.yaml @@ -0,0 +1,26 @@ +# SRA rate zones: Benton and Washington Counties (Northwest Arkansas) +# vs. STATEWIDE for every other AR county. + +- name: Case 1, Benton County is in the BENTON_WASHINGTON zone. + period: 2026-01 + input: + county_str: BENTON_COUNTY_AR + state_code: AR + output: + ar_sra_zone: BENTON_WASHINGTON + +- name: Case 2, Washington County is in the BENTON_WASHINGTON zone. + period: 2026-01 + input: + county_str: WASHINGTON_COUNTY_AR + state_code: AR + output: + ar_sra_zone: BENTON_WASHINGTON + +- name: Case 3, Pulaski County (Little Rock) is in the STATEWIDE zone. + period: 2026-01 + input: + county_str: PULASKI_COUNTY_AR + state_code: AR + output: + ar_sra_zone: STATEWIDE diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_child_care_subsidies.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_child_care_subsidies.py new file mode 100644 index 00000000000..f0aeb2b7fe8 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_child_care_subsidies.py @@ -0,0 +1,11 @@ +from policyengine_us.model_api import * + + +class ar_child_care_subsidies(Variable): + value_type = float + entity = SPMUnit + label = "Arkansas child care subsidies" + unit = USD + definition_period = YEAR + defined_for = StateCode.AR + adds = ["ar_sra"] diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py new file mode 100644 index 00000000000..01a2ca5c698 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py @@ -0,0 +1,30 @@ +from policyengine_us.model_api import * + + +class ar_sra(Variable): + value_type = float + entity = SPMUnit + unit = USD + label = "Arkansas School Readiness Assistance benefit amount" + definition_period = MONTH + defined_for = "is_ar_sra_eligible" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/R_&_R__Nov_2025_(English)_(1)_OEC.pdf#page=1", + ) + + def formula(spm_unit, period, parameters): + person = spm_unit.members + is_eligible_child = person("is_ar_sra_child_eligible", period) + daily_state_payment = person("ar_sra_daily_state_payment", period) + daily_copay = person("ar_sra_daily_copay", period) + attending_days = person("childcare_attending_days_per_month", period.this_year) + monthly_max_state_payment = daily_state_payment * attending_days + monthly_copay = daily_copay * attending_days + annual_expense = person("pre_subsidy_childcare_expenses", period.this_year) + monthly_expense = annual_expense / MONTHS_IN_YEAR + subsidy = min_( + max_(monthly_expense - monthly_copay, 0), + monthly_max_state_payment, + ) + return spm_unit.sum(subsidy * is_eligible_child) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py new file mode 100644 index 00000000000..4d9331f0120 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py @@ -0,0 +1,30 @@ +from policyengine_us.model_api import * + + +class ArSraAgeCategory(Enum): + INFANT = "Infant" + TODDLER = "Toddler" + PRESCHOOL = "Preschool" + SCHOOL_AGED = "School-Aged" + + +class ar_sra_age_category(Variable): + value_type = Enum + entity = Person + possible_values = ArSraAgeCategory + default_value = ArSraAgeCategory.INFANT + definition_period = MONTH + defined_for = StateCode.AR + label = "Arkansas SRA child age category" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ar.ade.oec.sra.rates.age_category_months + # `age` is YEAR-defined; `period.this_year` returns age in years (float). + # Multiply by 12 to compare against month-based thresholds. + age_months = person("age", period.this_year) * MONTHS_IN_YEAR + # The bracket returns the integer enum index (0=INFANT, 1=TODDLER, + # 2=PRESCHOOL, 3=SCHOOL_AGED); PolicyEngine maps it to the enum. + return p.calc(age_months) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_care_type.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_care_type.py new file mode 100644 index 00000000000..b415a9fb944 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_care_type.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class ArSraCareType(Enum): + REGULAR = "Regular" + NIGHT_WEEKEND = "Night/Weekend" + SN1 = "Special Needs Level 1" + SN2 = "Special Needs Level 2" + SN3 = "Special Needs Level 3" + + +class ar_sra_care_type(Variable): + value_type = Enum + entity = Person + possible_values = ArSraCareType + default_value = ArSraCareType.REGULAR + definition_period = MONTH + defined_for = StateCode.AR + label = "Arkansas SRA care type" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + ) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py new file mode 100644 index 00000000000..e8ab3292ec0 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py @@ -0,0 +1,34 @@ +from policyengine_us.model_api import * + + +class ArSraIncomeTier(Enum): + LE_40 = "At or below 40% SMI" + GT_40_LE_60 = "Above 40% and at or below 60% SMI" + GT_60 = "Above 60% SMI" + + +class ar_sra_income_tier(Variable): + value_type = Enum + entity = SPMUnit + possible_values = ArSraIncomeTier + default_value = ArSraIncomeTier.GT_60 + definition_period = MONTH + defined_for = StateCode.AR + label = "Arkansas SRA family income tier (% SMI)" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ar.ade.oec.sra + annual_income = spm_unit("ar_sra_countable_income", period) * MONTHS_IN_YEAR + smi = spm_unit("hhs_smi", period.this_year) + ratio = where(smi > 0, annual_income / smi, np.inf) + return select( + [ + ratio <= p.rates.no_copay_smi_threshold, + ratio <= p.rates.partial_subsidy_smi_threshold, + ], + [ArSraIncomeTier.LE_40, ArSraIncomeTier.GT_40_LE_60], + default=ArSraIncomeTier.GT_60, + ) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_time_category.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_time_category.py new file mode 100644 index 00000000000..f643f6b35e1 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_time_category.py @@ -0,0 +1,29 @@ +from policyengine_us.model_api import * + + +class ArSraTimeCategory(Enum): + FULL_TIME = "Full-Time" + PART_TIME = "Part-Time" + + +class ar_sra_time_category(Variable): + value_type = Enum + entity = Person + possible_values = ArSraTimeCategory + default_value = ArSraTimeCategory.FULL_TIME + definition_period = MONTH + defined_for = StateCode.AR + label = "Arkansas SRA time category" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ar.ade.oec.sra.rates + hours = person("childcare_hours_per_week", period.this_year) + return where( + hours >= p.full_time_hours_threshold, + ArSraTimeCategory.FULL_TIME, + ArSraTimeCategory.PART_TIME, + ) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_zone.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_zone.py new file mode 100644 index 00000000000..153147b73f9 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_zone.py @@ -0,0 +1,35 @@ +from policyengine_us.model_api import * + + +class ArSraZone(Enum): + BENTON_WASHINGTON = "Benton/Washington" + STATEWIDE = "Statewide" + + +class ar_sra_zone(Variable): + value_type = Enum + entity = Household + possible_values = ArSraZone + default_value = ArSraZone.STATEWIDE + definition_period = MONTH + defined_for = StateCode.AR + label = "Arkansas SRA rate zone" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + ) + + def formula(household, period, parameters): + # `defined_for = StateCode.AR` filters output but does NOT short-circuit + # vectorized execution, so non-AR county strings would still flow into + # this lookup. Guard by checking state first. + state = household("state_code_str", period.this_year) + county = household("county_str", period.this_year) + in_benton_washington = (state == "AR") & ( + (county == "BENTON_COUNTY_AR") | (county == "WASHINGTON_COUNTY_AR") + ) + return where( + in_benton_washington, + ArSraZone.BENTON_WASHINGTON, + ArSraZone.STATEWIDE, + ) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py new file mode 100644 index 00000000000..97bb547dd98 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class is_ar_sra_age_eligible(Variable): + value_type = bool + entity = Person + label = "Age-eligible for Arkansas SRA" + definition_period = MONTH + defined_for = StateCode.AR + reference = ( + "https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11", + "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=13", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ar.ade.oec.sra.eligibility + age = person("age", period.this_year) + return age < p.child_age_limit diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_asset_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_asset_eligible.py new file mode 100644 index 00000000000..deb00a53464 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_asset_eligible.py @@ -0,0 +1,17 @@ +from policyengine_us.model_api import * + + +class is_ar_sra_asset_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Asset-eligible for Arkansas SRA" + definition_period = MONTH + defined_for = StateCode.AR + reference = ( + "https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=25", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ar.ade.oec.sra.eligibility + assets = spm_unit("spm_unit_assets", period.this_year) + return assets <= p.asset_limit diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_child_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_child_eligible.py new file mode 100644 index 00000000000..663ecf59569 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_child_eligible.py @@ -0,0 +1,20 @@ +from policyengine_us.model_api import * + + +class is_ar_sra_child_eligible(Variable): + value_type = bool + entity = Person + label = "Eligible child for Arkansas SRA" + definition_period = MONTH + defined_for = StateCode.AR + reference = ( + "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=14", + "https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11", + ) + + def formula(person, period, parameters): + age_eligible = person("is_ar_sra_age_eligible", period) + immigration_eligible = person( + "is_ccdf_immigration_eligible_child", period.this_year + ) + return age_eligible & immigration_eligible diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py new file mode 100644 index 00000000000..c168e0895bc --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py @@ -0,0 +1,25 @@ +from policyengine_us.model_api import * + + +class is_ar_sra_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Arkansas School Readiness Assistance" + definition_period = MONTH + defined_for = StateCode.AR + reference = ( + "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=13", + "https://dese.ade.arkansas.gov/Files/R_&_R__Nov_2025_(English)_(1)_OEC.pdf#page=1", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ar.ade.oec.sra + if not p.in_effect: + return False + has_eligible_child = add(spm_unit, period, ["is_ar_sra_child_eligible"]) > 0 + income_ok = spm_unit("is_ar_sra_income_eligible", period) + asset_ok = spm_unit("is_ar_sra_asset_eligible", period) + li_active = spm_unit("is_ar_sra_li_activity_eligible", period) + ess_active = spm_unit("is_ar_sra_ess_eligible", period) + activity_ok = li_active | ess_active + return has_eligible_child & income_ok & asset_ok & activity_ok diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py new file mode 100644 index 00000000000..80b8fe170b2 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py @@ -0,0 +1,28 @@ +from policyengine_us.model_api import * + + +class is_ar_sra_ess_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Eligible for Arkansas SRA Extended Support Services (ESS) track" + definition_period = MONTH + defined_for = StateCode.AR + reference = ( + "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ar.ade.oec.sra.eligibility + was_tea = spm_unit("was_tea_recipient", period.this_year) + months_since = spm_unit("months_since_tea_exit", period) + ar_tea = spm_unit("ar_tea", period) + within_window = (months_since > 0) & (months_since <= p.ess_window_months) + in_track = was_tea & (ar_tea == 0) & within_window + in_year_1 = months_since <= p.ess_year_1_window_months + person = spm_unit.members + hours = person("weekly_hours_worked", period.this_year) + max_hours = spm_unit.max(hours) + year_1_active = max_hours >= p.activity_hours_ess_year_1 + year_2_active = max_hours >= p.activity_hours_ess_year_2 + activity_ok = where(in_year_1, year_1_active, year_2_active) + return in_track & activity_ok diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py new file mode 100644 index 00000000000..d04712ea794 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class is_ar_sra_income_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Income-eligible for Arkansas SRA" + definition_period = MONTH + defined_for = StateCode.AR + reference = ( + "https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=22", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ar.ade.oec.sra.eligibility + # `ar_sra_countable_income` is monthly; `hhs_smi` is annual. + annual_income = spm_unit("ar_sra_countable_income", period) * MONTHS_IN_YEAR + smi = spm_unit("hhs_smi", period.this_year) + return annual_income <= smi * p.income_smi_rate diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py new file mode 100644 index 00000000000..9f05194134d --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class is_ar_sra_li_activity_eligible(Variable): + value_type = bool + entity = SPMUnit + label = "Activity-eligible for Arkansas SRA Low-Income track" + definition_period = MONTH + defined_for = StateCode.AR + reference = ( + "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ar.ade.oec.sra.eligibility + person = spm_unit.members + is_head_or_spouse = person("is_tax_unit_head_or_spouse", period.this_year) + hours = person("weekly_hours_worked", period.this_year) + is_student = person("is_full_time_student", period.this_year) + meets_threshold = (hours >= p.activity_hours_li) | is_student + # All adults (heads/spouses) must meet the threshold. + return spm_unit.sum(is_head_or_spouse & ~meets_threshold) == 0 diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.py new file mode 100644 index 00000000000..3ba404387d6 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.py @@ -0,0 +1,27 @@ +from policyengine_us.model_api import * + + +class ar_sra_countable_income(Variable): + value_type = float + entity = SPMUnit + label = "Arkansas SRA countable income" + unit = USD + definition_period = MONTH + defined_for = StateCode.AR + reference = ( + "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=19", + "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=20", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ar.ade.oec.sra.income + # FSU Manual Section 4.3.2: SSI and Social Security of children under + # 18 are excluded from countable income. Sum each listed source per + # person and mask out child contributions before aggregating to the + # SPM unit. + person = spm_unit.members + # `age` is YEAR-defined; period.this_year reverses auto-division so + # this returns age in years for monthly periods. + is_adult = person("age", period.this_year) >= 18 + per_person_income = sum(person(source, period) for source in p.sources) + return spm_unit.sum(per_person_income * is_adult) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/months_since_tea_exit.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/months_since_tea_exit.py new file mode 100644 index 00000000000..c39f2d02e3c --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/months_since_tea_exit.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class months_since_tea_exit(Variable): + value_type = int + entity = SPMUnit + label = "Months since Arkansas TEA cash aid ended" + definition_period = MONTH + defined_for = StateCode.AR + default_value = 0 + reference = ( + "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16", + ) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py new file mode 100644 index 00000000000..85a761b72d3 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class ar_sra_daily_base_rate(Variable): + value_type = float + entity = Person + unit = USD + label = "Arkansas SRA daily base provider rate" + definition_period = MONTH + defined_for = "is_ar_sra_child_eligible" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ar.ade.oec.sra.rates + zone = person.household("ar_sra_zone", period) + age_category = person("ar_sra_age_category", period) + care_type = person("ar_sra_care_type", period) + time_category = person("ar_sra_time_category", period) + return p.base_rate[zone][age_category][care_type][time_category] diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py new file mode 100644 index 00000000000..3ee8f330b04 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class ar_sra_daily_copay(Variable): + value_type = float + entity = Person + unit = USD + label = "Arkansas SRA daily family copay" + definition_period = MONTH + defined_for = "is_ar_sra_child_eligible" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + ) + + def formula(person, period, parameters): + base = person("ar_sra_daily_base_rate", period) + state_share = person("ar_sra_state_share", period) + return base * (1 - state_share) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py new file mode 100644 index 00000000000..d64462f51ac --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py @@ -0,0 +1,18 @@ +from policyengine_us.model_api import * + + +class ar_sra_daily_state_payment(Variable): + value_type = float + entity = Person + unit = USD + label = "Arkansas SRA daily state payment per child" + definition_period = MONTH + defined_for = "is_ar_sra_child_eligible" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + ) + + def formula(person, period, parameters): + base = person("ar_sra_daily_base_rate", period) + state_share = person("ar_sra_state_share", period) + return base * state_share diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py new file mode 100644 index 00000000000..4dc1bba98aa --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class ar_sra_state_share(Variable): + value_type = float + entity = Person + label = "Arkansas SRA state share of daily base rate" + definition_period = MONTH + defined_for = "is_ar_sra_child_eligible" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ar.ade.oec.sra.rates + age_category = person("ar_sra_age_category", period) + time_category = person("ar_sra_time_category", period) + income_tier = person.spm_unit("ar_sra_income_tier", period) + return p.state_share_by_tier[age_category][time_category][income_tier] diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/was_tea_recipient.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/was_tea_recipient.py new file mode 100644 index 00000000000..a52588900f1 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/was_tea_recipient.py @@ -0,0 +1,13 @@ +from policyengine_us.model_api import * + + +class was_tea_recipient(Variable): + value_type = bool + entity = SPMUnit + label = "Was an Arkansas Transitional Employment Assistance recipient" + definition_period = YEAR + defined_for = StateCode.AR + default_value = False + reference = ( + "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16", + ) From 63a8180a348e46b8b7e5272d91e8d7950b697191 Mon Sep 17 00:00:00 2001 From: Ziming Date: Fri, 15 May 2026 10:43:30 -0400 Subject: [PATCH 03/17] Review-fix round 1: address critical issues from /review-program - Delete reinvented is_ar_sra_asset_eligible; delegate to federal is_ccdf_asset_eligible - Add ar_child_care_subsidies to gov/hhs/ccdf/child_care_subsidy_programs.yaml - Register AR SRA in programs.yaml under CCDF state implementations - Align in_effect.yaml start date to 2025-11-01 to match published rate sheets (Oct 2025 had different transitional rates and is documented as not-modeled) --- .../hhs/ccdf/child_care_subsidy_programs.yaml | 1 + .../ade/oec/sra/eligibility/asset_limit.yaml | 13 ---- .../gov/states/ar/ade/oec/sra/in_effect.yaml | 7 +- policyengine_us/programs.yaml | 8 ++- .../eligibility/ar_sra_asset_eligible.yaml | 65 ------------------- .../eligibility/is_ar_sra_asset_eligible.py | 17 ----- .../oec/sra/eligibility/is_ar_sra_eligible.py | 2 +- 7 files changed, 15 insertions(+), 98 deletions(-) delete mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/asset_limit.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_asset_eligible.yaml delete mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_asset_eligible.py diff --git a/policyengine_us/parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml b/policyengine_us/parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml index 89dc3c0bef2..3cd1637b75f 100644 --- a/policyengine_us/parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml +++ b/policyengine_us/parameters/gov/hhs/ccdf/child_care_subsidy_programs.yaml @@ -1,6 +1,7 @@ description: The federal government counts these state programs as child care subsidies. values: 2021-01-01: + - ar_child_care_subsidies # Arkansas School Readiness Assistance - ca_child_care_subsidies # California Child Care - co_child_care_subsidies # Colorado Child Care Assistance Program - ct_child_care_subsidies # Connecticut Care 4 Kids diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/asset_limit.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/asset_limit.yaml deleted file mode 100644 index 95f6b79ff06..00000000000 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/asset_limit.yaml +++ /dev/null @@ -1,13 +0,0 @@ -description: Arkansas limits family assets to this amount under the School Readiness Assistance program. -values: - 2025-10-01: 1_000_000 - -metadata: - unit: currency-USD - period: year - label: Arkansas SRA asset limit - reference: - - title: Arkansas CCDF Plan 2025-2027, Section 2.2.6 - href: https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=25 - - title: OEC Rights & Responsibilities (Nov 2025) - href: https://dese.ade.arkansas.gov/Files/R_&_R__Nov_2025_(English)_(1)_OEC.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml index 321e91f8032..1dade55acd8 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml @@ -1,7 +1,12 @@ description: Arkansas operates the School Readiness Assistance child care subsidy program if this is true. +# The SRA program legally launched 2025-10-01, but the Oct 2025 rate schedule +# (higher rates plus a one-month Quality Enhancement Payment) was replaced on +# 2025-11-01 by the rate sheet currently encoded. We gate the program to the +# Nov 1, 2025 rate-aligned period; the Oct 2025 transitional month is not +# modeled because its rates and QEP supplement are not in the parameter tree. values: 1900-01-01: false - 2025-10-01: true + 2025-11-01: true metadata: unit: bool diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 76b5377b5f3..bd546befdf1 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -460,8 +460,14 @@ programs: category: Benefits agency: HHS status: partial - coverage: CA, CO, CT, DE, DC, IL, MA, MD, ME, NC, NH, NJ, PA, RI, SC, TX, VA, VT, WV + coverage: AR, CA, CO, CT, DE, DC, IL, MA, MD, ME, NC, NH, NJ, PA, RI, SC, TX, VA, VT, WV state_implementations: + - state: AR + status: complete + name: Arkansas SRA + full_name: Arkansas School Readiness Assistance + variable: ar_sra + parameter_prefix: gov.states.ar.ade.oec.sra - state: CA status: complete name: CalWORKs childcare diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_asset_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_asset_eligible.yaml deleted file mode 100644 index 6d082109ccf..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_asset_eligible.yaml +++ /dev/null @@ -1,65 +0,0 @@ -# Arkansas SRA asset limit: $1,000,000 (2025-10-01). -# Comparison is `assets <= limit` (inclusive at boundary). - -- name: Case 1, assets of $500,000 are below the limit and asset-eligible. - period: 2026-01 - absolute_error_margin: 0.1 - input: - people: - person1: - age: 30 - person2: - age: 4 - is_tax_unit_dependent: true - spm_units: - spm_unit: - members: [person1, person2] - spm_unit_assets: 500_000 - households: - household: - members: [person1, person2] - state_code: AR - output: - is_ar_sra_asset_eligible: true - -- name: Case 2, assets of exactly $1,000,000 are at the limit and asset-eligible. - period: 2026-01 - absolute_error_margin: 0.1 - input: - people: - person1: - age: 30 - person2: - age: 4 - is_tax_unit_dependent: true - spm_units: - spm_unit: - members: [person1, person2] - spm_unit_assets: 1_000_000 - households: - household: - members: [person1, person2] - state_code: AR - output: - is_ar_sra_asset_eligible: true - -- name: Case 3, assets of $1,000,001 exceed the limit and are not asset-eligible. - period: 2026-01 - absolute_error_margin: 0.1 - input: - people: - person1: - age: 30 - person2: - age: 4 - is_tax_unit_dependent: true - spm_units: - spm_unit: - members: [person1, person2] - spm_unit_assets: 1_000_001 - households: - household: - members: [person1, person2] - state_code: AR - output: - is_ar_sra_asset_eligible: false diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_asset_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_asset_eligible.py deleted file mode 100644 index deb00a53464..00000000000 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_asset_eligible.py +++ /dev/null @@ -1,17 +0,0 @@ -from policyengine_us.model_api import * - - -class is_ar_sra_asset_eligible(Variable): - value_type = bool - entity = SPMUnit - label = "Asset-eligible for Arkansas SRA" - definition_period = MONTH - defined_for = StateCode.AR - reference = ( - "https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=25", - ) - - def formula(spm_unit, period, parameters): - p = parameters(period).gov.states.ar.ade.oec.sra.eligibility - assets = spm_unit("spm_unit_assets", period.this_year) - return assets <= p.asset_limit diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py index c168e0895bc..4dc8cee34f1 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py @@ -18,7 +18,7 @@ def formula(spm_unit, period, parameters): return False has_eligible_child = add(spm_unit, period, ["is_ar_sra_child_eligible"]) > 0 income_ok = spm_unit("is_ar_sra_income_eligible", period) - asset_ok = spm_unit("is_ar_sra_asset_eligible", period) + asset_ok = spm_unit("is_ccdf_asset_eligible", period.this_year) li_active = spm_unit("is_ar_sra_li_activity_eligible", period) ess_active = spm_unit("is_ar_sra_ess_eligible", period) activity_ok = li_active | ess_active From e65c53010db6fd3607119dee955540982f76cad9 Mon Sep 17 00:00:00 2001 From: Ziming Date: Sun, 17 May 2026 20:05:59 -0400 Subject: [PATCH 04/17] Review-fix round 2: address checklist findings from pr-review-checklist.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Delete orphan parameter income/excluded_sources.yaml (never referenced). - Rename was_tea_recipient/months_since_tea_exit → ar-prefixed for namespace. - LI activity: use age>=18 (not is_tax_unit_head_or_spouse); OR in meets_ccdf_activity_test fallback for unmodeled activities. - ESS activity: mask weekly_hours_worked to adults so working teens don't satisfy the threshold. - ar_sra: read pre_subsidy_childcare_expenses at period (auto-divides annual→monthly); drop redundant manual /MONTHS_IN_YEAR. - Compare monthly income vs monthly SMI in is_ar_sra_income_eligible and ar_sra_income_tier (single conversion instead of annualization). - Sweep parameter descriptions to use allowed verbs (limits / provides / sets / excludes / deducts / uses). - Remove absolute_error_margin from boolean-output test files. All 80 AR SRA tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../activity_hours_ess_year_1.yaml | 2 +- .../activity_hours_ess_year_2.yaml | 2 +- .../sra/eligibility/activity_hours_li.yaml | 2 +- .../sra/eligibility/ess_window_months.yaml | 2 +- .../eligibility/ess_year_1_window_months.yaml | 2 +- .../gov/states/ar/ade/oec/sra/in_effect.yaml | 2 +- .../ade/oec/sra/income/excluded_sources.yaml | 32 ------------------- .../states/ar/ade/oec/sra/income/sources.yaml | 2 +- .../oec/sra/rates/age_category_months.yaml | 2 +- .../ar/ade/oec/sra/rates/base_rate.yaml | 2 +- .../sra/rates/full_time_hours_threshold.yaml | 2 +- .../oec/sra/rates/no_copay_smi_threshold.yaml | 2 +- .../rates/partial_subsidy_smi_threshold.yaml | 2 +- .../oec/sra/rates/state_share_by_tier.yaml | 2 +- .../sra/eligibility/ar_sra_age_eligible.yaml | 4 --- .../eligibility/ar_sra_child_eligible.yaml | 4 --- .../oec/sra/eligibility/ar_sra_eligible.yaml | 11 ++----- .../sra/eligibility/ar_sra_ess_eligible.yaml | 26 ++++++--------- .../oec/sra/eligibility/ar_sra_in_effect.yaml | 3 -- .../eligibility/ar_sra_income_eligible.yaml | 4 --- .../ar_sra_li_activity_eligible.yaml | 5 --- .../states/ar/ade/oec/sra/integration.yaml | 8 ++--- ...ea_exit.py => ar_months_since_tea_exit.py} | 6 ++-- .../gov/states/ar/ade/oec/sra/ar_sra.py | 3 +- .../ar/ade/oec/sra/ar_sra_income_tier.py | 10 +++--- ...a_recipient.py => ar_was_tea_recipient.py} | 6 ++-- .../sra/eligibility/is_ar_sra_ess_eligible.py | 18 +++++------ .../eligibility/is_ar_sra_income_eligible.py | 13 ++++---- .../is_ar_sra_li_activity_eligible.py | 15 +++++---- 29 files changed, 62 insertions(+), 132 deletions(-) delete mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/excluded_sources.yaml rename policyengine_us/variables/gov/states/ar/ade/oec/sra/{months_since_tea_exit.py => ar_months_since_tea_exit.py} (55%) rename policyengine_us/variables/gov/states/ar/ade/oec/sra/{was_tea_recipient.py => ar_was_tea_recipient.py} (58%) diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_1.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_1.yaml index 8c8ab1cca07..9c55be4a220 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_1.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_1.yaml @@ -1,4 +1,4 @@ -description: Arkansas requires at least one adult in an ESS Year 1 School Readiness Assistance household to engage in at least this many hours per week of work, education, or training. +description: Arkansas sets this minimum weekly activity hours threshold for at least one adult in an ESS Year 1 household under the School Readiness Assistance program. values: 2025-10-01: 20 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_2.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_2.yaml index ba700c3048c..8f82ff79c1a 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_2.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_2.yaml @@ -1,4 +1,4 @@ -description: Arkansas requires at least one adult in an ESS Year 2 School Readiness Assistance household to engage in at least this many hours per week of work, education, or training. +description: Arkansas sets this minimum weekly activity hours threshold for at least one adult in an ESS Year 2 household under the School Readiness Assistance program. values: 2025-10-01: 25 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_li.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_li.yaml index 112f427df19..fe996f4ec76 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_li.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_li.yaml @@ -1,4 +1,4 @@ -description: Arkansas requires each adult in a Low-Income School Readiness Assistance household to engage in at least this many hours per week of work, education, or training. +description: Arkansas sets this minimum weekly activity hours threshold for each adult in a Low-Income household under the School Readiness Assistance program. values: 2025-10-01: 30 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml index 3c687043b14..a5428bd2019 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml @@ -1,4 +1,4 @@ -description: Arkansas restricts the ESS School Readiness Assistance track to families within this many months of exiting Transitional Employment Assistance. +description: Arkansas limits the ESS post-Transitional Employment Assistance window to this many months under the School Readiness Assistance program. values: 2025-10-01: 24 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_year_1_window_months.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_year_1_window_months.yaml index 0e15b712cbd..47b276f9de8 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_year_1_window_months.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_year_1_window_months.yaml @@ -1,4 +1,4 @@ -description: Arkansas defines the Employment-Sponsored Subsidy Year 1 window as this many months after Transitional Employment Assistance exit under the School Readiness Assistance program. +description: Arkansas sets this many months as the Employment-Sponsored Subsidy Year 1 window under the School Readiness Assistance program. values: 2025-10-01: 12 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml index 1dade55acd8..5c4c256f370 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml @@ -1,4 +1,4 @@ -description: Arkansas operates the School Readiness Assistance child care subsidy program if this is true. +description: Arkansas uses this indicator to determine whether the School Readiness Assistance program applies. # The SRA program legally launched 2025-10-01, but the Oct 2025 rate schedule # (higher rates plus a one-month Quality Enhancement Payment) was replaced on # 2025-11-01 by the rate sheet currently encoded. We gate the program to the diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/excluded_sources.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/excluded_sources.yaml deleted file mode 100644 index 5c83865c175..00000000000 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/excluded_sources.yaml +++ /dev/null @@ -1,32 +0,0 @@ -description: Arkansas excludes these income sources from countable income under the School Readiness Assistance program. -values: - 2025-10-01: - # - tanf # Transitional Employment Assistance (TEA) payments - - child_support_received - - eitc # Tax refunds including EITC - # Children's SSI and Social Security are excluded; handled by the - # countable-income formula via age filter rather than by listing them. - # The following are also excluded per FSU Manual Section 4.3.3 - # but have no matching variables or do not need explicit listing: - # - Work Pays payments - # - Irregular non-recurring lump sums (Christmas bonuses, insurance, - # capital gains) - # - Earned/unearned income of children under 18 - # - Loans, grants, scholarships, work-study earnings - # - Graduate / doctoral education earnings - # - Montgomery GI Bill / VEAP educational income - # - Reimbursement of work-related expenses - # - Foster Care board payments - # - Adoption subsidy - # - HUD rental assistance value - # - Utility assistance value - # - Disaster assistance - # - Tribal income - -metadata: - unit: list - period: year - label: Arkansas SRA excluded income sources - reference: - - title: FSU Procedural Manual (June 2023), Section 4.3.3 Excluded Income - href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=20 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/sources.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/sources.yaml index 3caf431eefd..6d347a739d1 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/sources.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/sources.yaml @@ -1,4 +1,4 @@ -description: Arkansas counts these income sources for adults under the School Readiness Assistance program. +description: Arkansas uses these income sources for adults under the School Readiness Assistance program. values: 2025-10-01: - employment_income diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml index e4478691570..1689759f40b 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml @@ -1,4 +1,4 @@ -description: Arkansas classifies children into these age categories by age in months for School Readiness Assistance rate lookup. Returned values match the integer index of the ar_sra_age_category enum (0=INFANT, 1=TODDLER, 2=PRESCHOOL, 3=SCHOOL_AGED). +description: Arkansas sets these age thresholds in months for age categories under the School Readiness Assistance program. # Age-category month boundaries are undocumented in Arkansas sources; # these peer-state defaults (Infant <=17 mo, Toddler 18-35 mo, Preschool # 36-71 mo, School-Aged 72+ mo) are flagged for future verification. diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml index d522bdd701f..da4153fed16 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml @@ -1,4 +1,4 @@ -description: Arkansas provides these daily base reimbursement rates by zone, age category, care type, and time category under the School Readiness Assistance program. +description: Arkansas provides these daily base reimbursement rates under the School Readiness Assistance program. metadata: period: day unit: currency-USD diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml index 0876dbc530b..04aaa094465 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml @@ -1,4 +1,4 @@ -description: Arkansas classifies child care attendance as full-time under the School Readiness Assistance program when weekly hours meet or exceed this threshold. +description: Arkansas sets this weekly hours threshold for full-time child care under the School Readiness Assistance program. # The full-time vs part-time hour cut-point is undocumented in Arkansas # sources; this 30-hour default mirrors peer-state conventions (NH uses # 31+ hours for FT; RI uses 30/45) and is flagged for future verification. diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml index 3404231688b..91a5722f873 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml @@ -1,4 +1,4 @@ -description: Arkansas waives the family copay under the School Readiness Assistance program for non-school-aged children whose family income is at or below this share of the state median income. +description: Arkansas sets this share of state median income as the no-copay threshold for non-school-aged children under the School Readiness Assistance program. values: 2025-11-01: 0.40 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml index 0514291e5e2..237566cbfec 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml @@ -1,4 +1,4 @@ -description: Arkansas classifies families in the partial-subsidy income tier under the School Readiness Assistance program when their income is above the no-copay threshold and at or below this share of the state median income; above this share families fall in the highest-copay tier. +description: Arkansas sets this share of state median income as the upper bound of the partial-subsidy income tier under the School Readiness Assistance program. values: 2025-11-01: 0.60 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/state_share_by_tier.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/state_share_by_tier.yaml index dac09797fae..939e7a2e6c4 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/state_share_by_tier.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/state_share_by_tier.yaml @@ -1,4 +1,4 @@ -description: Arkansas pays this share of the daily base rate by age category, time category, and family income tier (% SMI) under the School Readiness Assistance program. +description: Arkansas provides this share of the daily base rate under the School Readiness Assistance program. metadata: period: day unit: /1 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml index b719675538f..b60a9ea323f 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml @@ -1,6 +1,5 @@ - name: Case 1, child age 5 is under 13 and age-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -17,7 +16,6 @@ - name: Case 2, child age 12 at boundary is age-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -34,7 +32,6 @@ - name: Case 3, child age 13 is not age-eligible (strict less than). period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -51,7 +48,6 @@ - name: Case 4, infant age 0 is age-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_child_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_child_eligible.yaml index 1c8fdda467c..6e04ff94010 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_child_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_child_eligible.yaml @@ -2,7 +2,6 @@ - name: Case 1, citizen child age 5 who is a dependent is eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -23,7 +22,6 @@ - name: Case 2, child age 13 is not age-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -44,7 +42,6 @@ - name: Case 3, undocumented child is not immigration-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -65,7 +62,6 @@ - name: Case 4, refugee child age 4 is eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml index 7b8161e41fd..dfb3d9d3c79 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml @@ -3,7 +3,6 @@ - name: Case 1, all eligibility components met under the LI track. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -32,7 +31,6 @@ - name: Case 2, household income above 85 percent SMI fails eligibility. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -62,7 +60,6 @@ - name: Case 3, no eligible child fails eligibility. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -83,7 +80,6 @@ - name: Case 4, parent activity below LI threshold and no ESS track fails eligibility. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -102,7 +98,7 @@ spm_units: spm_unit: members: [person1, person2] - was_tea_recipient: false + ar_was_tea_recipient: false households: household: members: [person1, person2] @@ -113,7 +109,6 @@ - name: Case 5, ESS track 20 hours per week makes household eligible even below LI threshold. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -132,8 +127,8 @@ spm_units: spm_unit: members: [person1, person2] - was_tea_recipient: true - months_since_tea_exit: 6 + ar_was_tea_recipient: true + ar_months_since_tea_exit: 6 ar_tea: 0 households: household: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml index 7b9f419a475..142624aee4d 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml @@ -4,7 +4,6 @@ - name: Case 1, post-TEA family 6 months out with 20 hours per week is ESS-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -16,8 +15,8 @@ spm_units: spm_unit: members: [person1, person2] - was_tea_recipient: true - months_since_tea_exit: 6 + ar_was_tea_recipient: true + ar_months_since_tea_exit: 6 ar_tea: 0 households: household: @@ -28,21 +27,19 @@ - name: Case 2, family currently receiving TEA is not ESS-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: age: 28 weekly_hours_worked: 25 - # Force ar_tea > 0 by setting a recipient flag below person2: age: 2 is_tax_unit_dependent: true spm_units: spm_unit: members: [person1, person2] - was_tea_recipient: true - months_since_tea_exit: 6 + ar_was_tea_recipient: true + ar_months_since_tea_exit: 6 ar_tea: 200 households: household: @@ -53,7 +50,6 @@ - name: Case 3, post-TEA family 30 months out is past the 24-month window and not ESS-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -65,8 +61,8 @@ spm_units: spm_unit: members: [person1, person2] - was_tea_recipient: true - months_since_tea_exit: 30 + ar_was_tea_recipient: true + ar_months_since_tea_exit: 30 households: household: members: [person1, person2] @@ -76,7 +72,6 @@ - name: Case 4, family that never received TEA is not ESS-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -88,8 +83,8 @@ spm_units: spm_unit: members: [person1, person2] - was_tea_recipient: false - months_since_tea_exit: 0 + ar_was_tea_recipient: false + ar_months_since_tea_exit: 0 households: household: members: [person1, person2] @@ -99,7 +94,6 @@ - name: Case 5, ESS Year 2 family with 25 hours per week is ESS-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -111,8 +105,8 @@ spm_units: spm_unit: members: [person1, person2] - was_tea_recipient: true - months_since_tea_exit: 18 + ar_was_tea_recipient: true + ar_months_since_tea_exit: 18 ar_tea: 0 households: household: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml index 7096e74cf53..b5eb9f2550c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml @@ -5,7 +5,6 @@ - name: Case 1, period 2025-01 is before SRA effective date so household is not eligible. period: 2025-01 - absolute_error_margin: 0.1 input: people: person1: @@ -34,7 +33,6 @@ - name: Case 2, period 2026-01 is the SRA effective date and household is eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -63,7 +61,6 @@ - name: Case 3, period 2026-01 is well within the SRA era and household is eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_income_eligible.yaml index f13396bfaf7..579e6e54d45 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_income_eligible.yaml @@ -6,7 +6,6 @@ - name: Case 1, family income at 84.9 percent SMI is income-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -33,7 +32,6 @@ - name: Case 2, family income just at 85 percent SMI is income-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -61,7 +59,6 @@ - name: Case 3, family income at 85.1 percent SMI is not income-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -88,7 +85,6 @@ - name: Case 4, family with zero income is income-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml index a915089fe93..c53ffecf0c4 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml @@ -3,7 +3,6 @@ - name: Case 1, single parent works 30 hours per week exactly is activity-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -24,7 +23,6 @@ - name: Case 2, single parent works 29 hours per week is not activity-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -45,7 +43,6 @@ - name: Case 3, single parent works 31 hours per week is activity-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -66,7 +63,6 @@ - name: Case 4, two parents both at or above 30 hours per week are activity-eligible. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -90,7 +86,6 @@ - name: Case 5, two-parent household with one parent below threshold fails activity test. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml index 15eb8354583..783fb658a56 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml @@ -153,8 +153,8 @@ spm_units: spm_unit: members: [person1, person2] - was_tea_recipient: true - months_since_tea_exit: 6 + ar_was_tea_recipient: true + ar_months_since_tea_exit: 6 ar_tea: 0 spm_unit_pre_subsidy_childcare_expenses: 20_000 households: @@ -192,8 +192,8 @@ spm_units: spm_unit: members: [person1, person2] - was_tea_recipient: true - months_since_tea_exit: 18 + ar_was_tea_recipient: true + ar_months_since_tea_exit: 18 ar_tea: 0 spm_unit_pre_subsidy_childcare_expenses: 20_000 households: diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/months_since_tea_exit.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_months_since_tea_exit.py similarity index 55% rename from policyengine_us/variables/gov/states/ar/ade/oec/sra/months_since_tea_exit.py rename to policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_months_since_tea_exit.py index c39f2d02e3c..f5d4a72fd4e 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/months_since_tea_exit.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_months_since_tea_exit.py @@ -1,13 +1,11 @@ from policyengine_us.model_api import * -class months_since_tea_exit(Variable): +class ar_months_since_tea_exit(Variable): value_type = int entity = SPMUnit label = "Months since Arkansas TEA cash aid ended" definition_period = MONTH defined_for = StateCode.AR default_value = 0 - reference = ( - "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16", - ) + reference = "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16" diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py index 01a2ca5c698..ec7a459a45e 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py @@ -21,8 +21,7 @@ def formula(spm_unit, period, parameters): attending_days = person("childcare_attending_days_per_month", period.this_year) monthly_max_state_payment = daily_state_payment * attending_days monthly_copay = daily_copay * attending_days - annual_expense = person("pre_subsidy_childcare_expenses", period.this_year) - monthly_expense = annual_expense / MONTHS_IN_YEAR + monthly_expense = person("pre_subsidy_childcare_expenses", period) subsidy = min_( max_(monthly_expense - monthly_copay, 0), monthly_max_state_payment, diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py index e8ab3292ec0..c25c6c13efc 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py @@ -15,15 +15,13 @@ class ar_sra_income_tier(Variable): definition_period = MONTH defined_for = StateCode.AR label = "Arkansas SRA family income tier (% SMI)" - reference = ( - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", - ) + reference = "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf" def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra - annual_income = spm_unit("ar_sra_countable_income", period) * MONTHS_IN_YEAR - smi = spm_unit("hhs_smi", period.this_year) - ratio = where(smi > 0, annual_income / smi, np.inf) + monthly_income = spm_unit("ar_sra_countable_income", period) + monthly_smi = spm_unit("hhs_smi", period.this_year) / MONTHS_IN_YEAR + ratio = where(monthly_smi > 0, monthly_income / monthly_smi, np.inf) return select( [ ratio <= p.rates.no_copay_smi_threshold, diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/was_tea_recipient.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_was_tea_recipient.py similarity index 58% rename from policyengine_us/variables/gov/states/ar/ade/oec/sra/was_tea_recipient.py rename to policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_was_tea_recipient.py index a52588900f1..aea459f7c9c 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/was_tea_recipient.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_was_tea_recipient.py @@ -1,13 +1,11 @@ from policyengine_us.model_api import * -class was_tea_recipient(Variable): +class ar_was_tea_recipient(Variable): value_type = bool entity = SPMUnit label = "Was an Arkansas Transitional Employment Assistance recipient" definition_period = YEAR defined_for = StateCode.AR default_value = False - reference = ( - "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16", - ) + reference = "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16" diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py index 80b8fe170b2..c677eaea02b 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py @@ -4,25 +4,25 @@ class is_ar_sra_ess_eligible(Variable): value_type = bool entity = SPMUnit - label = "Eligible for Arkansas SRA Extended Support Services (ESS) track" + label = "Eligible for Arkansas SRA Employment-Sponsored Subsidy (ESS) track" definition_period = MONTH defined_for = StateCode.AR - reference = ( - "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16", - ) + reference = "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16" def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.eligibility - was_tea = spm_unit("was_tea_recipient", period.this_year) - months_since = spm_unit("months_since_tea_exit", period) + was_tea = spm_unit("ar_was_tea_recipient", period.this_year) + months_since = spm_unit("ar_months_since_tea_exit", period) ar_tea = spm_unit("ar_tea", period) within_window = (months_since > 0) & (months_since <= p.ess_window_months) in_track = was_tea & (ar_tea == 0) & within_window in_year_1 = months_since <= p.ess_year_1_window_months person = spm_unit.members + is_adult = person("age", period.this_year) >= 18 hours = person("weekly_hours_worked", period.this_year) - max_hours = spm_unit.max(hours) - year_1_active = max_hours >= p.activity_hours_ess_year_1 - year_2_active = max_hours >= p.activity_hours_ess_year_2 + adult_hours = where(is_adult, hours, 0) + max_adult_hours = spm_unit.max(adult_hours) + year_1_active = max_adult_hours >= p.activity_hours_ess_year_1 + year_2_active = max_adult_hours >= p.activity_hours_ess_year_2 activity_ok = where(in_year_1, year_1_active, year_2_active) return in_track & activity_ok diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py index d04712ea794..e85a0c6a22d 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py @@ -7,13 +7,12 @@ class is_ar_sra_income_eligible(Variable): label = "Income-eligible for Arkansas SRA" definition_period = MONTH defined_for = StateCode.AR - reference = ( - "https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=22", - ) + reference = "https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=22" def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.eligibility - # `ar_sra_countable_income` is monthly; `hhs_smi` is annual. - annual_income = spm_unit("ar_sra_countable_income", period) * MONTHS_IN_YEAR - smi = spm_unit("hhs_smi", period.this_year) - return annual_income <= smi * p.income_smi_rate + monthly_income = spm_unit("ar_sra_countable_income", period) + monthly_smi_limit = ( + spm_unit("hhs_smi", period.this_year) * p.income_smi_rate / MONTHS_IN_YEAR + ) + return monthly_income <= monthly_smi_limit diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py index 9f05194134d..fb767119a86 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py @@ -7,16 +7,17 @@ class is_ar_sra_li_activity_eligible(Variable): label = "Activity-eligible for Arkansas SRA Low-Income track" definition_period = MONTH defined_for = StateCode.AR - reference = ( - "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16", - ) + reference = "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16" def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.eligibility person = spm_unit.members - is_head_or_spouse = person("is_tax_unit_head_or_spouse", period.this_year) + is_adult = person("age", period.this_year) >= 18 hours = person("weekly_hours_worked", period.this_year) is_student = person("is_full_time_student", period.this_year) - meets_threshold = (hours >= p.activity_hours_li) | is_student - # All adults (heads/spouses) must meet the threshold. - return spm_unit.sum(is_head_or_spouse & ~meets_threshold) == 0 + meets_activity = (hours >= p.activity_hours_li) | is_student + # All adults must meet the activity test. + has_adult = spm_unit.sum(is_adult) > 0 + all_adults_qualify = spm_unit.sum(is_adult & ~meets_activity) == 0 + ccdf_fallback = spm_unit("meets_ccdf_activity_test", period.this_year) + return (has_adult & all_adults_qualify) | ccdf_fallback From f78dde80297a7d1fb601a285723cbc50635be4bf Mon Sep 17 00:00:00 2001 From: Ziming Date: Sun, 17 May 2026 21:49:02 -0400 Subject: [PATCH 05/17] Review-fix round 3: reference honesty + test/code polish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tier 1 — Honest references (drop or reframe phantom citations): - age_category_months.yaml: replace FSU §4.1 (doesn't define month boundaries) with the rate sheet (establishes the age-category labels) and strengthen the inline note that month boundaries are peer-state convention, not AR source. - full_time_hours_threshold.yaml: keep rate-sheet citations but retitle to make clear they establish FT/PT as billing categories — the 30-hour cutoff itself is peer-state convention. - child_age_limit.yaml, is_ar_sra_age_eligible.py, is_ar_sra_child_eligible.py: drop FSU co-citation (FSU §4.1 doesn't state the age-13 rule; only Title 016 §3.1.4 does). The two .py files also disagreed on which FSU page (13 vs 14). - base_rate.yaml: add top-of-file note that PT NIGHT_WEEKEND cells mirror PT REGULAR as a fallback — the source rate sheets have no PT N/W row. Tier 3 — Polish: - ar_sra.py: add clarifying comments on the YEAR→MONTH conversions for pre_subsidy_childcare_expenses (auto-divides at MONTH period) and childcare_attending_days_per_month (read at this_year to preserve count semantics). - Standardize absolute_error_margin to 0.1 across all currency rate tests (was 0.01, inconsistent with project convention of 0.1). - Expand variable-file reference tuples to cite all 4 rate-sheet PDFs (Statewide FT/PT + Benton-Washington FT/PT) — variables previously cited a subset of what the YAML cited. 80/80 AR SRA tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../oec/sra/eligibility/child_age_limit.yaml | 2 -- .../oec/sra/rates/age_category_months.yaml | 12 +++++---- .../ar/ade/oec/sra/rates/base_rate.yaml | 4 ++- .../sra/rates/full_time_hours_threshold.yaml | 11 ++++---- .../oec/sra/rates/ar_sra_daily_base_rate.yaml | 26 +++++++++---------- .../ade/oec/sra/rates/ar_sra_daily_copay.yaml | 6 ++--- .../sra/rates/ar_sra_daily_state_payment.yaml | 6 ++--- .../gov/states/ar/ade/oec/sra/ar_sra.py | 4 +++ .../sra/eligibility/is_ar_sra_age_eligible.py | 5 +--- .../eligibility/is_ar_sra_child_eligible.py | 5 +--- .../oec/sra/rates/ar_sra_daily_base_rate.py | 2 ++ .../ade/oec/sra/rates/ar_sra_daily_copay.py | 3 +++ .../sra/rates/ar_sra_daily_state_payment.py | 3 +++ .../ade/oec/sra/rates/ar_sra_state_share.py | 3 +++ 14 files changed, 52 insertions(+), 40 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit.yaml index 1ce2537e4f1..6952e208895 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit.yaml @@ -9,5 +9,3 @@ metadata: reference: - title: AR ADC 016.22.8 Section 3.1.4 Eligible Child / Date of Birth href: https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11 - - title: FSU Procedural Manual (June 2023), Section 4.1 - href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=13 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml index 1689759f40b..b191909d336 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml @@ -1,7 +1,9 @@ description: Arkansas sets these age thresholds in months for age categories under the School Readiness Assistance program. -# Age-category month boundaries are undocumented in Arkansas sources; -# these peer-state defaults (Infant <=17 mo, Toddler 18-35 mo, Preschool -# 36-71 mo, School-Aged 72+ mo) are flagged for future verification. +# The rate sheets group rates by Infant / Toddler / Preschool / School-Aged +# but do NOT specify month boundaries within those labels. The encoded +# month boundaries (Infant <=17 mo, Toddler 18-35 mo, Preschool 36-71 mo, +# School-Aged 72+ mo) are peer-state conventions, not Arkansas sources, +# and are flagged for future verification with OEC. brackets: - threshold: @@ -28,5 +30,5 @@ metadata: period: year label: Arkansas SRA age category month thresholds reference: - - title: FSU Procedural Manual (June 2023), Section 4.1 - href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=13 + - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Full Time (Nov 1, 2025) - age category labels + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml index da4153fed16..35e5ba94014 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml @@ -1,4 +1,7 @@ description: Arkansas provides these daily base reimbursement rates under the School Readiness Assistance program. +# Source rate sheets have no Part-Time Night/Weekend row. PT NIGHT_WEEKEND +# cells below mirror PT REGULAR as a fallback so the (zone × age × care_type +# × time) lookup is complete; this is a modeling choice, not a source value. metadata: period: day unit: currency-USD @@ -28,7 +31,6 @@ BENTON_WASHINGTON: NIGHT_WEEKEND: FULL_TIME: 2025-11-01: 41.80 - # Part-Time has no Night/Weekend row; uses regular Part-Time rate PART_TIME: 2025-11-01: 19.00 SN1: diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml index 04aaa094465..85008d39662 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml @@ -1,7 +1,8 @@ description: Arkansas sets this weekly hours threshold for full-time child care under the School Readiness Assistance program. -# The full-time vs part-time hour cut-point is undocumented in Arkansas -# sources; this 30-hour default mirrors peer-state conventions (NH uses -# 31+ hours for FT; RI uses 30/45) and is flagged for future verification. +# Arkansas rate sheets distinguish Full Time vs Part Time as billing +# categories but do NOT define the numeric hours cut-point. The encoded +# 30-hour threshold mirrors peer-state conventions (NH uses 31+ for FT; +# RI uses 30/45) and is flagged for future verification with OEC. values: 2025-10-01: 30 @@ -10,7 +11,7 @@ metadata: period: year label: Arkansas SRA full-time weekly hours threshold reference: - - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Full Time (Nov 1, 2025) + - title: SRA Sliding Fee Scale - Statewide Full Time (Nov 1, 2025) - establishes Full Time category href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf - - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Part Time (Nov 1, 2025) + - title: SRA Sliding Fee Scale - Statewide Part Time (Nov 1, 2025) - establishes Part Time category href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml index 838183778ff..41b9db28b39 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml @@ -14,7 +14,7 @@ - name: Case 1, Statewide infant full time base rate is 36.00. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -30,7 +30,7 @@ - name: Case 2, Statewide toddler full time base rate is 35.00. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -46,7 +46,7 @@ - name: Case 3, Statewide preschool full time base rate is 33.00. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -62,7 +62,7 @@ - name: Case 4, Statewide school-aged full time base rate is 28.00. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -78,7 +78,7 @@ - name: Case 5, Benton/Washington infant full time base rate is 38.00. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -94,7 +94,7 @@ - name: Case 6, Benton/Washington toddler full time base rate is 37.00. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -110,7 +110,7 @@ - name: Case 7, Statewide infant part time base rate is 18.00. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -126,7 +126,7 @@ - name: Case 8, Benton/Washington infant part time base rate is 19.00. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -142,7 +142,7 @@ - name: Case 9, Statewide infant Night/Weekend full time base rate is 39.60. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -159,7 +159,7 @@ - name: Case 10, Statewide infant SN1 full time base rate is 36.00. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -176,7 +176,7 @@ - name: Case 11, Statewide infant SN2 full time base rate is 50.40. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -193,7 +193,7 @@ - name: Case 12, Statewide infant SN3 full time base rate is 50.40. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -210,7 +210,7 @@ - name: Case 13, Statewide preschool Night/Weekend full time base rate is 36.30. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml index dcccc4062ce..7be9184e103 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml @@ -2,7 +2,7 @@ - name: Case 1, Toddler Statewide FT at LE_40 SMI has zero copay (share 1.00). period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -33,7 +33,7 @@ - name: Case 2, School-Aged Statewide FT at LE_40 SMI has positive copay (20 percent of base). period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -64,7 +64,7 @@ - name: Case 3, Preschool Statewide FT at GT_60 SMI has copay 40 percent of base. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml index 6d3cf791a4b..895c942c4fa 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml @@ -5,7 +5,7 @@ - name: Case 1, Toddler Statewide FT at LE_40 SMI pays full base rate (no-copay). period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -36,7 +36,7 @@ - name: Case 2, School-Aged Statewide FT at LE_40 SMI has positive copay (share 0.80). period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: @@ -67,7 +67,7 @@ - name: Case 3, Infant Benton/Washington FT at GT_60 SMI gets reduced share. period: 2026-01 - absolute_error_margin: 0.01 + absolute_error_margin: 0.1 input: people: person1: diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py index ec7a459a45e..b67220f270d 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py @@ -18,9 +18,13 @@ def formula(spm_unit, period, parameters): is_eligible_child = person("is_ar_sra_child_eligible", period) daily_state_payment = person("ar_sra_daily_state_payment", period) daily_copay = person("ar_sra_daily_copay", period) + # `childcare_attending_days_per_month` is YEAR-defined but stores + # a monthly count (e.g., 22 days/mo); read at this_year to skip the + # YEAR→MONTH auto-divide. attending_days = person("childcare_attending_days_per_month", period.this_year) monthly_max_state_payment = daily_state_payment * attending_days monthly_copay = daily_copay * attending_days + # YEAR-defined expense auto-divides to monthly at MONTH period. monthly_expense = person("pre_subsidy_childcare_expenses", period) subsidy = min_( max_(monthly_expense - monthly_copay, 0), diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py index 97bb547dd98..e3e8d47e549 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py @@ -7,10 +7,7 @@ class is_ar_sra_age_eligible(Variable): label = "Age-eligible for Arkansas SRA" definition_period = MONTH defined_for = StateCode.AR - reference = ( - "https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11", - "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=13", - ) + reference = "https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11" def formula(person, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.eligibility diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_child_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_child_eligible.py index 663ecf59569..5952c5cab22 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_child_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_child_eligible.py @@ -7,10 +7,7 @@ class is_ar_sra_child_eligible(Variable): label = "Eligible child for Arkansas SRA" definition_period = MONTH defined_for = StateCode.AR - reference = ( - "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=14", - "https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11", - ) + reference = "https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11" def formula(person, period, parameters): age_eligible = person("is_ar_sra_age_eligible", period) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py index 85a761b72d3..298fab8c9ec 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py @@ -10,7 +10,9 @@ class ar_sra_daily_base_rate(Variable): defined_for = "is_ar_sra_child_eligible" reference = ( "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", ) def formula(person, period, parameters): diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py index 3ee8f330b04..82bcc581914 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py @@ -10,6 +10,9 @@ class ar_sra_daily_copay(Variable): defined_for = "is_ar_sra_child_eligible" reference = ( "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", ) def formula(person, period, parameters): diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py index d64462f51ac..e9cc2eff4d7 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py @@ -10,6 +10,9 @@ class ar_sra_daily_state_payment(Variable): defined_for = "is_ar_sra_child_eligible" reference = ( "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", ) def formula(person, period, parameters): diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py index 4dc1bba98aa..7bb27b81e29 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py @@ -9,6 +9,9 @@ class ar_sra_state_share(Variable): defined_for = "is_ar_sra_child_eligible" reference = ( "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", ) def formula(person, period, parameters): From 672d4198280738ef824389a803db161da82b3c19 Mon Sep 17 00:00:00 2001 From: Ziming Date: Sun, 17 May 2026 21:52:37 -0400 Subject: [PATCH 06/17] Trim redundant reference lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Revert 4-PDF reference expansion in 4 rate variable files (ar_sra_daily_base_rate / daily_copay / daily_state_payment / state_share). Each variable does a parameter lookup; the YAML files already cite all 4 rate sheets as the authoritative source. Restore a single canonical URL per variable. - Drop tuple wrapper from ar_sra_care_type.py and ar_sra_age_category.py which had `reference = ( "single_url", )` — string is the convention for a single reference. - Trim no_copay_smi_threshold.yaml and partial_subsidy_smi_threshold.yaml from 2 refs to 1 — the income-tier headers (40%, 60%) appear identically on the FT and PT rate sheets so a second citation is redundant. 80/80 AR SRA tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml | 2 -- .../ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml | 2 -- .../gov/states/ar/ade/oec/sra/ar_sra_age_category.py | 4 +--- .../gov/states/ar/ade/oec/sra/ar_sra_care_type.py | 4 +--- .../states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py | 7 +------ .../gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py | 7 +------ .../ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py | 7 +------ .../gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py | 7 +------ 8 files changed, 6 insertions(+), 34 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml index 91a5722f873..fa2770568c3 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml @@ -9,5 +9,3 @@ metadata: reference: - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Full Time (Nov 1, 2025) href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf - - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Part Time (Nov 1, 2025) - href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml index 237566cbfec..e6e47ea8903 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml @@ -9,5 +9,3 @@ metadata: reference: - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Full Time (Nov 1, 2025) href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf - - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Part Time (Nov 1, 2025) - href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py index 4d9331f0120..8d3e28d38ee 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py @@ -16,9 +16,7 @@ class ar_sra_age_category(Variable): definition_period = MONTH defined_for = StateCode.AR label = "Arkansas SRA child age category" - reference = ( - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", - ) + reference = "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf" def formula(person, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.rates.age_category_months diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_care_type.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_care_type.py index b415a9fb944..f69801fcac5 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_care_type.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_care_type.py @@ -17,6 +17,4 @@ class ar_sra_care_type(Variable): definition_period = MONTH defined_for = StateCode.AR label = "Arkansas SRA care type" - reference = ( - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", - ) + reference = "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf" diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py index 298fab8c9ec..99d43dc1d25 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py @@ -8,12 +8,7 @@ class ar_sra_daily_base_rate(Variable): label = "Arkansas SRA daily base provider rate" definition_period = MONTH defined_for = "is_ar_sra_child_eligible" - reference = ( - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", - ) + reference = "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf" def formula(person, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.rates diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py index 82bcc581914..a10df87c8ea 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py @@ -8,12 +8,7 @@ class ar_sra_daily_copay(Variable): label = "Arkansas SRA daily family copay" definition_period = MONTH defined_for = "is_ar_sra_child_eligible" - reference = ( - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", - ) + reference = "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf" def formula(person, period, parameters): base = person("ar_sra_daily_base_rate", period) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py index e9cc2eff4d7..f8c23fd5062 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py @@ -8,12 +8,7 @@ class ar_sra_daily_state_payment(Variable): label = "Arkansas SRA daily state payment per child" definition_period = MONTH defined_for = "is_ar_sra_child_eligible" - reference = ( - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", - ) + reference = "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf" def formula(person, period, parameters): base = person("ar_sra_daily_base_rate", period) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py index 7bb27b81e29..de9f41c995b 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py @@ -7,12 +7,7 @@ class ar_sra_state_share(Variable): label = "Arkansas SRA state share of daily base rate" definition_period = MONTH defined_for = "is_ar_sra_child_eligible" - reference = ( - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", - "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", - ) + reference = "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf" def formula(person, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.rates From 26c95860aa058d5098e82c699cea182f978cd6e5 Mon Sep 17 00:00:00 2001 From: Ziming Date: Sun, 17 May 2026 22:00:29 -0400 Subject: [PATCH 07/17] Add test coverage for round-3 gaps identified by edge-case-generator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add 17 test cases targeting BLOCKER and HIGH-priority gaps from the round-3 review pass: integration.yaml (6 new cases): - Case 9: SN2 special-needs care exercises non-REGULAR care type path - Case 10: low monthly expense ($300) binds before the state payment cap - Case 11: mixed-eligibility household (one 4-year-old, one 13-year-old) confirms per-child masking in the spm_unit.sum - Case 12: zero attending days produces $0 benefit despite eligibility - Case 13: school-aged child at LE_40 SMI confirms 80% state share flows through to a non-zero benefit (always-copay rule) - Case 14: part-time infant care exercises the PT category path ar_sra_li_activity_eligible.yaml (2 new cases): - Case 6: meets_ccdf_activity_test fallback for unmodeled activities - Case 7: mixed work + full-time-student adult exemption ar_sra_ess_eligible.yaml (4 new cases): - Case 6: month 12 is last Year-1 month, 20 hr threshold satisfied - Case 7: month 24 is last in-window month, 25 hr threshold satisfied - Case 8: month 25 is past the window, household not eligible - Case 9: working teen does not satisfy threshold when adult masked hours fall below — exercises the adult-only hours masking ar_sra_income_tier.yaml (4 new cases): - Cases 4-5: 40% SMI boundary (LE_40 just under, GT_40_LE_60 just over) - Cases 6-7: 60% SMI boundary (GT_40_LE_60 just under, GT_60 just over) ar_sra_eligible.yaml (1 new case): - Case 6: high assets ($2M) above CCDF asset limit fails eligibility Total: 97/97 AR SRA tests pass (was 80/80). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../oec/sra/eligibility/ar_sra_eligible.yaml | 30 +++ .../sra/eligibility/ar_sra_ess_eligible.yaml | 97 ++++++++ .../ar_sra_li_activity_eligible.yaml | 45 ++++ .../states/ar/ade/oec/sra/integration.yaml | 217 ++++++++++++++++++ .../ade/oec/sra/rates/ar_sra_income_tier.yaml | 108 +++++++++ 5 files changed, 497 insertions(+) diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml index dfb3d9d3c79..b1fd2ef2ea4 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml @@ -137,3 +137,33 @@ county_str: PULASKI_COUNTY_AR output: is_ar_sra_eligible: true + +- name: Case 6, household with assets above the CCDF asset limit fails eligibility. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked: 35 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + # Above the $1M CCDF asset limit + spm_unit_assets: 2_000_000 + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml index 142624aee4d..ec0f5ae4a11 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml @@ -114,3 +114,100 @@ state_code: AR output: is_ar_sra_ess_eligible: true + +- name: Case 6, month 12 is the last Year-1 month and 20 hours satisfies the Year-1 threshold. + period: 2026-01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 20 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 12 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: true + +- name: Case 7, month 24 is the last in-window month and 25 hours satisfies the Year-2 threshold. + period: 2026-01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 25 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 24 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: true + +- name: Case 8, month 25 is past the 24-month window so household is not ESS-eligible. + period: 2026-01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 25 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 25 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: false + +- name: Case 9, a working teen does not satisfy the activity threshold when no adult does. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked: 10 + person2: + age: 16 + is_tax_unit_dependent: true + weekly_hours_worked: 30 + person3: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 6 + ar_tea: 0 + households: + household: + members: [person1, person2, person3] + state_code: AR + output: + # Teen's 30 hours is masked out; adult max = 10 hr, below Year-1 threshold (20) + is_ar_sra_ess_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml index c53ffecf0c4..eaa23fb83ee 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml @@ -106,3 +106,48 @@ state_code: AR output: is_ar_sra_li_activity_eligible: false + +- name: Case 6, adult with zero hours but meets_ccdf_activity_test fallback is eligible. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked: 0 + person2: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + meets_ccdf_activity_test: true + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_li_activity_eligible: true + +- name: Case 7, two-parent household with one working and one full-time student is eligible. + period: 2026-01 + input: + people: + person1: + age: 32 + weekly_hours_worked: 35 + person2: + age: 28 + weekly_hours_worked: 0 + is_full_time_student: true + person3: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2, person3] + households: + household: + members: [person1, person2, person3] + state_code: AR + output: + is_ar_sra_li_activity_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml index 783fb658a56..cdba95a4cf4 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml @@ -302,3 +302,220 @@ state_code: CA output: ar_sra: 0 + +- name: Case 9, LI single parent with toddler in SN2 special-needs care, Statewide FT. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + # LE_40 tier + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + ar_sra_care_type: SN2 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Statewide / Toddler / SN2 / FT base = $49, share LE_40 = 1.00 + # daily state payment = $49.00, monthly = $49 * 22 = $1078 + ar_sra: 1078 + +- name: Case 10, low pre-subsidy expense binds before state payment cap. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + # Annual $3,600 = $300/month, well below the $770 monthly cap + spm_unit_pre_subsidy_childcare_expenses: 3_600 + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Toddler Statewide FT LE_40: cap = $770/mo, copay = $0 + # subsidy = min(max(300 - 0, 0), 770) = $300 (expense binds) + ar_sra: 300 + +- name: Case 11, mixed-eligibility household with one eligible child and one over-age child. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 32 + weekly_hours_worked: 35 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + person3: + age: 13 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Only the 4-year-old is age-eligible; 13-year-old contributes $0 + # Preschool Statewide FT LE_40: base $33, share 1.00 + # monthly state payment = $33 * 22 = $726 + ar_sra: 726 + +- name: Case 12, eligible child with zero attending days produces zero benefit. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 0 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # attending_days = 0 -> monthly_max_state_payment = 0 + # subsidy = min(max(expense - 0, 0), 0) = 0 + ar_sra: 0 + +- name: Case 13, school-aged child at LE_40 SMI confirms 80 percent state share through to benefit. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + # LE_40 tier + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # School-Aged Statewide FT LE_40: base = $28, share = 0.80 (always copay) + # daily state payment = $28 * 0.80 = $22.40 + # monthly state payment = $22.40 * 22 = $492.80 + ar_sra: 492.80 + +- name: Case 14, part-time infant care, LI parent, Statewide. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + # PT (below 30 hr full-time threshold) + childcare_hours_per_week: 20 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Statewide Infant PT REGULAR base = $18, share LE_40 = 1.00 + # daily state payment = $18.00, monthly = $18 * 22 = $396 + ar_sra: 396 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml index 73b0f7c7542..0bc2aefedcb 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml @@ -86,3 +86,111 @@ state_code: AR output: ar_sra_income_tier: GT_60 + +- name: Case 4, family just under 40 percent SMI is in the LE_40 tier. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + # 64,737.33 * 0.3985 = $25,798 (just under 40 percent) + employment_income: 25_800 + immigration_status: CITIZEN + person2: + age: 4 + 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: AR + output: + ar_sra_income_tier: LE_40 + +- name: Case 5, family just above 40 percent SMI is in the GT_40_LE_60 tier. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + # 64,737.33 * 0.4016 = $26,000 (just above 40 percent) + employment_income: 26_000 + immigration_status: CITIZEN + person2: + age: 4 + 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: AR + output: + ar_sra_income_tier: GT_40_LE_60 + +- name: Case 6, family just under 60 percent SMI is in the GT_40_LE_60 tier. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + # 64,737.33 * 0.5978 = $38,700 (just under 60 percent) + employment_income: 38_700 + immigration_status: CITIZEN + person2: + age: 4 + 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: AR + output: + ar_sra_income_tier: GT_40_LE_60 + +- name: Case 7, family just above 60 percent SMI is in the GT_60 tier. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + # 64,737.33 * 0.6025 = $39,000 (just above 60 percent) + employment_income: 39_000 + immigration_status: CITIZEN + person2: + age: 4 + 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: AR + output: + ar_sra_income_tier: GT_60 From a662b8056c6cb7a3e0a6e537e754610473bd915f Mon Sep 17 00:00:00 2001 From: Ziming Date: Sun, 17 May 2026 23:16:14 -0400 Subject: [PATCH 08/17] Review-fix round 4: address /review-program findings (9 critical + 16 should) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Critical: - Add 4% SPM-unit copay cap (CCDF State Plan §3.1.1; AR self-cert under federal 7%). New max_copay_share_of_gross_income parameter; ar_sra.py adds cap_savings to subsidy when rate-sheet copays exceed the ceiling. Updated integration Cases 1/2/5/13 with cap-adjusted values; added multi-child cap-binding Case 18. - Parameterize adult age threshold (18) via new eligibility/adult_age_threshold.yaml; removed hardcoded 18 from ar_sra_countable_income, is_ar_sra_ess_eligible, is_ar_sra_li_activity_eligible. - Register ar_child_care_subsidies in household_state_benefits.yaml. - Add ESS boundary + below-threshold tests (month 13 with 20/25 hr, 19/24 hr below-threshold). - Cover all 24 state_share keys (added Cases 5-24 covering INFANT and PART_TIME branches). - Add is_ar_sra_eligible: false to integration Case 8 (non-AR). - Add NIGHT_WEEKEND / SN1 / SN3 integration cases (REQ-021). Should-Address: - FT threshold corrected to 35 hr/wk (≈ 5 × 7 hr/day per FSU §5.4.6). - ESS Year-2 activity adds is_full_time_student OR-clause; Year-1 TEA-income-ineligible alt path documented as unmodeled. - Strip trailing zeros across rates YAMLs; remove empty edge_cases dir; add #page=1 anchor on OEC announcement; remove redundant ACF reference. - Rewrite is_ar_sra_eligible scalar return as AND-chain; trim verbose comments in ar_sra_age_category and ar_sra_zone. - Test gaps: zero-adult LI case, age-category month boundaries (17/18, 35/36, 71/72), PT NIGHT_WEEKEND fallback, BW SN2 + NIGHT_WEEKEND, new ar_sra_care_type test file. 140/140 AR SRA tests pass; household_state_benefits tests unaffected. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../household/household_state_benefits.yaml | 2 + .../sra/eligibility/adult_age_threshold.yaml | 11 + .../oec/sra/eligibility/income_smi_rate.yaml | 2 - .../gov/states/ar/ade/oec/sra/in_effect.yaml | 2 +- .../ar/ade/oec/sra/rates/base_rate.yaml | 160 ++--- .../sra/rates/full_time_hours_threshold.yaml | 14 +- .../max_copay_share_of_gross_income.yaml | 14 + .../oec/sra/rates/no_copay_smi_threshold.yaml | 2 +- .../rates/partial_subsidy_smi_threshold.yaml | 2 +- .../oec/sra/rates/state_share_by_tier.yaml | 48 +- .../sra/eligibility/ar_sra_ess_eligible.yaml | 92 +++ .../ar_sra_li_activity_eligible.yaml | 19 + .../states/ar/ade/oec/sra/integration.yaml | 201 ++++++- .../oec/sra/rates/ar_sra_age_category.yaml | 78 +++ .../ade/oec/sra/rates/ar_sra_care_type.yaml | 71 +++ .../oec/sra/rates/ar_sra_daily_base_rate.yaml | 52 ++ .../ade/oec/sra/rates/ar_sra_state_share.yaml | 563 ++++++++++++++++++ .../oec/sra/rates/ar_sra_time_category.yaml | 17 +- .../gov/states/ar/ade/oec/sra/ar_sra.py | 22 +- .../ar/ade/oec/sra/ar_sra_age_category.py | 4 - .../gov/states/ar/ade/oec/sra/ar_sra_zone.py | 5 +- .../oec/sra/eligibility/is_ar_sra_eligible.py | 11 +- .../sra/eligibility/is_ar_sra_ess_eligible.py | 12 +- .../is_ar_sra_li_activity_eligible.py | 2 +- .../oec/sra/income/ar_sra_countable_income.py | 15 +- 25 files changed, 1252 insertions(+), 169 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/adult_age_threshold.yaml create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/max_copay_share_of_gross_income.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_care_type.yaml diff --git a/policyengine_us/parameters/gov/household/household_state_benefits.yaml b/policyengine_us/parameters/gov/household/household_state_benefits.yaml index b74241a36b5..52bda3a5887 100644 --- a/policyengine_us/parameters/gov/household/household_state_benefits.yaml +++ b/policyengine_us/parameters/gov/household/household_state_benefits.yaml @@ -136,6 +136,8 @@ values: - wa_rca # Louisiana benefits - la_oss + # Arkansas benefits + - ar_child_care_subsidies metadata: unit: list period: year diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/adult_age_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/adult_age_threshold.yaml new file mode 100644 index 00000000000..cac8d9e8155 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/adult_age_threshold.yaml @@ -0,0 +1,11 @@ +description: Arkansas treats household members at or above this age as adults under the School Readiness Assistance program. +values: + 2025-10-01: 18 + +metadata: + unit: year + period: year + label: Arkansas SRA adult age threshold + reference: + - title: FSU Procedural Manual (June 2023), Section 4.3.2 Countable Unearned Income + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=20 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml index 7717509723d..a3e87db921a 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml @@ -9,5 +9,3 @@ metadata: reference: - title: Arkansas CCDF Plan 2025-2027, Section 2.2.4 href: https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=22 - - title: ACF CCDF Family Income Eligibility Levels by State (Jan 2025) - href: https://acf.gov/sites/default/files/documents/occ/CCDF-Family-Income-Eligibility-Levels-by-State.pdf diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml index 5c4c256f370..46a39a48cb0 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml @@ -16,4 +16,4 @@ metadata: - title: OEC Rights & Responsibilities (Nov 2025) href: https://dese.ade.arkansas.gov/Files/R_&_R__Nov_2025_(English)_(1)_OEC.pdf#page=1 - title: OEC SRA Announcement Regarding Rates and Copays Effective November 1 - href: https://dese.ade.arkansas.gov/Files/OEC_SRA_Announcement_Regarding_Rates_and_Copays_Effective_November_1_OEC.pdf + href: https://dese.ade.arkansas.gov/Files/OEC_SRA_Announcement_Regarding_Rates_and_Copays_Effective_November_1_OEC.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml index 35e5ba94014..c74dadc9a75 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml @@ -25,210 +25,210 @@ BENTON_WASHINGTON: INFANT: REGULAR: FULL_TIME: - 2025-11-01: 38.00 + 2025-11-01: 38 PART_TIME: - 2025-11-01: 19.00 + 2025-11-01: 19 NIGHT_WEEKEND: FULL_TIME: - 2025-11-01: 41.80 + 2025-11-01: 41.8 PART_TIME: - 2025-11-01: 19.00 + 2025-11-01: 19 SN1: FULL_TIME: - 2025-11-01: 38.00 + 2025-11-01: 38 PART_TIME: - 2025-11-01: 19.00 + 2025-11-01: 19 SN2: FULL_TIME: - 2025-11-01: 53.20 + 2025-11-01: 53.2 PART_TIME: - 2025-11-01: 26.60 + 2025-11-01: 26.6 SN3: FULL_TIME: - 2025-11-01: 53.20 + 2025-11-01: 53.2 PART_TIME: - 2025-11-01: 26.60 + 2025-11-01: 26.6 TODDLER: REGULAR: FULL_TIME: - 2025-11-01: 37.00 + 2025-11-01: 37 PART_TIME: - 2025-11-01: 18.50 + 2025-11-01: 18.5 NIGHT_WEEKEND: FULL_TIME: - 2025-11-01: 40.70 + 2025-11-01: 40.7 PART_TIME: - 2025-11-01: 18.50 + 2025-11-01: 18.5 SN1: FULL_TIME: - 2025-11-01: 37.00 + 2025-11-01: 37 PART_TIME: - 2025-11-01: 18.50 + 2025-11-01: 18.5 SN2: FULL_TIME: - 2025-11-01: 51.80 + 2025-11-01: 51.8 PART_TIME: - 2025-11-01: 25.90 + 2025-11-01: 25.9 SN3: FULL_TIME: - 2025-11-01: 51.80 + 2025-11-01: 51.8 PART_TIME: - 2025-11-01: 25.90 + 2025-11-01: 25.9 PRESCHOOL: REGULAR: FULL_TIME: - 2025-11-01: 33.00 + 2025-11-01: 33 PART_TIME: - 2025-11-01: 16.50 + 2025-11-01: 16.5 NIGHT_WEEKEND: FULL_TIME: - 2025-11-01: 36.30 + 2025-11-01: 36.3 PART_TIME: - 2025-11-01: 16.50 + 2025-11-01: 16.5 SN1: FULL_TIME: - 2025-11-01: 33.00 + 2025-11-01: 33 PART_TIME: - 2025-11-01: 16.50 + 2025-11-01: 16.5 SN2: FULL_TIME: - 2025-11-01: 46.20 + 2025-11-01: 46.2 PART_TIME: - 2025-11-01: 23.10 + 2025-11-01: 23.1 SN3: FULL_TIME: - 2025-11-01: 46.20 + 2025-11-01: 46.2 PART_TIME: - 2025-11-01: 23.10 + 2025-11-01: 23.1 SCHOOL_AGED: REGULAR: FULL_TIME: - 2025-11-01: 28.00 + 2025-11-01: 28 PART_TIME: - 2025-11-01: 14.00 + 2025-11-01: 14 NIGHT_WEEKEND: FULL_TIME: - 2025-11-01: 30.80 + 2025-11-01: 30.8 PART_TIME: - 2025-11-01: 14.00 + 2025-11-01: 14 SN1: FULL_TIME: - 2025-11-01: 28.00 + 2025-11-01: 28 PART_TIME: - 2025-11-01: 14.00 + 2025-11-01: 14 SN2: FULL_TIME: - 2025-11-01: 39.20 + 2025-11-01: 39.2 PART_TIME: - 2025-11-01: 19.60 + 2025-11-01: 19.6 SN3: FULL_TIME: - 2025-11-01: 39.20 + 2025-11-01: 39.2 PART_TIME: - 2025-11-01: 19.60 + 2025-11-01: 19.6 STATEWIDE: INFANT: REGULAR: FULL_TIME: - 2025-11-01: 36.00 + 2025-11-01: 36 PART_TIME: - 2025-11-01: 18.00 + 2025-11-01: 18 NIGHT_WEEKEND: FULL_TIME: - 2025-11-01: 39.60 + 2025-11-01: 39.6 PART_TIME: - 2025-11-01: 18.00 + 2025-11-01: 18 SN1: FULL_TIME: - 2025-11-01: 36.00 + 2025-11-01: 36 PART_TIME: - 2025-11-01: 18.00 + 2025-11-01: 18 SN2: FULL_TIME: - 2025-11-01: 50.40 + 2025-11-01: 50.4 PART_TIME: - 2025-11-01: 25.20 + 2025-11-01: 25.2 SN3: FULL_TIME: - 2025-11-01: 50.40 + 2025-11-01: 50.4 PART_TIME: - 2025-11-01: 25.20 + 2025-11-01: 25.2 TODDLER: REGULAR: FULL_TIME: - 2025-11-01: 35.00 + 2025-11-01: 35 PART_TIME: - 2025-11-01: 17.50 + 2025-11-01: 17.5 NIGHT_WEEKEND: FULL_TIME: - 2025-11-01: 38.50 + 2025-11-01: 38.5 PART_TIME: - 2025-11-01: 17.50 + 2025-11-01: 17.5 SN1: FULL_TIME: - 2025-11-01: 35.00 + 2025-11-01: 35 PART_TIME: - 2025-11-01: 17.50 + 2025-11-01: 17.5 SN2: FULL_TIME: - 2025-11-01: 49.00 + 2025-11-01: 49 PART_TIME: - 2025-11-01: 24.50 + 2025-11-01: 24.5 SN3: FULL_TIME: - 2025-11-01: 49.00 + 2025-11-01: 49 PART_TIME: - 2025-11-01: 24.50 + 2025-11-01: 24.5 PRESCHOOL: REGULAR: FULL_TIME: - 2025-11-01: 33.00 + 2025-11-01: 33 PART_TIME: - 2025-11-01: 16.50 + 2025-11-01: 16.5 NIGHT_WEEKEND: FULL_TIME: - 2025-11-01: 36.30 + 2025-11-01: 36.3 PART_TIME: - 2025-11-01: 16.50 + 2025-11-01: 16.5 SN1: FULL_TIME: - 2025-11-01: 33.00 + 2025-11-01: 33 PART_TIME: - 2025-11-01: 16.50 + 2025-11-01: 16.5 SN2: FULL_TIME: - 2025-11-01: 46.20 + 2025-11-01: 46.2 PART_TIME: - 2025-11-01: 23.10 + 2025-11-01: 23.1 SN3: FULL_TIME: - 2025-11-01: 46.20 + 2025-11-01: 46.2 PART_TIME: - 2025-11-01: 23.10 + 2025-11-01: 23.1 SCHOOL_AGED: REGULAR: FULL_TIME: - 2025-11-01: 28.00 + 2025-11-01: 28 PART_TIME: - 2025-11-01: 14.00 + 2025-11-01: 14 NIGHT_WEEKEND: FULL_TIME: - 2025-11-01: 30.80 + 2025-11-01: 30.8 PART_TIME: - 2025-11-01: 14.00 + 2025-11-01: 14 SN1: FULL_TIME: - 2025-11-01: 28.00 + 2025-11-01: 28 PART_TIME: - 2025-11-01: 14.00 + 2025-11-01: 14 SN2: FULL_TIME: - 2025-11-01: 39.20 + 2025-11-01: 39.2 PART_TIME: - 2025-11-01: 19.60 + 2025-11-01: 19.6 SN3: FULL_TIME: - 2025-11-01: 39.20 + 2025-11-01: 39.2 PART_TIME: - 2025-11-01: 19.60 + 2025-11-01: 19.6 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml index 85008d39662..c35d1a76e81 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml @@ -1,16 +1,20 @@ description: Arkansas sets this weekly hours threshold for full-time child care under the School Readiness Assistance program. -# Arkansas rate sheets distinguish Full Time vs Part Time as billing -# categories but do NOT define the numeric hours cut-point. The encoded -# 30-hour threshold mirrors peer-state conventions (NH uses 31+ for FT; -# RI uses 30/45) and is flagged for future verification with OEC. +# FSU Procedural Manual §5.4.6 defines Full Time as 7+ hours per day. We +# approximate as a per-week threshold of 35 (= 5 days * 7 hr/day) because +# the model carries `childcare_hours_per_week`, not per-day hours. This +# approximation misclassifies attendance patterns that diverge from a +# 5-day week (e.g., 4 days * 8 hr = 32 hr/wk would be FT under FSU but +# PT here). values: - 2025-10-01: 30 + 2025-10-01: 35 metadata: unit: hour period: year label: Arkansas SRA full-time weekly hours threshold reference: + - title: FSU Procedural Manual (June 2023), Section 5.4.6 Level of Care + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=29 - title: SRA Sliding Fee Scale - Statewide Full Time (Nov 1, 2025) - establishes Full Time category href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf - title: SRA Sliding Fee Scale - Statewide Part Time (Nov 1, 2025) - establishes Part Time category diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/max_copay_share_of_gross_income.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/max_copay_share_of_gross_income.yaml new file mode 100644 index 00000000000..e32f04d702c --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/max_copay_share_of_gross_income.yaml @@ -0,0 +1,14 @@ +description: Arkansas caps the total family copay at this share of gross monthly income under the School Readiness Assistance program. +# CCDF rules cap copays at 7% of gross family income; Arkansas's CCDF State +# Plan §3.1.1 self-certifies a stricter 4% maximum. The cap applies per +# family, regardless of the number of children participating in CCDF. +values: + 2025-11-01: 0.04 + +metadata: + unit: /1 + period: year + label: Arkansas SRA maximum family copay share of gross income + reference: + - title: Arkansas CCDF Plan 2025-2027, Section 3.1.1 Family Co-payment + href: https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=39 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml index fa2770568c3..f23675e1d5f 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml @@ -1,6 +1,6 @@ description: Arkansas sets this share of state median income as the no-copay threshold for non-school-aged children under the School Readiness Assistance program. values: - 2025-11-01: 0.40 + 2025-11-01: 0.4 metadata: unit: /1 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml index e6e47ea8903..dcb77b019e3 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/partial_subsidy_smi_threshold.yaml @@ -1,6 +1,6 @@ description: Arkansas sets this share of state median income as the upper bound of the partial-subsidy income tier under the School Readiness Assistance program. values: - 2025-11-01: 0.60 + 2025-11-01: 0.6 metadata: unit: /1 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/state_share_by_tier.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/state_share_by_tier.yaml index 939e7a2e6c4..961a05c933b 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/state_share_by_tier.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/state_share_by_tier.yaml @@ -20,60 +20,60 @@ metadata: INFANT: FULL_TIME: LE_40: - 2025-11-01: 1.00 + 2025-11-01: 1 GT_40_LE_60: - 2025-11-01: 0.80 + 2025-11-01: 0.8 GT_60: - 2025-11-01: 0.70 + 2025-11-01: 0.7 PART_TIME: LE_40: - 2025-11-01: 1.00 + 2025-11-01: 1 GT_40_LE_60: - 2025-11-01: 0.70 + 2025-11-01: 0.7 GT_60: - 2025-11-01: 0.60 + 2025-11-01: 0.6 TODDLER: FULL_TIME: LE_40: - 2025-11-01: 1.00 + 2025-11-01: 1 GT_40_LE_60: - 2025-11-01: 0.80 + 2025-11-01: 0.8 GT_60: - 2025-11-01: 0.70 + 2025-11-01: 0.7 PART_TIME: LE_40: - 2025-11-01: 1.00 + 2025-11-01: 1 GT_40_LE_60: - 2025-11-01: 0.60 + 2025-11-01: 0.6 GT_60: - 2025-11-01: 0.50 + 2025-11-01: 0.5 PRESCHOOL: FULL_TIME: LE_40: - 2025-11-01: 1.00 + 2025-11-01: 1 GT_40_LE_60: - 2025-11-01: 0.70 + 2025-11-01: 0.7 GT_60: - 2025-11-01: 0.60 + 2025-11-01: 0.6 PART_TIME: LE_40: - 2025-11-01: 1.00 + 2025-11-01: 1 GT_40_LE_60: - 2025-11-01: 0.60 + 2025-11-01: 0.6 GT_60: - 2025-11-01: 0.50 + 2025-11-01: 0.5 SCHOOL_AGED: FULL_TIME: LE_40: - 2025-11-01: 0.80 + 2025-11-01: 0.8 GT_40_LE_60: - 2025-11-01: 0.50 + 2025-11-01: 0.5 GT_60: - 2025-11-01: 0.30 + 2025-11-01: 0.3 PART_TIME: LE_40: - 2025-11-01: 0.70 + 2025-11-01: 0.7 GT_40_LE_60: - 2025-11-01: 0.50 + 2025-11-01: 0.5 GT_60: - 2025-11-01: 0.30 + 2025-11-01: 0.3 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml index ec0f5ae4a11..11016a858a7 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml @@ -211,3 +211,95 @@ output: # Teen's 30 hours is masked out; adult max = 10 hr, below Year-1 threshold (20) is_ar_sra_ess_eligible: false + +- name: Case 10, month 13 (first Year-2 month) with 20 hours falls below the Year-2 threshold (25). + period: 2026-01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 20 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 13 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: false + +- name: Case 11, month 13 with 25 hours satisfies the Year-2 threshold. + period: 2026-01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 25 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 13 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: true + +- name: Case 12, Year-1 family with 19 hours falls one hour short of the 20-hour threshold. + period: 2026-01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 19 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 6 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: false + +- name: Case 13, Year-2 family with 24 hours falls one hour short of the 25-hour threshold. + period: 2026-01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 24 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 18 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml index eaa23fb83ee..e8939e6a920 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml @@ -151,3 +151,22 @@ state_code: AR output: is_ar_sra_li_activity_eligible: true + +- name: Case 8, household with only children (no adult) is not activity-eligible. + period: 2026-01 + input: + people: + person1: + age: 8 + person2: + age: 4 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_li_activity_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml index cdba95a4cf4..ad58e73b5dd 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml @@ -17,6 +17,10 @@ # # All scenarios use childcare_attending_days_per_month = 22 (typical weekday count). # Pre-subsidy expenses are set high enough that the state-payment cap binds. +# +# 4% copay cap (CCDF State Plan §3.1.1): family copay sum is capped at 4% of +# monthly countable income. When the rate-sheet copays exceed the cap, the +# state covers the gap (cap_savings added to subsidy). - name: Case 1, LI single mother, 1 toddler, full-time, Statewide. period: 2026-01 @@ -49,10 +53,13 @@ county_str: PULASKI_COUNTY_AR output: is_ar_sra_eligible: true - # Toddler, Statewide, FT, GT_40_LE_60: - # base = $35, share = 0.80, daily state payment = $28.00 - # monthly state payment = 28 * 22 = $616 - ar_sra: 616 + # Toddler FT GT_40_LE_60, Statewide: + # daily_state_payment = $28, monthly = $616 (uncapped subsidy at cap) + # monthly_copay = $7 * 22 = $154 + # monthly countable income = $30,695 / 12 = $2,557.92 + # 4% cap = $102.32 -> cap_savings = $154 - $102.32 = $51.68 + # ar_sra = $616 + $51.68 = $667.68 + ar_sra: 667.68 - name: Case 2, LI two-parent, 1 infant, full-time, Benton/Washington zone. period: 2026-01 @@ -89,10 +96,13 @@ county_str: BENTON_COUNTY_AR output: is_ar_sra_eligible: true - # Infant, Benton/Washington, FT, GT_60: - # base = $38, share = 0.70, daily state payment = $26.60 - # monthly state payment = 26.60 * 22 = $585.20 - ar_sra: 585.20 + # Infant FT GT_60, Benton/Washington: + # daily_state_payment = $26.60, monthly = $585.20 (uncapped at cap) + # monthly_copay = $11.40 * 22 = $250.80 + # monthly countable income = $60,668 / 12 = $5,055.67 + # 4% cap = $202.23 -> cap_savings = $250.80 - $202.23 = $48.57 + # ar_sra = $585.20 + $48.57 = $633.77 + ar_sra: 633.77 - name: Case 3, LI single parent, 1 preschooler, FT, Statewide, no-copay floor at LE_40. period: 2026-01 @@ -203,10 +213,11 @@ county_str: PULASKI_COUNTY_AR output: is_ar_sra_eligible: true - # Toddler, Statewide, FT, GT_40_LE_60: - # base = $35, share = 0.80, daily state payment = $28.00 - # monthly state payment = 28 * 22 = $616 - ar_sra: 616 + # Toddler FT GT_40_LE_60, Statewide (same rate-sheet cell as Case 1): + # monthly countable income = $27,626 / 12 = $2,302.17 + # 4% cap = $92.09 -> cap_savings = $154 - $92.09 = $61.91 + # ar_sra = $616 + $61.91 = $677.91 + ar_sra: 677.91 - name: Case 6, family income above 85 percent SMI gets zero benefit. period: 2026-01 @@ -301,6 +312,7 @@ members: [person1, person2] state_code: CA output: + is_ar_sra_eligible: false ar_sra: 0 - name: Case 9, LI single parent with toddler in SN2 special-needs care, Statewide FT. @@ -480,10 +492,13 @@ county_str: PULASKI_COUNTY_AR output: is_ar_sra_eligible: true - # School-Aged Statewide FT LE_40: base = $28, share = 0.80 (always copay) - # daily state payment = $28 * 0.80 = $22.40 - # monthly state payment = $22.40 * 22 = $492.80 - ar_sra: 492.80 + # School-Aged FT LE_40, Statewide (school-aged always has copay): + # daily_state_payment = $28 * 0.80 = $22.40, monthly = $492.80 (uncapped) + # monthly_copay = $5.60 * 22 = $123.20 + # monthly countable income = $18,417 / 12 = $1,534.75 + # 4% cap = $61.39 -> cap_savings = $123.20 - $61.39 = $61.81 + # ar_sra = $492.80 + $61.81 = $554.61 + ar_sra: 554.61 - name: Case 14, part-time infant care, LI parent, Statewide. period: 2026-01 @@ -519,3 +534,157 @@ # Statewide Infant PT REGULAR base = $18, share LE_40 = 1.00 # daily state payment = $18.00, monthly = $18 * 22 = $396 ar_sra: 396 + +- name: Case 15, NIGHT_WEEKEND care, toddler at LE_40 SMI, FT, Statewide. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + ar_sra_care_type: NIGHT_WEEKEND + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Toddler NIGHT_WEEKEND FT, Statewide, LE_40: + # base = $38.50, share = 1.00 -> copay = $0 + # monthly state payment = $38.50 * 22 = $847 + ar_sra: 847 + +- name: Case 16, SN1 care, toddler at LE_40 SMI, FT, Statewide. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + ar_sra_care_type: SN1 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Toddler SN1 FT, Statewide, LE_40 (SN1 rates match REGULAR for toddler): + # base = $35, share = 1.00 -> copay = $0 + # monthly state payment = $35 * 22 = $770 + ar_sra: 770 + +- name: Case 17, SN3 care, toddler at LE_40 SMI, FT, Statewide. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + ar_sra_care_type: SN3 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Toddler SN3 FT, Statewide, LE_40 (SN3 base = $49, premium tier): + # base = $49, share = 1.00 -> copay = $0 + # monthly state payment = $49 * 22 = $1078 + ar_sra: 1078 + +- name: Case 18, two-child cap-binding case demonstrates 4% copay ceiling. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + # 3-person SMI = $75,835.20; 50% = $37,918 (GT_40_LE_60 tier) + employment_income: 37_918 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + person3: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + tax_units: + tax_unit: + members: [person1, person2, person3] + spm_units: + spm_unit: + members: [person1, person2, person3] + spm_unit_pre_subsidy_childcare_expenses: 30_000 + households: + household: + members: [person1, person2, person3] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Two toddlers, FT GT_40_LE_60, Statewide: + # per-child daily_state_payment = $28, monthly = $616 each (uncapped) + # per-child monthly_copay = $154, total uncapped copay = $308 + # monthly countable income = $37,918 / 12 = $3,159.83 + # 4% cap = $126.39 -> cap_savings = $308 - $126.39 = $181.61 + # total uncapped subsidy = $1,232 + # ar_sra = $1,232 + $181.61 = $1,413.61 + ar_sra: 1413.61 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_age_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_age_category.yaml index 333cabb6382..17593f3a124 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_age_category.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_age_category.yaml @@ -58,3 +58,81 @@ state_code: AR output: ar_sra_age_category: SCHOOL_AGED + +- name: Case 5, 17-month-old (1.417 years) is the last INFANT month. + period: 2026-01 + input: + people: + person1: + age: 1.417 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_age_category: INFANT + +- name: Case 6, 18-month-old (1.5 years) is the first TODDLER month. + period: 2026-01 + input: + people: + person1: + age: 1.5 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_age_category: TODDLER + +- name: Case 7, 35-month-old (2.917 years) is the last TODDLER month. + period: 2026-01 + input: + people: + person1: + age: 2.917 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_age_category: TODDLER + +- name: Case 8, 36-month-old (3 years) is the first PRESCHOOL month. + period: 2026-01 + input: + people: + person1: + age: 3 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_age_category: PRESCHOOL + +- name: Case 9, 71-month-old (5.917 years) is the last PRESCHOOL month. + period: 2026-01 + input: + people: + person1: + age: 5.917 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_age_category: PRESCHOOL + +- name: Case 10, 72-month-old (6 years) is the first SCHOOL_AGED month. + period: 2026-01 + input: + people: + person1: + age: 6 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_age_category: SCHOOL_AGED diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_care_type.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_care_type.yaml new file mode 100644 index 00000000000..5203b76fa05 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_care_type.yaml @@ -0,0 +1,71 @@ +# ar_sra_care_type is a bare-input enum variable; default is REGULAR. +# Verify each enum value round-trips correctly. + +- name: Case 1, default ar_sra_care_type is REGULAR. + period: 2026-01 + input: + people: + person1: + age: 2 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_care_type: REGULAR + +- name: Case 2, NIGHT_WEEKEND care type round-trips. + period: 2026-01 + input: + people: + person1: + age: 2 + ar_sra_care_type: NIGHT_WEEKEND + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_care_type: NIGHT_WEEKEND + +- name: Case 3, SN1 care type round-trips. + period: 2026-01 + input: + people: + person1: + age: 2 + ar_sra_care_type: SN1 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_care_type: SN1 + +- name: Case 4, SN2 care type round-trips. + period: 2026-01 + input: + people: + person1: + age: 2 + ar_sra_care_type: SN2 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_care_type: SN2 + +- name: Case 5, SN3 care type round-trips. + period: 2026-01 + input: + people: + person1: + age: 2 + ar_sra_care_type: SN3 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_care_type: SN3 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml index 41b9db28b39..b03c49c57aa 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml @@ -224,3 +224,55 @@ state_code: AR output: ar_sra_daily_base_rate: 36.30 + +- name: Case 14, Statewide infant Night/Weekend part time mirrors REGULAR PT (18.00 — modeling fallback). + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 0 + childcare_hours_per_week: 20 + ar_sra_care_type: NIGHT_WEEKEND + households: + household: + members: [person1] + county_str: PULASKI_COUNTY_AR + state_code: AR + output: + # PT NIGHT_WEEKEND has no source rate; fallback to PT REGULAR per base_rate.yaml. + ar_sra_daily_base_rate: 18.00 + +- name: Case 15, Benton/Washington infant SN2 full time base rate is 53.20. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 0 + childcare_hours_per_week: 40 + ar_sra_care_type: SN2 + households: + household: + members: [person1] + county_str: BENTON_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 53.20 + +- name: Case 16, Benton/Washington toddler Night/Weekend full time base rate is 40.70. + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 2 + childcare_hours_per_week: 40 + ar_sra_care_type: NIGHT_WEEKEND + households: + household: + members: [person1] + county_str: WASHINGTON_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 40.70 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.yaml index fa2a5967c25..2fb148ddfcb 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.yaml @@ -127,3 +127,566 @@ output: # School-Aged FT LE_40 = 0.80 (school-aged always has copay) ar_sra_state_share: [0, 0.80] + +- name: Case 5, infant at 30 percent SMI (FT) gets state share 1.00. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Infant FT LE_40 = 1.00 + ar_sra_state_share: [0, 1.00] + +- name: Case 6, infant at 50 percent SMI (FT) gets state share 0.80. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + # 90,280 * 0.68 * 0.50 = $30,695.20 + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Infant FT GT_40_LE_60 = 0.80 + ar_sra_state_share: [0, 0.80] + +- name: Case 7, infant at 75 percent SMI (FT) gets state share 0.70. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + # 90,280 * 0.68 * 0.75 = $46,043 + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Infant FT GT_60 = 0.70 + ar_sra_state_share: [0, 0.70] + +- name: Case 8, infant at 30 percent SMI (PT) gets state share 1.00. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + # Below 30 hr FT threshold + childcare_hours_per_week: 20 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Infant PT LE_40 = 1.00 + ar_sra_state_share: [0, 1.00] + +- name: Case 9, infant at 50 percent SMI (PT) gets state share 0.70. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 20 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Infant PT GT_40_LE_60 = 0.70 + ar_sra_state_share: [0, 0.70] + +- name: Case 10, infant at 75 percent SMI (PT) gets state share 0.60. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 20 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Infant PT GT_60 = 0.60 + ar_sra_state_share: [0, 0.60] + +- name: Case 11, toddler at 30 percent SMI (PT) gets state share 1.00. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 20 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Toddler PT LE_40 = 1.00 + ar_sra_state_share: [0, 1.00] + +- name: Case 12, toddler at 50 percent SMI (PT) gets state share 0.60. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 20 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Toddler PT GT_40_LE_60 = 0.60 + ar_sra_state_share: [0, 0.60] + +- name: Case 13, toddler at 75 percent SMI (PT) gets state share 0.50. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 20 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Toddler PT GT_60 = 0.50 + ar_sra_state_share: [0, 0.50] + +- name: Case 14, preschooler at 30 percent SMI (PT) gets state share 1.00. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 20 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Preschool PT LE_40 = 1.00 + ar_sra_state_share: [0, 1.00] + +- name: Case 15, preschooler at 50 percent SMI (PT) gets state share 0.60. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 20 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Preschool PT GT_40_LE_60 = 0.60 + ar_sra_state_share: [0, 0.60] + +- name: Case 16, preschooler at 75 percent SMI (PT) gets state share 0.50. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 20 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Preschool PT GT_60 = 0.50 + ar_sra_state_share: [0, 0.50] + +- name: Case 17, school-aged child at 30 percent SMI (PT) gets state share 0.70. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 20 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # School-Aged PT LE_40 = 0.70 + ar_sra_state_share: [0, 0.70] + +- name: Case 18, school-aged child at 50 percent SMI (PT) gets state share 0.50. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 20 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # School-Aged PT GT_40_LE_60 = 0.50 + ar_sra_state_share: [0, 0.50] + +- name: Case 19, school-aged child at 75 percent SMI (PT) gets state share 0.30. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 20 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # School-Aged PT GT_60 = 0.30 + ar_sra_state_share: [0, 0.30] + +- name: Case 20, toddler at 50 percent SMI (FT) gets state share 0.80. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Toddler FT GT_40_LE_60 = 0.80 + ar_sra_state_share: [0, 0.80] + +- name: Case 21, toddler at 75 percent SMI (FT) gets state share 0.70. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Toddler FT GT_60 = 0.70 + ar_sra_state_share: [0, 0.70] + +- name: Case 22, preschooler at 30 percent SMI (FT) gets state share 1.00. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 18_417 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Preschool FT LE_40 = 1.00 + ar_sra_state_share: [0, 1.00] + +- name: Case 23, preschooler at 75 percent SMI (FT) gets state share 0.60. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Preschool FT GT_60 = 0.60 + ar_sra_state_share: [0, 0.60] + +- name: Case 24, school-aged child at 50 percent SMI (FT) gets state share 0.50. + period: 2026-01 + absolute_error_margin: 0.001 + input: + people: + person1: + age: 30 + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 7 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # School-Aged FT GT_40_LE_60 = 0.50 + ar_sra_state_share: [0, 0.50] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_time_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_time_category.yaml index 92fe0e68285..3b7525eac70 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_time_category.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_time_category.yaml @@ -1,12 +1,13 @@ -# Time category: >=30 hr/wk -> FULL_TIME, otherwise PART_TIME. -# Threshold parameter: gov.states.ar.ade.oec.sra.rates.full_time_hours_threshold = 30 +# Time category: >=35 hr/wk -> FULL_TIME, otherwise PART_TIME. +# Threshold parameter: gov.states.ar.ade.oec.sra.rates.full_time_hours_threshold = 35 +# (approximates FSU §5.4.6 "7+ hours per day" as 5 days * 7 = 35 hr/week.) -- name: Case 1, 30 hours per week is FULL_TIME at the threshold. +- name: Case 1, 35 hours per week is FULL_TIME at the threshold. period: 2026-01 input: people: person1: - childcare_hours_per_week: 30 + childcare_hours_per_week: 35 households: household: members: [person1] @@ -14,12 +15,12 @@ output: ar_sra_time_category: FULL_TIME -- name: Case 2, 35 hours per week is FULL_TIME. +- name: Case 2, 40 hours per week is FULL_TIME. period: 2026-01 input: people: person1: - childcare_hours_per_week: 35 + childcare_hours_per_week: 40 households: household: members: [person1] @@ -40,12 +41,12 @@ output: ar_sra_time_category: PART_TIME -- name: Case 4, 29 hours per week is PART_TIME just below the threshold. +- name: Case 4, 34 hours per week is PART_TIME just below the threshold. period: 2026-01 input: people: person1: - childcare_hours_per_week: 29 + childcare_hours_per_week: 34 households: household: members: [person1] diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py index b67220f270d..f2a38904865 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py @@ -4,13 +4,13 @@ class ar_sra(Variable): value_type = float entity = SPMUnit - unit = USD label = "Arkansas School Readiness Assistance benefit amount" + unit = USD definition_period = MONTH defined_for = "is_ar_sra_eligible" reference = ( "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", - "https://dese.ade.arkansas.gov/Files/R_&_R__Nov_2025_(English)_(1)_OEC.pdf#page=1", + "https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=39", ) def formula(spm_unit, period, parameters): @@ -18,16 +18,22 @@ def formula(spm_unit, period, parameters): is_eligible_child = person("is_ar_sra_child_eligible", period) daily_state_payment = person("ar_sra_daily_state_payment", period) daily_copay = person("ar_sra_daily_copay", period) - # `childcare_attending_days_per_month` is YEAR-defined but stores - # a monthly count (e.g., 22 days/mo); read at this_year to skip the - # YEAR→MONTH auto-divide. attending_days = person("childcare_attending_days_per_month", period.this_year) monthly_max_state_payment = daily_state_payment * attending_days monthly_copay = daily_copay * attending_days - # YEAR-defined expense auto-divides to monthly at MONTH period. monthly_expense = person("pre_subsidy_childcare_expenses", period) - subsidy = min_( + uncapped_subsidy = min_( max_(monthly_expense - monthly_copay, 0), monthly_max_state_payment, ) - return spm_unit.sum(subsidy * is_eligible_child) + total_uncapped_subsidy = spm_unit.sum(uncapped_subsidy * is_eligible_child) + # CCDF State Plan §3.1.1 caps the family copay at 4% of gross income + # per family, regardless of the number of children. When rate-sheet + # copays sum above the cap, the state covers the gap. + p = parameters(period).gov.states.ar.ade.oec.sra.rates + total_uncapped_copay = spm_unit.sum(monthly_copay * is_eligible_child) + copay_ceiling = p.max_copay_share_of_gross_income * spm_unit( + "ar_sra_countable_income", period + ) + cap_savings = max_(total_uncapped_copay - copay_ceiling, 0) + return total_uncapped_subsidy + cap_savings diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py index 8d3e28d38ee..9baba36d547 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py @@ -20,9 +20,5 @@ class ar_sra_age_category(Variable): def formula(person, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.rates.age_category_months - # `age` is YEAR-defined; `period.this_year` returns age in years (float). - # Multiply by 12 to compare against month-based thresholds. age_months = person("age", period.this_year) * MONTHS_IN_YEAR - # The bracket returns the integer enum index (0=INFANT, 1=TODDLER, - # 2=PRESCHOOL, 3=SCHOOL_AGED); PolicyEngine maps it to the enum. return p.calc(age_months) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_zone.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_zone.py index 153147b73f9..a1b1a61cdca 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_zone.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_zone.py @@ -20,9 +20,8 @@ class ar_sra_zone(Variable): ) def formula(household, period, parameters): - # `defined_for = StateCode.AR` filters output but does NOT short-circuit - # vectorized execution, so non-AR county strings would still flow into - # this lookup. Guard by checking state first. + # Belt-and-suspenders: defined_for filters output but doesn't gate + # the lookup, so guard county_str against non-AR rows. state = household("state_code_str", period.this_year) county = household("county_str", period.this_year) in_benton_washington = (state == "AR") & ( diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py index 4dc8cee34f1..073132c8905 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py @@ -14,12 +14,15 @@ class is_ar_sra_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra - if not p.in_effect: - return False has_eligible_child = add(spm_unit, period, ["is_ar_sra_child_eligible"]) > 0 income_ok = spm_unit("is_ar_sra_income_eligible", period) asset_ok = spm_unit("is_ccdf_asset_eligible", period.this_year) li_active = spm_unit("is_ar_sra_li_activity_eligible", period) ess_active = spm_unit("is_ar_sra_ess_eligible", period) - activity_ok = li_active | ess_active - return has_eligible_child & income_ok & asset_ok & activity_ok + return ( + p.in_effect + & has_eligible_child + & income_ok + & asset_ok + & (li_active | ess_active) + ) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py index c677eaea02b..7a4b46c52e0 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py @@ -18,11 +18,19 @@ def formula(spm_unit, period, parameters): in_track = was_tea & (ar_tea == 0) & within_window in_year_1 = months_since <= p.ess_year_1_window_months person = spm_unit.members - is_adult = person("age", period.this_year) >= 18 + is_adult = person("age", period.this_year) >= p.adult_age_threshold hours = person("weekly_hours_worked", period.this_year) adult_hours = where(is_adult, hours, 0) max_adult_hours = spm_unit.max(adult_hours) year_1_active = max_adult_hours >= p.activity_hours_ess_year_1 - year_2_active = max_adult_hours >= p.activity_hours_ess_year_2 + # FSU §4.1.5.2 / R&R Nov 2025: Year-2 activity can be satisfied by + # 25+ hr/wk work, school/training, or a combination. We don't track + # AR TEA's net-income trigger at the moment, so the Year-1 alt path + # ("earnings make family TEA-income-ineligible") is unmodeled. + adult_is_student = is_adult & person("is_full_time_student", period.this_year) + any_adult_student = spm_unit.sum(adult_is_student) > 0 + year_2_active = ( + max_adult_hours >= p.activity_hours_ess_year_2 + ) | any_adult_student activity_ok = where(in_year_1, year_1_active, year_2_active) return in_track & activity_ok diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py index fb767119a86..328af84c6f9 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py @@ -12,7 +12,7 @@ class is_ar_sra_li_activity_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.eligibility person = spm_unit.members - is_adult = person("age", period.this_year) >= 18 + is_adult = person("age", period.this_year) >= p.adult_age_threshold hours = person("weekly_hours_worked", period.this_year) is_student = person("is_full_time_student", period.this_year) meets_activity = (hours >= p.activity_hours_li) | is_student diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.py index 3ba404387d6..514852870d4 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.py @@ -14,14 +14,11 @@ class ar_sra_countable_income(Variable): ) def formula(spm_unit, period, parameters): - p = parameters(period).gov.states.ar.ade.oec.sra.income - # FSU Manual Section 4.3.2: SSI and Social Security of children under - # 18 are excluded from countable income. Sum each listed source per - # person and mask out child contributions before aggregating to the - # SPM unit. + p = parameters(period).gov.states.ar.ade.oec.sra + # FSU Manual §4.3.2 excludes SSI and Social Security of children + # from countable income; mask per-person contributions by adult + # status before aggregating to the SPM unit. person = spm_unit.members - # `age` is YEAR-defined; period.this_year reverses auto-division so - # this returns age in years for monthly periods. - is_adult = person("age", period.this_year) >= 18 - per_person_income = sum(person(source, period) for source in p.sources) + is_adult = person("age", period.this_year) >= p.eligibility.adult_age_threshold + per_person_income = sum(person(source, period) for source in p.income.sources) return spm_unit.sum(per_person_income * is_adult) From b8b76080a61b79c79aabdabdfd8fe923bbb47062 Mon Sep 17 00:00:00 2001 From: Ziming Date: Sun, 17 May 2026 23:56:41 -0400 Subject: [PATCH 09/17] Review-fix round 5: address /review-program re-review findings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Critical: 0 (none introduced). Should-Address: - Tighten student OR-clause from is_full_time_student to is_full_time_college_student (FSU §4.1.5.4 converts via post-secondary credit hours, not K-12 enrollment). Applies to both LI and ESS tracks. - ESS Year-1 student OR-clause was asymmetrically missing — make Year-1 symmetric with Year-2 (FSU §4.1.5.2 / R&R Nov 2025 both authorize full-time school as Year-1 path). - Restore is_ar_sra_eligible early-return guard (project standard; matches CT/MT/SC/UT pattern, broadcast-safe with YEAR-period in_effect lookup). - ar_sra.py: clamp countable income at 0 before computing copay ceiling (prevents cap_savings inflation on negative income). Add min_(total_uncapped_subsidy + cap_savings, total_expense) clamp so total subsidy never exceeds actual childcare cost. - in_effect.yaml: change from period: year to period: month so the Nov 1, 2025 start date isn't backdated to Jan 1, 2025 by year-period lookup. Drop duplicate Case 3 from in_effect tests. - adult_age_threshold.yaml: cite FSU §4.3 (p.19) which contains the explicit "age eighteen (18) years and over" language (was §4.3.2). - full_time_hours_threshold.yaml: cite FSU §5.4.6 Authorization Care Types table (p.30) rather than the section header (p.29). - ar_sra_child_eligible.yaml: fix header that claimed "tax-unit dependent" check (formula doesn't check it). - Add tests: ESS Year-1/Year-2 student satisfies activity (Cases 14/15), ESS months_since=0 boundary (Case 16), exact 40%/60% SMI tier boundaries (Cases 8/9), zero-expense integration clamp guard (Case 19), negative-income regression guard (Case 20). 146 AR SRA tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../sra/eligibility/adult_age_threshold.yaml | 4 +- .../gov/states/ar/ade/oec/sra/in_effect.yaml | 2 +- .../sra/rates/full_time_hours_threshold.yaml | 4 +- .../eligibility/ar_sra_child_eligible.yaml | 2 +- .../sra/eligibility/ar_sra_ess_eligible.yaml | 71 +++++++++++++++++++ .../oec/sra/eligibility/ar_sra_in_effect.yaml | 34 +-------- .../ar_sra_li_activity_eligible.yaml | 4 +- .../states/ar/ade/oec/sra/integration.yaml | 71 +++++++++++++++++++ .../ade/oec/sra/rates/ar_sra_income_tier.yaml | 54 ++++++++++++++ .../gov/states/ar/ade/oec/sra/ar_sra.py | 11 +-- .../oec/sra/eligibility/is_ar_sra_eligible.py | 10 +-- .../sra/eligibility/is_ar_sra_ess_eligible.py | 16 +++-- .../is_ar_sra_li_activity_eligible.py | 7 +- 13 files changed, 232 insertions(+), 58 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/adult_age_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/adult_age_threshold.yaml index cac8d9e8155..27d56b412a3 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/adult_age_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/adult_age_threshold.yaml @@ -7,5 +7,5 @@ metadata: period: year label: Arkansas SRA adult age threshold reference: - - title: FSU Procedural Manual (June 2023), Section 4.3.2 Countable Unearned Income - href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=20 + - title: FSU Procedural Manual (June 2023), Section 4.3 Countable Income (defines parents/custodians "age eighteen (18) years and over") + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=19 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml index 46a39a48cb0..59d00512ce6 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml @@ -10,7 +10,7 @@ values: metadata: unit: bool - period: year + period: month label: Arkansas SRA in effect reference: - title: OEC Rights & Responsibilities (Nov 2025) diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml index c35d1a76e81..c3f2380bda6 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml @@ -13,8 +13,8 @@ metadata: period: year label: Arkansas SRA full-time weekly hours threshold reference: - - title: FSU Procedural Manual (June 2023), Section 5.4.6 Level of Care - href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=29 + - title: FSU Procedural Manual (June 2023), Section 5.4.6 Authorization Care Types + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=30 - title: SRA Sliding Fee Scale - Statewide Full Time (Nov 1, 2025) - establishes Full Time category href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf - title: SRA Sliding Fee Scale - Statewide Part Time (Nov 1, 2025) - establishes Part Time category diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_child_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_child_eligible.yaml index 6e04ff94010..dd7868f3df6 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_child_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_child_eligible.yaml @@ -1,4 +1,4 @@ -# Eligible-child test: age < 13 AND tax-unit dependent AND immigration-eligible. +# Eligible-child test: age < 13 AND immigration-eligible. - name: Case 1, citizen child age 5 who is a dependent is eligible. period: 2026-01 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml index 11016a858a7..04bbd52aeac 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml @@ -303,3 +303,74 @@ state_code: AR output: is_ar_sra_ess_eligible: false + +- name: Case 14, Year-1 full-time college student adult with 0 hours satisfies activity via student OR-clause. + period: 2026-01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 0 + is_full_time_college_student: true + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 6 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: true + +- name: Case 15, Year-2 full-time college student adult with 0 hours satisfies activity via student OR-clause. + period: 2026-01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 0 + is_full_time_college_student: true + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 18 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: true + +- name: Case 16, was_tea is true but months_since_tea_exit is 0 falls outside the ESS window. + period: 2026-01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 0 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml index b5eb9f2550c..a1acd2d79b3 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml @@ -1,7 +1,5 @@ -# SRA program is in effect from 2025-10-01 forward. +# SRA program is in effect from 2025-11-01 forward. # The in_effect parameter gates ar_sra_eligible at the top level. -# This test verifies the gate by constructing an otherwise-eligible -# household in different periods. - name: Case 1, period 2025-01 is before SRA effective date so household is not eligible. period: 2025-01 @@ -31,35 +29,7 @@ output: is_ar_sra_eligible: false -- name: Case 2, period 2026-01 is the SRA effective date and household is eligible. - period: 2026-01 - input: - people: - person1: - age: 30 - weekly_hours_worked: 35 - employment_income: 20_000 - immigration_status: CITIZEN - person2: - age: 4 - is_tax_unit_dependent: true - immigration_status: CITIZEN - childcare_hours_per_week: 40 - tax_units: - tax_unit: - members: [person1, person2] - spm_units: - spm_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: AR - county_str: PULASKI_COUNTY_AR - output: - is_ar_sra_eligible: true - -- name: Case 3, period 2026-01 is well within the SRA era and household is eligible. +- name: Case 2, period 2026-01 is within the SRA era so household is eligible. period: 2026-01 input: people: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml index e8939e6a920..d0f7b08c03c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_li_activity_eligible.yaml @@ -128,7 +128,7 @@ output: is_ar_sra_li_activity_eligible: true -- name: Case 7, two-parent household with one working and one full-time student is eligible. +- name: Case 7, two-parent household with one working and one full-time college student is eligible. period: 2026-01 input: people: @@ -138,7 +138,7 @@ person2: age: 28 weekly_hours_worked: 0 - is_full_time_student: true + is_full_time_college_student: true person3: age: 4 is_tax_unit_dependent: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml index ad58e73b5dd..60eecc0cee0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml @@ -688,3 +688,74 @@ # total uncapped subsidy = $1,232 # ar_sra = $1,232 + $181.61 = $1,413.61 ar_sra: 1413.61 + +- name: Case 19, eligible family with zero pre-subsidy expenses gets zero subsidy (clamp guard). + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + # GT_40_LE_60 tier + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # total_expense = 0; the min_(uncapped_subsidy + cap_savings, total_expense) + # clamp keeps the subsidy from inflating beyond actual cost. + ar_sra: 0 + +- name: Case 20, negative self-employment income clamps countable income at 0 (regression guard). + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + # Self-employment loss; total countable income would be negative. + self_employment_income: -20_000 + employment_income: 5_000 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_week: 40 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Negative income -> LE_40 tier (share=1.00, copay=0) -> cap_savings=0. + # Toddler Statewide FT LE_40: monthly state payment = $35 * 22 = $770. + ar_sra: 770 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml index 0bc2aefedcb..ace5f8e3f5c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml @@ -194,3 +194,57 @@ state_code: AR output: ar_sra_income_tier: GT_60 + +- name: Case 8, family at exactly 40 percent SMI is in the LE_40 tier (boundary is inclusive). + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + # 64,737.33 * 0.40 = $25,894.93 + employment_income: 25_894.93 + immigration_status: CITIZEN + person2: + age: 4 + 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: AR + output: + ar_sra_income_tier: LE_40 + +- name: Case 9, family at exactly 60 percent SMI is in the GT_40_LE_60 tier (boundary is inclusive). + period: 2026-01 + absolute_error_margin: 0.1 + input: + people: + person1: + age: 30 + # 64,737.33 * 0.60 = $38,842.40 + employment_income: 38_842.40 + immigration_status: CITIZEN + person2: + age: 4 + 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: AR + output: + ar_sra_income_tier: GT_40_LE_60 diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py index f2a38904865..b969513480b 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py @@ -32,8 +32,11 @@ def formula(spm_unit, period, parameters): # copays sum above the cap, the state covers the gap. p = parameters(period).gov.states.ar.ade.oec.sra.rates total_uncapped_copay = spm_unit.sum(monthly_copay * is_eligible_child) - copay_ceiling = p.max_copay_share_of_gross_income * spm_unit( - "ar_sra_countable_income", period - ) + # Clamp at 0 so a negative countable income (e.g. self-employment + # loss) doesn't inflate cap_savings. + countable_income = max_(spm_unit("ar_sra_countable_income", period), 0) + copay_ceiling = p.max_copay_share_of_gross_income * countable_income cap_savings = max_(total_uncapped_copay - copay_ceiling, 0) - return total_uncapped_subsidy + cap_savings + # State subsidy never exceeds the family's actual childcare cost. + total_expense = spm_unit.sum(monthly_expense * is_eligible_child) + return min_(total_uncapped_subsidy + cap_savings, total_expense) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py index 073132c8905..0ba23bbbcc9 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_eligible.py @@ -14,15 +14,11 @@ class is_ar_sra_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra + if not p.in_effect: + return False has_eligible_child = add(spm_unit, period, ["is_ar_sra_child_eligible"]) > 0 income_ok = spm_unit("is_ar_sra_income_eligible", period) asset_ok = spm_unit("is_ccdf_asset_eligible", period.this_year) li_active = spm_unit("is_ar_sra_li_activity_eligible", period) ess_active = spm_unit("is_ar_sra_ess_eligible", period) - return ( - p.in_effect - & has_eligible_child - & income_ok - & asset_ok - & (li_active | ess_active) - ) + return has_eligible_child & income_ok & asset_ok & (li_active | ess_active) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py index 7a4b46c52e0..def30b47c31 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py @@ -22,13 +22,17 @@ def formula(spm_unit, period, parameters): hours = person("weekly_hours_worked", period.this_year) adult_hours = where(is_adult, hours, 0) max_adult_hours = spm_unit.max(adult_hours) - year_1_active = max_adult_hours >= p.activity_hours_ess_year_1 - # FSU §4.1.5.2 / R&R Nov 2025: Year-2 activity can be satisfied by - # 25+ hr/wk work, school/training, or a combination. We don't track - # AR TEA's net-income trigger at the moment, so the Year-1 alt path - # ("earnings make family TEA-income-ineligible") is unmodeled. - adult_is_student = is_adult & person("is_full_time_student", period.this_year) + # FSU §4.1.5.1-2 / R&R Nov 2025: both Year-1 and Year-2 activity can + # be satisfied by work hours OR full-time school/training. We don't + # track AR TEA's net-income trigger at the moment, so the Year-1 alt + # path "earnings make family TEA-income-ineligible" is unmodeled. + adult_is_student = is_adult & person( + "is_full_time_college_student", period.this_year + ) any_adult_student = spm_unit.sum(adult_is_student) > 0 + year_1_active = ( + max_adult_hours >= p.activity_hours_ess_year_1 + ) | any_adult_student year_2_active = ( max_adult_hours >= p.activity_hours_ess_year_2 ) | any_adult_student diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py index 328af84c6f9..ebd49f9c403 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py @@ -14,7 +14,12 @@ def formula(spm_unit, period, parameters): person = spm_unit.members is_adult = person("age", period.this_year) >= p.adult_age_threshold hours = person("weekly_hours_worked", period.this_year) - is_student = person("is_full_time_student", period.this_year) + # FSU §4.1.5.4: school converts to work-equivalent via 2.5 hr per + # semester credit. Full-time college (12+ credits) implies 30+ hr + # equivalent, satisfying LI's 30 hr/wk threshold. We don't extend + # the proxy to K-12 students because the conversion rule applies to + # post-secondary credit hours. + is_student = person("is_full_time_college_student", period.this_year) meets_activity = (hours >= p.activity_hours_li) | is_student # All adults must meet the activity test. has_adult = spm_unit.sum(is_adult) > 0 From 3f67dd4b99eab890314236653a90ba7126ab82ef Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 18 May 2026 00:04:21 -0400 Subject: [PATCH 10/17] Review-fix round 6: clear final should-address items - Spell out "Employment-Sponsored Subsidy" instead of "ESS" acronym in 3 parameter descriptions (ess_window_months, activity_hours_ess_year_1, activity_hours_ess_year_2). - Simplify hhs_smi access in is_ar_sra_income_eligible and ar_sra_income_tier: drop the explicit period.this_year + /MONTHS_IN_YEAR pattern in favor of reading the YEAR-defined hhs_smi at MONTH period (core auto-converts the USD flow variable annual->monthly). 146 AR SRA tests pass; all critical and should-address findings from multi-round /review-program now cleared. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ar/ade/oec/sra/eligibility/activity_hours_ess_year_1.yaml | 2 +- .../ar/ade/oec/sra/eligibility/activity_hours_ess_year_2.yaml | 2 +- .../states/ar/ade/oec/sra/eligibility/ess_window_months.yaml | 2 +- .../variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py | 2 +- .../ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py | 4 +--- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_1.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_1.yaml index 9c55be4a220..77c915e2b3c 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_1.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_1.yaml @@ -1,4 +1,4 @@ -description: Arkansas sets this minimum weekly activity hours threshold for at least one adult in an ESS Year 1 household under the School Readiness Assistance program. +description: Arkansas sets this minimum weekly activity hours threshold for at least one adult in an Employment-Sponsored Subsidy Year 1 household under the School Readiness Assistance program. values: 2025-10-01: 20 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_2.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_2.yaml index 8f82ff79c1a..7fdbc3422e0 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_2.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_ess_year_2.yaml @@ -1,4 +1,4 @@ -description: Arkansas sets this minimum weekly activity hours threshold for at least one adult in an ESS Year 2 household under the School Readiness Assistance program. +description: Arkansas sets this minimum weekly activity hours threshold for at least one adult in an Employment-Sponsored Subsidy Year 2 household under the School Readiness Assistance program. values: 2025-10-01: 25 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml index a5428bd2019..e2fafe1c6ff 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml @@ -1,4 +1,4 @@ -description: Arkansas limits the ESS post-Transitional Employment Assistance window to this many months under the School Readiness Assistance program. +description: Arkansas limits the Employment-Sponsored Subsidy post-Transitional Employment Assistance window to this many months under the School Readiness Assistance program. values: 2025-10-01: 24 diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py index c25c6c13efc..5a3559f29cc 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py @@ -20,7 +20,7 @@ class ar_sra_income_tier(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra monthly_income = spm_unit("ar_sra_countable_income", period) - monthly_smi = spm_unit("hhs_smi", period.this_year) / MONTHS_IN_YEAR + monthly_smi = spm_unit("hhs_smi", period) ratio = where(monthly_smi > 0, monthly_income / monthly_smi, np.inf) return select( [ diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py index e85a0c6a22d..cb25987868e 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py @@ -12,7 +12,5 @@ class is_ar_sra_income_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.eligibility monthly_income = spm_unit("ar_sra_countable_income", period) - monthly_smi_limit = ( - spm_unit("hhs_smi", period.this_year) * p.income_smi_rate / MONTHS_IN_YEAR - ) + monthly_smi_limit = spm_unit("hhs_smi", period) * p.income_smi_rate return monthly_income <= monthly_smi_limit From b0c08c120d763ffad100456ac1c2e18609045f45 Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 18 May 2026 01:26:40 -0400 Subject: [PATCH 11/17] Review-fix round 7: address review-program findings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch FT classification to per-day (FSU §5.4.6 literal): - ar_sra_time_category now reads childcare_hours_per_day; threshold = 7. - Updates ~50 test inputs from childcare_hours_per_week to childcare_hours_per_day. - Fixes the 4-day × 8-hour case that was misclassified as PT under the per-week proxy. Reference / citation fixes: - ess_window_months page anchor 26 → 27 (where 24-month value displays). - adult_age_threshold title: §4.3 "Countable Income" → §4.3 "Income". - full_time_hours_threshold title: §5.4.6 "Authorization Care Types" → "Level of Care Authorized". - income_smi_rate page anchor 22 → 21 (where section header appears). - in_effect: drop #page=1 from the one-page OEC Announcement. Code style (drop multi-line "what" comments, add explanatory NOTEs): - ar_sra.py: trim CCDF Plan and clamp comments; add NOTE on the final expense clamp. - ar_sra_zone, is_ar_sra_ess_eligible, is_ar_sra_li_activity_eligible, ar_sra_countable_income: trim multi-line comments per code-style skill. - is_ar_sra_income_eligible, ar_sra_income_tier: add hhs_smi auto-divide NOTE. Move hard-coded Benton/Washington counties to a list parameter: - New rates/benton_washington_counties.yaml; ar_sra_zone uses np.isin lookup. Test additions / fixes: - $1M asset boundary tests (exact, +$1, -$1) added to ar_sra_eligible.yaml. - Fold ar_sra_in_effect.yaml into ar_sra_eligible.yaml; remove the standalone file. - Reconcile SMI documentation across integration.yaml and ar_sra_state_share.yaml (use uprated $95,201.95 to match hhs_smi at 2026-01-01). - Add just-below 85% SMI boundary case to ar_sra_income_eligible.yaml. - Clarify ESS Case 16 (months_since_tea_exit = 0 = still on TEA, not yet in window). - absolute_error_margin: 0.1 → 0.01 (currency tests); strip 0.1 from Enum-output tier file (no margin needed); rate-output state_share keeps 0.001. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../sra/eligibility/adult_age_threshold.yaml | 2 +- .../sra/eligibility/ess_window_months.yaml | 2 +- .../oec/sra/eligibility/income_smi_rate.yaml | 2 +- .../gov/states/ar/ade/oec/sra/in_effect.yaml | 2 +- .../sra/rates/benton_washington_counties.yaml | 15 +++ .../sra/rates/full_time_hours_threshold.yaml | 14 +- .../oec/sra/eligibility/ar_sra_eligible.yaml | 126 +++++++++++++++++- .../sra/eligibility/ar_sra_ess_eligible.yaml | 2 +- .../oec/sra/eligibility/ar_sra_in_effect.yaml | 58 -------- .../eligibility/ar_sra_income_eligible.yaml | 26 ++++ .../sra/income/ar_sra_countable_income.yaml | 8 +- .../states/ar/ade/oec/sra/integration.yaml | 89 +++++++------ .../oec/sra/rates/ar_sra_daily_base_rate.yaml | 64 ++++----- .../ade/oec/sra/rates/ar_sra_daily_copay.yaml | 12 +- .../sra/rates/ar_sra_daily_state_payment.yaml | 12 +- .../ade/oec/sra/rates/ar_sra_income_tier.yaml | 9 -- .../ade/oec/sra/rates/ar_sra_state_share.yaml | 53 ++++---- .../oec/sra/rates/ar_sra_time_category.yaml | 38 ++++-- .../gov/states/ar/ade/oec/sra/ar_sra.py | 10 +- .../ar/ade/oec/sra/ar_sra_income_tier.py | 1 + .../ar/ade/oec/sra/ar_sra_time_category.py | 2 +- .../gov/states/ar/ade/oec/sra/ar_sra_zone.py | 9 +- .../sra/eligibility/is_ar_sra_ess_eligible.py | 6 +- .../eligibility/is_ar_sra_income_eligible.py | 1 + .../is_ar_sra_li_activity_eligible.py | 8 +- .../oec/sra/income/ar_sra_countable_income.py | 4 +- 26 files changed, 331 insertions(+), 244 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/benton_washington_counties.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/adult_age_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/adult_age_threshold.yaml index 27d56b412a3..75bead2cb80 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/adult_age_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/adult_age_threshold.yaml @@ -7,5 +7,5 @@ metadata: period: year label: Arkansas SRA adult age threshold reference: - - title: FSU Procedural Manual (June 2023), Section 4.3 Countable Income (defines parents/custodians "age eighteen (18) years and over") + - title: FSU Procedural Manual (June 2023), Section 4.3 Income (defines parents/custodians "age eighteen (18) years and over") href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=19 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml index e2fafe1c6ff..c68d5c655af 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml @@ -8,4 +8,4 @@ metadata: label: Arkansas SRA ESS post-TEA window months reference: - title: FSU Procedural Manual (June 2023), Section 5.4.1 - href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=26 + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=27 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml index a3e87db921a..3366180048e 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml @@ -8,4 +8,4 @@ metadata: label: Arkansas SRA income limit SMI rate reference: - title: Arkansas CCDF Plan 2025-2027, Section 2.2.4 - href: https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=22 + href: https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=21 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml index 59d00512ce6..462c3404514 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml @@ -16,4 +16,4 @@ metadata: - title: OEC Rights & Responsibilities (Nov 2025) href: https://dese.ade.arkansas.gov/Files/R_&_R__Nov_2025_(English)_(1)_OEC.pdf#page=1 - title: OEC SRA Announcement Regarding Rates and Copays Effective November 1 - href: https://dese.ade.arkansas.gov/Files/OEC_SRA_Announcement_Regarding_Rates_and_Copays_Effective_November_1_OEC.pdf#page=1 + href: https://dese.ade.arkansas.gov/Files/OEC_SRA_Announcement_Regarding_Rates_and_Copays_Effective_November_1_OEC.pdf diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/benton_washington_counties.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/benton_washington_counties.yaml new file mode 100644 index 00000000000..f4260904c08 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/benton_washington_counties.yaml @@ -0,0 +1,15 @@ +description: Arkansas uses these counties as the higher-cost Benton/Washington reimbursement zone under the School Readiness Assistance program. +values: + 2025-10-01: + - BENTON_COUNTY_AR + - WASHINGTON_COUNTY_AR + +metadata: + unit: list + period: year + label: Arkansas SRA Benton/Washington counties + reference: + - title: SRA Sliding Fee Scale - Benton/Washington Co Full Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf + - title: SRA Sliding Fee Scale - Benton/Washington Co Part Time (Nov 1, 2025) + href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml index c3f2380bda6..c30568a855e 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/full_time_hours_threshold.yaml @@ -1,19 +1,13 @@ -description: Arkansas sets this weekly hours threshold for full-time child care under the School Readiness Assistance program. -# FSU Procedural Manual §5.4.6 defines Full Time as 7+ hours per day. We -# approximate as a per-week threshold of 35 (= 5 days * 7 hr/day) because -# the model carries `childcare_hours_per_week`, not per-day hours. This -# approximation misclassifies attendance patterns that diverge from a -# 5-day week (e.g., 4 days * 8 hr = 32 hr/wk would be FT under FSU but -# PT here). +description: Arkansas sets this daily hours threshold for full-time child care under the School Readiness Assistance program. values: - 2025-10-01: 35 + 2025-10-01: 7 metadata: unit: hour period: year - label: Arkansas SRA full-time weekly hours threshold + label: Arkansas SRA full-time daily hours threshold reference: - - title: FSU Procedural Manual (June 2023), Section 5.4.6 Authorization Care Types + - title: FSU Procedural Manual (June 2023), Section 5.4.6 Level of Care Authorized href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=30 - title: SRA Sliding Fee Scale - Statewide Full Time (Nov 1, 2025) - establishes Full Time category href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml index b1fd2ef2ea4..c316535c9f9 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_eligible.yaml @@ -14,7 +14,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -43,7 +43,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -91,7 +91,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -120,7 +120,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -151,14 +151,13 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] spm_units: spm_unit: members: [person1, person2] - # Above the $1M CCDF asset limit spm_unit_assets: 2_000_000 households: household: @@ -167,3 +166,118 @@ county_str: PULASKI_COUNTY_AR output: is_ar_sra_eligible: false + +- name: Case 7, assets exactly at the $1M CCDF limit are eligible. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked: 35 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_assets: 1_000_000 + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + +- name: Case 8, assets one dollar above the $1M CCDF limit fail eligibility. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked: 35 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_assets: 1_000_001 + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: false + +- name: Case 9, assets just below the $1M CCDF limit are eligible. + period: 2026-01 + input: + people: + person1: + age: 30 + weekly_hours_worked: 35 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + spm_unit_assets: 999_999 + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + +- name: Case 10, period 2025-01 is before the SRA effective date so household is not eligible. + period: 2025-01 + input: + people: + person1: + age: 30 + weekly_hours_worked: 35 + employment_income: 20_000 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml index 04bbd52aeac..7e2cb92c41c 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml @@ -352,7 +352,7 @@ output: is_ar_sra_ess_eligible: true -- name: Case 16, was_tea is true but months_since_tea_exit is 0 falls outside the ESS window. +- name: Case 16, ESS window starts at month 1, so months_since_tea_exit of 0 (still receiving TEA) is not yet in the post-TEA window. period: 2026-01 input: people: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml deleted file mode 100644 index a1acd2d79b3..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_in_effect.yaml +++ /dev/null @@ -1,58 +0,0 @@ -# SRA program is in effect from 2025-11-01 forward. -# The in_effect parameter gates ar_sra_eligible at the top level. - -- name: Case 1, period 2025-01 is before SRA effective date so household is not eligible. - period: 2025-01 - input: - people: - person1: - age: 30 - weekly_hours_worked: 35 - employment_income: 20_000 - immigration_status: CITIZEN - person2: - age: 4 - is_tax_unit_dependent: true - immigration_status: CITIZEN - childcare_hours_per_week: 40 - tax_units: - tax_unit: - members: [person1, person2] - spm_units: - spm_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: AR - county_str: PULASKI_COUNTY_AR - output: - is_ar_sra_eligible: false - -- name: Case 2, period 2026-01 is within the SRA era so household is eligible. - period: 2026-01 - input: - people: - person1: - age: 30 - weekly_hours_worked: 35 - employment_income: 20_000 - immigration_status: CITIZEN - person2: - age: 4 - is_tax_unit_dependent: true - immigration_status: CITIZEN - childcare_hours_per_week: 40 - tax_units: - tax_unit: - members: [person1, person2] - spm_units: - spm_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: AR - county_str: PULASKI_COUNTY_AR - output: - is_ar_sra_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_income_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_income_eligible.yaml index 579e6e54d45..862dcdf32d6 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_income_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_income_eligible.yaml @@ -106,3 +106,29 @@ state_code: AR output: is_ar_sra_income_eligible: true + +- name: Case 5, family income one dollar below the 85 percent SMI cap is income-eligible. + period: 2026-01 + input: + people: + person1: + age: 30 + # 64,737.33 * 0.85 = $55,026.73; just-below boundary at $55,025. + employment_income: 55_025 + immigration_status: CITIZEN + person2: + age: 4 + 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: AR + output: + is_ar_sra_income_eligible: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.yaml index 9734368474f..1f72d890543 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.yaml @@ -5,7 +5,7 @@ - name: Case 1, parent employment income is fully counted (annual $30,000 = $2,500/month). period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -26,7 +26,7 @@ - name: Case 2, child SSI is excluded (annual $25,000 parent earnings = $2,083.33/month). period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -50,7 +50,7 @@ - name: Case 3, two adults combine earnings (annual $40,000 = $3,333.33/month). period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -74,7 +74,7 @@ - name: Case 4, zero-income family produces zero countable income. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml index 60eecc0cee0..8289f6f0e02 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml @@ -1,9 +1,10 @@ # Arkansas SRA integration tests # # Reference parameters (Nov 1, 2025 rate sheet): -# AR SMI (FFY 2026, 4-person, 2025-10-01): $90,280/year -# SMI(2)=90,280*0.68=$61,390.40; SMI(3)=90,280*0.84=$75,835.20 +# AR SMI (FFY 2026, uprated to 2026-01-01, 4-person): $95,201.95/year +# SMI(2)=95,201.95*0.68=$64,737.33; SMI(3)=95,201.95*0.84=$79,969.64 # 85% income limit: SMI*0.85 +# Tier percentages in test comments are computed against the uprated SMI. # # Income tier brackets (% SMI): LE_40 (<=40), GT_40_LE_60 (4060) # Daily base rates (Statewide REGULAR): Infant FT $36, Toddler FT $35, @@ -24,7 +25,7 @@ - name: Case 1, LI single mother, 1 toddler, full-time, Statewide. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -37,7 +38,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 tax_units: tax_unit: @@ -63,7 +64,7 @@ - name: Case 2, LI two-parent, 1 infant, full-time, Benton/Washington zone. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -80,7 +81,7 @@ age: 0 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 tax_units: tax_unit: @@ -106,7 +107,7 @@ - name: Case 3, LI single parent, 1 preschooler, FT, Statewide, no-copay floor at LE_40. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -119,7 +120,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 tax_units: tax_unit: @@ -142,7 +143,7 @@ - name: Case 4, ESS Year 1 (post-TEA 6 months, 22 hr/wk), 1 toddler, FT, Statewide. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -155,7 +156,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 tax_units: tax_unit: @@ -181,7 +182,7 @@ - name: Case 5, ESS Year 2 (post-TEA 18 months, 26 hr/wk), 1 toddler, FT, Statewide. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -194,7 +195,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 tax_units: tax_unit: @@ -221,7 +222,7 @@ - name: Case 6, family income above 85 percent SMI gets zero benefit. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -234,7 +235,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 tax_units: tax_unit: @@ -254,7 +255,7 @@ - name: Case 7, AR resident in pre-SRA period gets zero benefit. period: 2025-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -266,7 +267,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 tax_units: tax_unit: @@ -286,7 +287,7 @@ - name: Case 8, non-AR household (state_code CA) gets zero benefit despite otherwise meeting criteria. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -298,7 +299,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 tax_units: tax_unit: @@ -317,7 +318,7 @@ - name: Case 9, LI single parent with toddler in SN2 special-needs care, Statewide FT. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -330,7 +331,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 ar_sra_care_type: SN2 tax_units: @@ -353,7 +354,7 @@ - name: Case 10, low pre-subsidy expense binds before state payment cap. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -365,7 +366,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 tax_units: tax_unit: @@ -388,7 +389,7 @@ - name: Case 11, mixed-eligibility household with one eligible child and one over-age child. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -400,13 +401,13 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 person3: age: 13 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 tax_units: tax_unit: @@ -429,7 +430,7 @@ - name: Case 12, eligible child with zero attending days produces zero benefit. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -441,7 +442,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 0 tax_units: tax_unit: @@ -463,7 +464,7 @@ - name: Case 13, school-aged child at LE_40 SMI confirms 80 percent state share through to benefit. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -476,7 +477,7 @@ age: 7 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 tax_units: tax_unit: @@ -502,7 +503,7 @@ - name: Case 14, part-time infant care, LI parent, Statewide. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -515,7 +516,7 @@ is_tax_unit_dependent: true immigration_status: CITIZEN # PT (below 30 hr full-time threshold) - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 childcare_attending_days_per_month: 22 tax_units: tax_unit: @@ -537,7 +538,7 @@ - name: Case 15, NIGHT_WEEKEND care, toddler at LE_40 SMI, FT, Statewide. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -549,7 +550,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 ar_sra_care_type: NIGHT_WEEKEND tax_units: @@ -573,7 +574,7 @@ - name: Case 16, SN1 care, toddler at LE_40 SMI, FT, Statewide. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -585,7 +586,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 ar_sra_care_type: SN1 tax_units: @@ -609,7 +610,7 @@ - name: Case 17, SN3 care, toddler at LE_40 SMI, FT, Statewide. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -621,7 +622,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 ar_sra_care_type: SN3 tax_units: @@ -645,7 +646,7 @@ - name: Case 18, two-child cap-binding case demonstrates 4% copay ceiling. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -658,13 +659,13 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 person3: age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 tax_units: tax_unit: @@ -691,7 +692,7 @@ - name: Case 19, eligible family with zero pre-subsidy expenses gets zero subsidy (clamp guard). period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -704,7 +705,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 tax_units: tax_unit: @@ -726,7 +727,7 @@ - name: Case 20, negative self-employment income clamps countable income at 0 (regression guard). period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -740,7 +741,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 childcare_attending_days_per_month: 22 tax_units: tax_unit: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml index b03c49c57aa..6d1a397cddc 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml @@ -14,12 +14,12 @@ - name: Case 1, Statewide infant full time base rate is 36.00. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 0 - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 households: household: members: [person1] @@ -30,12 +30,12 @@ - name: Case 2, Statewide toddler full time base rate is 35.00. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 2 - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 households: household: members: [person1] @@ -46,12 +46,12 @@ - name: Case 3, Statewide preschool full time base rate is 33.00. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 4 - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 households: household: members: [person1] @@ -62,12 +62,12 @@ - name: Case 4, Statewide school-aged full time base rate is 28.00. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 7 - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 households: household: members: [person1] @@ -78,12 +78,12 @@ - name: Case 5, Benton/Washington infant full time base rate is 38.00. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 0 - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 households: household: members: [person1] @@ -94,12 +94,12 @@ - name: Case 6, Benton/Washington toddler full time base rate is 37.00. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 2 - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 households: household: members: [person1] @@ -110,12 +110,12 @@ - name: Case 7, Statewide infant part time base rate is 18.00. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 0 - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 households: household: members: [person1] @@ -126,12 +126,12 @@ - name: Case 8, Benton/Washington infant part time base rate is 19.00. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 0 - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 households: household: members: [person1] @@ -142,12 +142,12 @@ - name: Case 9, Statewide infant Night/Weekend full time base rate is 39.60. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 0 - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 ar_sra_care_type: NIGHT_WEEKEND households: household: @@ -159,12 +159,12 @@ - name: Case 10, Statewide infant SN1 full time base rate is 36.00. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 0 - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 ar_sra_care_type: SN1 households: household: @@ -176,12 +176,12 @@ - name: Case 11, Statewide infant SN2 full time base rate is 50.40. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 0 - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 ar_sra_care_type: SN2 households: household: @@ -193,12 +193,12 @@ - name: Case 12, Statewide infant SN3 full time base rate is 50.40. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 0 - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 ar_sra_care_type: SN3 households: household: @@ -210,12 +210,12 @@ - name: Case 13, Statewide preschool Night/Weekend full time base rate is 36.30. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 4 - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 ar_sra_care_type: NIGHT_WEEKEND households: household: @@ -227,12 +227,12 @@ - name: Case 14, Statewide infant Night/Weekend part time mirrors REGULAR PT (18.00 — modeling fallback). period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 0 - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 ar_sra_care_type: NIGHT_WEEKEND households: household: @@ -245,12 +245,12 @@ - name: Case 15, Benton/Washington infant SN2 full time base rate is 53.20. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 0 - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 ar_sra_care_type: SN2 households: household: @@ -262,12 +262,12 @@ - name: Case 16, Benton/Washington toddler Night/Weekend full time base rate is 40.70. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: age: 2 - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 ar_sra_care_type: NIGHT_WEEKEND households: household: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml index 7be9184e103..d6410e0ca10 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml @@ -2,7 +2,7 @@ - name: Case 1, Toddler Statewide FT at LE_40 SMI has zero copay (share 1.00). period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -14,7 +14,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -33,7 +33,7 @@ - name: Case 2, School-Aged Statewide FT at LE_40 SMI has positive copay (20 percent of base). period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -45,7 +45,7 @@ age: 7 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -64,7 +64,7 @@ - name: Case 3, Preschool Statewide FT at GT_60 SMI has copay 40 percent of base. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -76,7 +76,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml index 895c942c4fa..45f5039fa9a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml @@ -5,7 +5,7 @@ - name: Case 1, Toddler Statewide FT at LE_40 SMI pays full base rate (no-copay). period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -17,7 +17,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -36,7 +36,7 @@ - name: Case 2, School-Aged Statewide FT at LE_40 SMI has positive copay (share 0.80). period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -48,7 +48,7 @@ age: 7 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -67,7 +67,7 @@ - name: Case 3, Infant Benton/Washington FT at GT_60 SMI gets reduced share. period: 2026-01 - absolute_error_margin: 0.1 + absolute_error_margin: 0.01 input: people: person1: @@ -79,7 +79,7 @@ age: 0 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml index ace5f8e3f5c..50f8c058d41 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_income_tier.yaml @@ -8,7 +8,6 @@ - name: Case 1, family at 30 percent SMI is in the LE_40 tier. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -35,7 +34,6 @@ - name: Case 2, family at 50 percent SMI is in the GT_40_LE_60 tier. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -62,7 +60,6 @@ - name: Case 3, family at 75 percent SMI is in the GT_60 tier. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -89,7 +86,6 @@ - name: Case 4, family just under 40 percent SMI is in the LE_40 tier. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -116,7 +112,6 @@ - name: Case 5, family just above 40 percent SMI is in the GT_40_LE_60 tier. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -143,7 +138,6 @@ - name: Case 6, family just under 60 percent SMI is in the GT_40_LE_60 tier. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -170,7 +164,6 @@ - name: Case 7, family just above 60 percent SMI is in the GT_60 tier. period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -197,7 +190,6 @@ - name: Case 8, family at exactly 40 percent SMI is in the LE_40 tier (boundary is inclusive). period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: @@ -224,7 +216,6 @@ - name: Case 9, family at exactly 60 percent SMI is in the GT_40_LE_60 tier (boundary is inclusive). period: 2026-01 - absolute_error_margin: 0.1 input: people: person1: diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.yaml index 2fb148ddfcb..a6dadc30dff 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.yaml @@ -10,8 +10,9 @@ # School-Aged FT LE_40 = 0.80 (always copay) # School-Aged FT GT_60 = 0.30 # -# Arkansas SMI (2025-10-01, FFY 2026, 4-person): $90,280/year -# 2-person SPM: SMI = 90,280 * 0.68 = $61,390.40 annual +# Arkansas SMI (FFY 2026, uprated to 2026-01-01, 4-person): $95,201.95/year +# 2-person SPM: SMI = 95,201.95 * 0.68 = $64,737.33 annual +# Tier percentages quoted in test names are computed against the uprated SMI. - name: Case 1, toddler at 30 percent SMI gets state share 1.00 (no-copay floor). period: 2026-01 @@ -27,7 +28,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -55,7 +56,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -84,7 +85,7 @@ age: 7 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -113,7 +114,7 @@ age: 7 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -141,7 +142,7 @@ age: 0 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -170,7 +171,7 @@ age: 0 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -199,7 +200,7 @@ age: 0 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -228,7 +229,7 @@ is_tax_unit_dependent: true immigration_status: CITIZEN # Below 30 hr FT threshold - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 tax_units: tax_unit: members: [person1, person2] @@ -256,7 +257,7 @@ age: 0 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 tax_units: tax_unit: members: [person1, person2] @@ -284,7 +285,7 @@ age: 0 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 tax_units: tax_unit: members: [person1, person2] @@ -312,7 +313,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 tax_units: tax_unit: members: [person1, person2] @@ -340,7 +341,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 tax_units: tax_unit: members: [person1, person2] @@ -368,7 +369,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 tax_units: tax_unit: members: [person1, person2] @@ -396,7 +397,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 tax_units: tax_unit: members: [person1, person2] @@ -424,7 +425,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 tax_units: tax_unit: members: [person1, person2] @@ -452,7 +453,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 tax_units: tax_unit: members: [person1, person2] @@ -480,7 +481,7 @@ age: 7 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 tax_units: tax_unit: members: [person1, person2] @@ -508,7 +509,7 @@ age: 7 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 tax_units: tax_unit: members: [person1, person2] @@ -536,7 +537,7 @@ age: 7 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 20 + childcare_hours_per_day: 4 tax_units: tax_unit: members: [person1, person2] @@ -564,7 +565,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -592,7 +593,7 @@ age: 2 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -620,7 +621,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -648,7 +649,7 @@ age: 4 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] @@ -676,7 +677,7 @@ age: 7 is_tax_unit_dependent: true immigration_status: CITIZEN - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 tax_units: tax_unit: members: [person1, person2] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_time_category.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_time_category.yaml index 3b7525eac70..3d9a1d8e0b6 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_time_category.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_time_category.yaml @@ -1,13 +1,12 @@ -# Time category: >=35 hr/wk -> FULL_TIME, otherwise PART_TIME. -# Threshold parameter: gov.states.ar.ade.oec.sra.rates.full_time_hours_threshold = 35 -# (approximates FSU §5.4.6 "7+ hours per day" as 5 days * 7 = 35 hr/week.) +# Time category: childcare_hours_per_day >= 7 -> FULL_TIME, otherwise PART_TIME. +# Per FSU §5.4.6 "7+ hours per day" (gov.states.ar.ade.oec.sra.rates.full_time_hours_threshold = 7). -- name: Case 1, 35 hours per week is FULL_TIME at the threshold. +- name: Case 1, 7 hours per day is FULL_TIME at the threshold. period: 2026-01 input: people: person1: - childcare_hours_per_week: 35 + childcare_hours_per_day: 7 households: household: members: [person1] @@ -15,12 +14,12 @@ output: ar_sra_time_category: FULL_TIME -- name: Case 2, 40 hours per week is FULL_TIME. +- name: Case 2, 8 hours per day is FULL_TIME. period: 2026-01 input: people: person1: - childcare_hours_per_week: 40 + childcare_hours_per_day: 8 households: household: members: [person1] @@ -28,12 +27,12 @@ output: ar_sra_time_category: FULL_TIME -- name: Case 3, 25 hours per week is PART_TIME. +- name: Case 3, 5 hours per day is PART_TIME. period: 2026-01 input: people: person1: - childcare_hours_per_week: 25 + childcare_hours_per_day: 5 households: household: members: [person1] @@ -41,12 +40,12 @@ output: ar_sra_time_category: PART_TIME -- name: Case 4, 34 hours per week is PART_TIME just below the threshold. +- name: Case 4, 6 hours per day is PART_TIME just below the threshold. period: 2026-01 input: people: person1: - childcare_hours_per_week: 34 + childcare_hours_per_day: 6 households: household: members: [person1] @@ -54,15 +53,28 @@ output: ar_sra_time_category: PART_TIME -- name: Case 5, 0 hours per week is PART_TIME. +- name: Case 5, 0 hours per day is PART_TIME. period: 2026-01 input: people: person1: - childcare_hours_per_week: 0 + childcare_hours_per_day: 0 households: household: members: [person1] state_code: AR output: ar_sra_time_category: PART_TIME + +- name: Case 6, 8 hours per day for 4 days per week (32 hours per week total) is FULL_TIME under the per-day rule. + period: 2026-01 + input: + people: + person1: + childcare_hours_per_day: 8 + households: + household: + members: [person1] + state_code: AR + output: + ar_sra_time_category: FULL_TIME diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py index b969513480b..7f46d455994 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py @@ -27,16 +27,14 @@ def formula(spm_unit, period, parameters): monthly_max_state_payment, ) total_uncapped_subsidy = spm_unit.sum(uncapped_subsidy * is_eligible_child) - # CCDF State Plan §3.1.1 caps the family copay at 4% of gross income - # per family, regardless of the number of children. When rate-sheet - # copays sum above the cap, the state covers the gap. + # CCDF State Plan §3.1.1: per-family copay capped at 4% of gross income. p = parameters(period).gov.states.ar.ade.oec.sra.rates total_uncapped_copay = spm_unit.sum(monthly_copay * is_eligible_child) - # Clamp at 0 so a negative countable income (e.g. self-employment - # loss) doesn't inflate cap_savings. + # Clamp at 0 so negative countable income doesn't inflate cap_savings. countable_income = max_(spm_unit("ar_sra_countable_income", period), 0) copay_ceiling = p.max_copay_share_of_gross_income * countable_income cap_savings = max_(total_uncapped_copay - copay_ceiling, 0) - # State subsidy never exceeds the family's actual childcare cost. + # Clamp at actual expense: when a child has $0 expense, the rate-sheet + # copay still appears in total_uncapped_copay and could inflate cap_savings. total_expense = spm_unit.sum(monthly_expense * is_eligible_child) return min_(total_uncapped_subsidy + cap_savings, total_expense) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py index 5a3559f29cc..522b868304a 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py @@ -20,6 +20,7 @@ class ar_sra_income_tier(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra monthly_income = spm_unit("ar_sra_countable_income", period) + # hhs_smi is YEAR-defined; bare period auto-divides annual → monthly. monthly_smi = spm_unit("hhs_smi", period) ratio = where(monthly_smi > 0, monthly_income / monthly_smi, np.inf) return select( diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_time_category.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_time_category.py index f643f6b35e1..0884784e3c4 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_time_category.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_time_category.py @@ -21,7 +21,7 @@ class ar_sra_time_category(Variable): def formula(person, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.rates - hours = person("childcare_hours_per_week", period.this_year) + hours = person("childcare_hours_per_day", period.this_year) return where( hours >= p.full_time_hours_threshold, ArSraTimeCategory.FULL_TIME, diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_zone.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_zone.py index a1b1a61cdca..6f520a5e42f 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_zone.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_zone.py @@ -20,13 +20,12 @@ class ar_sra_zone(Variable): ) def formula(household, period, parameters): - # Belt-and-suspenders: defined_for filters output but doesn't gate - # the lookup, so guard county_str against non-AR rows. + # Guard against non-AR rows: defined_for filters output but not the lookup. state = household("state_code_str", period.this_year) county = household("county_str", period.this_year) - in_benton_washington = (state == "AR") & ( - (county == "BENTON_COUNTY_AR") | (county == "WASHINGTON_COUNTY_AR") - ) + p = parameters(period).gov.states.ar.ade.oec.sra.rates + in_bw_county = np.isin(county, p.benton_washington_counties) + in_benton_washington = (state == "AR") & in_bw_county return where( in_benton_washington, ArSraZone.BENTON_WASHINGTON, diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py index def30b47c31..a8108f6e5df 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py @@ -22,10 +22,8 @@ def formula(spm_unit, period, parameters): hours = person("weekly_hours_worked", period.this_year) adult_hours = where(is_adult, hours, 0) max_adult_hours = spm_unit.max(adult_hours) - # FSU §4.1.5.1-2 / R&R Nov 2025: both Year-1 and Year-2 activity can - # be satisfied by work hours OR full-time school/training. We don't - # track AR TEA's net-income trigger at the moment, so the Year-1 alt - # path "earnings make family TEA-income-ineligible" is unmodeled. + # Year-1 alt path "earnings make family TEA-income-ineligible" (FSU §4.1.5.1) + # is unmodeled; we don't track AR TEA's net-income trigger at the moment. adult_is_student = is_adult & person( "is_full_time_college_student", period.this_year ) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py index cb25987868e..9c81ba6b444 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_income_eligible.py @@ -12,5 +12,6 @@ class is_ar_sra_income_eligible(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.eligibility monthly_income = spm_unit("ar_sra_countable_income", period) + # hhs_smi is YEAR-defined; bare period auto-divides annual → monthly. monthly_smi_limit = spm_unit("hhs_smi", period) * p.income_smi_rate return monthly_income <= monthly_smi_limit diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py index ebd49f9c403..6288dd186cc 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_li_activity_eligible.py @@ -14,14 +14,10 @@ def formula(spm_unit, period, parameters): person = spm_unit.members is_adult = person("age", period.this_year) >= p.adult_age_threshold hours = person("weekly_hours_worked", period.this_year) - # FSU §4.1.5.4: school converts to work-equivalent via 2.5 hr per - # semester credit. Full-time college (12+ credits) implies 30+ hr - # equivalent, satisfying LI's 30 hr/wk threshold. We don't extend - # the proxy to K-12 students because the conversion rule applies to - # post-secondary credit hours. + # FSU §4.1.5.4 converts full-time college (12+ credits @ 2.5 hr/credit ≥ 30 hr) + # into work-equivalent; K-12 students excluded (rule applies to post-secondary). is_student = person("is_full_time_college_student", period.this_year) meets_activity = (hours >= p.activity_hours_li) | is_student - # All adults must meet the activity test. has_adult = spm_unit.sum(is_adult) > 0 all_adults_qualify = spm_unit.sum(is_adult & ~meets_activity) == 0 ccdf_fallback = spm_unit("meets_ccdf_activity_test", period.this_year) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.py index 514852870d4..dbeb694537a 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_countable_income.py @@ -15,9 +15,7 @@ class ar_sra_countable_income(Variable): def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra - # FSU Manual §4.3.2 excludes SSI and Social Security of children - # from countable income; mask per-person contributions by adult - # status before aggregating to the SPM unit. + # FSU §4.3.2 excludes children's SSI and Social Security; mask by adult status. person = spm_unit.members is_adult = person("age", period.this_year) >= p.eligibility.adult_age_threshold per_person_income = sum(person(source, period) for source in p.income.sources) From 67bf3ef809e5b4790a2f1c6ae57f7e2982469936 Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 18 May 2026 01:42:29 -0400 Subject: [PATCH 12/17] Review-fix round 8: gross-income cap, disability extension, ESS Y1 alt path, Night/Weekend coercion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Substantive behavior changes (4 review-finding items resolved): 1. **4% cap base switched to gross income** (CCDF State Plan §3.1.1 literal): - New `ar_sra_gross_income` mirrors `ar_sra_countable_income` but does NOT exclude children's SSI / Social Security (the FSU §4.3.2 exclusion is for the countable-income tier, not the per-family copay ceiling). - `ar_sra.py` uses `ar_sra_gross_income` as the 4% cap denominator. 2. **Age-13+ disability extension** (CCDF State Plan §2.2.1): - New `child_age_limit_disabled = 18` parameter. - `is_ar_sra_age_eligible.py` uses the higher limit when `is_disabled`. - 3 new test cases (disabled child 15 eligible, non-disabled 15 not, age 18 boundary). 3. **ESS Year-1 TEA-income-ineligibility alt path** (FSU §4.1.5.1): - `is_ar_sra_ess_eligible.py` Year-1 activity OR-clauses `~ar_tea_income_eligible`. - Year-2 unchanged (FSU §4.1.5.2 does not have the alt path). - 3 new test cases (Y1 alt path triggers, Y1 work-hours fallback fails when TEA-income-eligible, Y2 does not include alt path). 4. **Night/Weekend rates coerced to FT-only** (OEC Oct 7 2025 Provider Call): - Per OEC, Night/Weekend is a separate 5th service category priced at 110% of FT typical rates — not a FT/PT subdimension. - `ar_sra_daily_base_rate.py` overrides time-category lookup to FT when care_type is NIGHT_WEEKEND. - Test Case 14 (PT NIGHT_WEEKEND infant) expected value updated from $18 (old PT REGULAR fallback) to $39.60 (Night/Weekend FT rate). Source-research updates: - `age_category_months.yaml` reference updated from peer-state convention flag to AR Minimum Licensing Requirements (DCCECE 2020) for Infant/Toddler boundaries plus Ark. Code 6-18-207 for kindergarten/School-Age boundary. - `is_ar_sra_age_eligible.py` reference expanded to include CCDF State Plan §2.2.1 (disability extension authority). - `ar_sra_daily_base_rate.py` reference expanded to include OEC Provider Call 10.7.25 (Night/Weekend category definition). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../eligibility/child_age_limit_disabled.yaml | 13 ++++ .../oec/sra/rates/age_category_months.yaml | 14 ++-- .../sra/eligibility/ar_sra_age_eligible.yaml | 51 +++++++++++++ .../sra/eligibility/ar_sra_ess_eligible.yaml | 75 +++++++++++++++++++ .../oec/sra/rates/ar_sra_daily_base_rate.yaml | 8 +- .../gov/states/ar/ade/oec/sra/ar_sra.py | 6 +- .../sra/eligibility/is_ar_sra_age_eligible.py | 10 ++- .../sra/eligibility/is_ar_sra_ess_eligible.py | 10 ++- .../ade/oec/sra/income/ar_sra_gross_income.py | 22 ++++++ .../oec/sra/rates/ar_sra_daily_base_rate.py | 13 +++- 10 files changed, 203 insertions(+), 19 deletions(-) create mode 100644 policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit_disabled.yaml create mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.py diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit_disabled.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit_disabled.yaml new file mode 100644 index 00000000000..29e047fbe3d --- /dev/null +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit_disabled.yaml @@ -0,0 +1,13 @@ +description: Arkansas extends School Readiness Assistance eligibility to children with verified disabilities under this age. +values: + 2025-10-01: 18 + +metadata: + unit: year + period: year + label: Arkansas SRA child age limit (disabled extension) + reference: + - title: AR ADC 016.22.8 Section 3.1.4 Eligible Child / Date of Birth + href: https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11 + - title: Arkansas CCDF Plan 2025-2027, Section 2.2.1 Eligibility Definitions + href: https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=18 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml index b191909d336..07dc1eb52bc 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml @@ -1,9 +1,9 @@ description: Arkansas sets these age thresholds in months for age categories under the School Readiness Assistance program. -# The rate sheets group rates by Infant / Toddler / Preschool / School-Aged -# but do NOT specify month boundaries within those labels. The encoded -# month boundaries (Infant <=17 mo, Toddler 18-35 mo, Preschool 36-71 mo, -# School-Aged 72+ mo) are peer-state conventions, not Arkansas sources, -# and are flagged for future verification with OEC. +# Boundaries follow the 2020 AR Min Licensing Requirements for Child Care Centers +# (Infant Center: birth to 18 months; Toddler Center: 18 to 36 months; School-Age +# Care: kindergarten and above per Ark. Code 6-18-207, age 5 by Aug 1 of the +# school year). Preschool fills the gap (36-71 months); the school-aged 72-month +# boundary uses typical kindergarten entry rather than the strict 60-month minimum. brackets: - threshold: @@ -32,3 +32,7 @@ metadata: reference: - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Full Time (Nov 1, 2025) - age category labels href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf + - title: AR Minimum Licensing Requirements for Child Care Centers (DCCECE, 2020) - Infant Center (item 13), Toddler Center (item 21), School Age Care (item 22) + href: https://humanservices.arkansas.gov/wp-content/uploads/2020-Child-Care-centers.pdf + - title: Ark. Code Sec. 6-18-207 (kindergarten enrollment age 5 by August 1) + href: https://law.justia.com/codes/arkansas/title-6/subtitle-2/chapter-18/subchapter-2/section-6-18-207/ diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml index b60a9ea323f..69916bcf374 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml @@ -61,3 +61,54 @@ state_code: AR output: is_ar_sra_age_eligible: [false, true] + +- name: Case 5, disabled child age 15 is age-eligible under the disability extension (under 18). + period: 2026-01 + input: + people: + person1: + age: 40 + person2: + age: 15 + is_tax_unit_dependent: true + is_disabled: true + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_age_eligible: [false, true] + +- name: Case 6, non-disabled child age 15 is not age-eligible (over 13). + period: 2026-01 + input: + people: + person1: + age: 40 + person2: + age: 15 + is_tax_unit_dependent: true + is_disabled: false + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_age_eligible: [false, false] + +- name: Case 7, disabled child age 18 is at the disability extension boundary and not age-eligible (strict less than). + period: 2026-01 + input: + people: + person1: + age: 45 + person2: + age: 18 + is_tax_unit_dependent: true + is_disabled: true + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_age_eligible: [false, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml index 7e2cb92c41c..9fee21585fa 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml @@ -374,3 +374,78 @@ state_code: AR output: is_ar_sra_ess_eligible: false + +- name: Case 17, ESS Year-1 alt path (FSU 4.1.5.1) - earnings exceed TEA income limit, work hours below the 20 hr threshold. + period: 2026-01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 15 + # AR TEA income limit for 2-person SPM is well under $30k/year; + # $30k earnings make the family TEA-income-ineligible. + employment_income: 30_000 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 6 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: true + +- name: Case 18, ESS Year-1 work-hours fallback - 15 hr/wk plus TEA-income-eligible (low income) fails the activity test. + period: 2026-01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 15 + # Zero income keeps the family TEA-income-eligible. + employment_income: 0 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 6 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: false + +- name: Case 19, ESS Year-2 alt path does NOT include TEA-income-ineligibility - Year-2 requires 25 hr/wk or full-time student. + period: 2026-01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 15 + employment_income: 30_000 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 18 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + is_ar_sra_ess_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml index 6d1a397cddc..363f2b06b66 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml @@ -225,7 +225,7 @@ output: ar_sra_daily_base_rate: 36.30 -- name: Case 14, Statewide infant Night/Weekend part time mirrors REGULAR PT (18.00 — modeling fallback). +- name: Case 14, Statewide infant Night/Weekend with part-time hours uses the Night/Weekend FT rate (39.60) per OEC 5-category structure. period: 2026-01 absolute_error_margin: 0.01 input: @@ -240,8 +240,10 @@ county_str: PULASKI_COUNTY_AR state_code: AR output: - # PT NIGHT_WEEKEND has no source rate; fallback to PT REGULAR per base_rate.yaml. - ar_sra_daily_base_rate: 18.00 + # Per OEC Oct 7 2025 Provider Call: Night/Weekend is its own service category + # (110% of FT typical), not a FT/PT subdimension. PT hours still use the + # Night/Weekend FT rate. + ar_sra_daily_base_rate: 39.60 - name: Case 15, Benton/Washington infant SN2 full time base rate is 53.20. period: 2026-01 diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py index 7f46d455994..759be0c49b9 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py @@ -30,9 +30,9 @@ def formula(spm_unit, period, parameters): # CCDF State Plan §3.1.1: per-family copay capped at 4% of gross income. p = parameters(period).gov.states.ar.ade.oec.sra.rates total_uncapped_copay = spm_unit.sum(monthly_copay * is_eligible_child) - # Clamp at 0 so negative countable income doesn't inflate cap_savings. - countable_income = max_(spm_unit("ar_sra_countable_income", period), 0) - copay_ceiling = p.max_copay_share_of_gross_income * countable_income + # Clamp at 0 so a negative self-employment loss doesn't inflate cap_savings. + gross_income = max_(spm_unit("ar_sra_gross_income", period), 0) + copay_ceiling = p.max_copay_share_of_gross_income * gross_income cap_savings = max_(total_uncapped_copay - copay_ceiling, 0) # Clamp at actual expense: when a child has $0 expense, the rate-sheet # copay still appears in total_uncapped_copay and could inflate cap_savings. diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py index e3e8d47e549..312c22a9a98 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py @@ -7,9 +7,15 @@ class is_ar_sra_age_eligible(Variable): label = "Age-eligible for Arkansas SRA" definition_period = MONTH defined_for = StateCode.AR - reference = "https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11" + reference = ( + "https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11", + "https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=18", + ) def formula(person, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.eligibility age = person("age", period.this_year) - return age < p.child_age_limit + is_disabled = person("is_disabled", period.this_year) + # CCDF State Plan §2.2.1: disabled children eligible up to age 18. + age_limit = where(is_disabled, p.child_age_limit_disabled, p.child_age_limit) + return age < age_limit diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py index a8108f6e5df..7dc74d7c7c1 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py @@ -22,15 +22,17 @@ def formula(spm_unit, period, parameters): hours = person("weekly_hours_worked", period.this_year) adult_hours = where(is_adult, hours, 0) max_adult_hours = spm_unit.max(adult_hours) - # Year-1 alt path "earnings make family TEA-income-ineligible" (FSU §4.1.5.1) - # is unmodeled; we don't track AR TEA's net-income trigger at the moment. adult_is_student = is_adult & person( "is_full_time_college_student", period.this_year ) any_adult_student = spm_unit.sum(adult_is_student) > 0 + # FSU §4.1.5.1 Year-1 alt path: earnings make family TEA-income-ineligible. + tea_income_ineligible = ~spm_unit("ar_tea_income_eligible", period) year_1_active = ( - max_adult_hours >= p.activity_hours_ess_year_1 - ) | any_adult_student + (max_adult_hours >= p.activity_hours_ess_year_1) + | any_adult_student + | tea_income_ineligible + ) year_2_active = ( max_adult_hours >= p.activity_hours_ess_year_2 ) | any_adult_student diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.py new file mode 100644 index 00000000000..367b7dff4d1 --- /dev/null +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.py @@ -0,0 +1,22 @@ +from policyengine_us.model_api import * + + +class ar_sra_gross_income(Variable): + value_type = float + entity = SPMUnit + label = "Arkansas SRA gross income for the per-family copay ceiling" + unit = USD + definition_period = MONTH + defined_for = StateCode.AR + reference = ( + "https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=39", + "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=19", + ) + + def formula(spm_unit, period, parameters): + p = parameters(period).gov.states.ar.ade.oec.sra.income + # CCDF State Plan §3.1.1 caps the family copay at 4% of gross income, + # which includes all members (children's SSI and SS included). + person = spm_unit.members + per_person_income = sum(person(source, period) for source in p.sources) + return spm_unit.sum(per_person_income) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py index 99d43dc1d25..36c84b11bd9 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py @@ -8,7 +8,10 @@ class ar_sra_daily_base_rate(Variable): label = "Arkansas SRA daily base provider rate" definition_period = MONTH defined_for = "is_ar_sra_child_eligible" - reference = "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/October_2025_Provider_Call_10.7.25_OEC.pdf#page=5", + ) def formula(person, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.rates @@ -16,4 +19,10 @@ def formula(person, period, parameters): age_category = person("ar_sra_age_category", period) care_type = person("ar_sra_care_type", period) time_category = person("ar_sra_time_category", period) - return p.base_rate[zone][age_category][care_type][time_category] + rate = p.base_rate[zone][age_category][care_type][time_category] + # Per OEC Oct 7 2025 Provider Call: Night/Weekend is a separate + # 110%-of-FT category, not a FT/PT subdimension. Override with FT rate. + time_categories = time_category.possible_values + ft_rate = p.base_rate[zone][age_category][care_type][time_categories.FULL_TIME] + is_night_weekend = care_type == care_type.possible_values.NIGHT_WEEKEND + return where(is_night_weekend, ft_rate, rate) From 39e479ed6b28f0df06a1ce2d99c154f0984a3de6 Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 18 May 2026 16:48:13 -0400 Subject: [PATCH 13/17] Round 9 source verification: doc improvements only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves the 3 remaining "Verification TODO" items from the PR description. No formula or parameter-value changes — research-only round. - ar_sra_care_type.py: add FSU Procedural Manual §5.6.1 page-32 reference and a 4-line comment documenting SN1/SN2/SN3 criteria. SN level is set by a licensed medical practitioner's documentation per FSU §5.6.1; not derivable from any current PolicyEngine input. Variable remains a bare Enum input. - activity_hours_li.yaml: 2-line comment clarifying the 30 hr/wk applies to LI track only (ESS year-1 and year-2 thresholds live in separate parameter files). Verified separately (no change needed): - state_share_by_tier.yaml SCHOOL_AGED + LE_40 already gives 0.8/0.7 state share (not 1.0), matching OEC Oct 1 2025 deck's "$4.65 copay on $15.50 rate". No school-aged $0-copay bug. - base_rate.yaml already reflects Oct 1 2025 SN simplification: SN1 = REGULAR; SN2 = SN3 = REGULAR x 1.4 across all zones/ages. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../ar/ade/oec/sra/eligibility/activity_hours_li.yaml | 2 ++ .../gov/states/ar/ade/oec/sra/ar_sra_care_type.py | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_li.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_li.yaml index fe996f4ec76..9779ccf5f13 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_li.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/activity_hours_li.yaml @@ -1,4 +1,6 @@ description: Arkansas sets this minimum weekly activity hours threshold for each adult in a Low-Income household under the School Readiness Assistance program. +# Applies to the Low-Income (LI) track only. ESS thresholds live in +# activity_hours_ess_year_1.yaml and activity_hours_ess_year_2.yaml. values: 2025-10-01: 30 diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_care_type.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_care_type.py index f69801fcac5..fcc469b20f5 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_care_type.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_care_type.py @@ -9,6 +9,10 @@ class ArSraCareType(Enum): SN3 = "Special Needs Level 3" +# Per FSU Procedural Manual §5.6.1: SN1 = no extra staff, SN2 = temporary extra +# staff, SN3 = full-time 1:1 staff, set by a licensed medical practitioner. We +# don't track that operational determination at the moment, so this is a bare +# input — users modeling a known case set it directly. class ar_sra_care_type(Variable): value_type = Enum entity = Person @@ -17,4 +21,7 @@ class ar_sra_care_type(Variable): definition_period = MONTH defined_for = StateCode.AR label = "Arkansas SRA care type" - reference = "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=32", + ) From ac9d6197e0be0c72578a0f4412c1d20585bccd2a Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 18 May 2026 17:45:11 -0400 Subject: [PATCH 14/17] Review-fix round 10: address /review-program critical findings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - child_age_limit_disabled: 18 -> 19 per FSU §5.6.1 ("under nineteen") and CCDF State Plan §2.2.1 ("below age 19"). - Night/Weekend rate: populate PT N/W cells as PT REGULAR * 1.10 per Provider Call slide 4 ("+10% on typical rates"); remove FT-coercion override in ar_sra_daily_base_rate formula that doubled the PT rate. - income_smi_rate reference: #page=21 -> #page=22 (§2.2.4 header location). - Promote dese.ade.arkansas.gov CCDF State Plan as primary source for child_age_limit{,_disabled} (drop publichealthlawcenter.org aggregator). - Add ar_sra unit test (5 cases): baseline, total_expense clamp, zero-expense clamp, 4% gross-income cap binding, negative-income clamp. - Add ar_sra_gross_income unit test (4 cases): adult-only, child SSI inclusion (vs countable exclusion), child SSDI inclusion, defined_for guard. - Repair pre-existing ESS Year-1 alt-path test: use employment_income_before_lsr (the variable tanf_gross_earned_income actually reads), not employment_income, so TEA-income-ineligibility is correctly triggered. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../oec/sra/eligibility/child_age_limit.yaml | 4 +- .../eligibility/child_age_limit_disabled.yaml | 6 +- .../oec/sra/eligibility/income_smi_rate.yaml | 2 +- .../ar/ade/oec/sra/rates/base_rate.yaml | 22 +-- .../gov/states/ar/ade/oec/sra/ar_sra.yaml | 181 ++++++++++++++++++ .../sra/eligibility/ar_sra_age_eligible.yaml | 23 ++- .../sra/eligibility/ar_sra_ess_eligible.yaml | 7 +- .../oec/sra/income/ar_sra_gross_income.yaml | 88 +++++++++ .../oec/sra/rates/ar_sra_daily_base_rate.yaml | 10 +- .../sra/eligibility/is_ar_sra_age_eligible.py | 3 +- .../oec/sra/rates/ar_sra_daily_base_rate.py | 8 +- 11 files changed, 318 insertions(+), 36 deletions(-) create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/ar_sra.yaml create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.yaml diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit.yaml index 6952e208895..ff6b13fc4a7 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit.yaml @@ -7,5 +7,5 @@ metadata: period: year label: Arkansas SRA child age limit reference: - - title: AR ADC 016.22.8 Section 3.1.4 Eligible Child / Date of Birth - href: https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11 + - title: Arkansas CCDF Plan 2025-2027, Section 2.2.1 Eligibility Definitions + href: https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=18 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit_disabled.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit_disabled.yaml index 29e047fbe3d..69b57d06ba1 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit_disabled.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit_disabled.yaml @@ -1,13 +1,13 @@ description: Arkansas extends School Readiness Assistance eligibility to children with verified disabilities under this age. values: - 2025-10-01: 18 + 2025-10-01: 19 metadata: unit: year period: year label: Arkansas SRA child age limit (disabled extension) reference: - - title: AR ADC 016.22.8 Section 3.1.4 Eligible Child / Date of Birth - href: https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11 - title: Arkansas CCDF Plan 2025-2027, Section 2.2.1 Eligibility Definitions href: https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=18 + - title: Arkansas FSU Procedural Manual, Section 5.6.1 Special Needs Child + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=32 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml index 3366180048e..a3e87db921a 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/income_smi_rate.yaml @@ -8,4 +8,4 @@ metadata: label: Arkansas SRA income limit SMI rate reference: - title: Arkansas CCDF Plan 2025-2027, Section 2.2.4 - href: https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=21 + href: https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=22 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml index c74dadc9a75..5204095f984 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml @@ -1,7 +1,7 @@ description: Arkansas provides these daily base reimbursement rates under the School Readiness Assistance program. -# Source rate sheets have no Part-Time Night/Weekend row. PT NIGHT_WEEKEND -# cells below mirror PT REGULAR as a fallback so the (zone × age × care_type -# × time) lookup is complete; this is a modeling choice, not a source value. +# Source rate sheets have no Part-Time Night/Weekend row. Per the October 7 2025 +# Provider Call ("Weekend and night time rates are set at a standard 10% increase +# of typical rates"), PT NIGHT_WEEKEND cells below are derived as PT REGULAR × 1.10. metadata: period: day unit: currency-USD @@ -32,7 +32,7 @@ BENTON_WASHINGTON: FULL_TIME: 2025-11-01: 41.8 PART_TIME: - 2025-11-01: 19 + 2025-11-01: 20.9 SN1: FULL_TIME: 2025-11-01: 38 @@ -58,7 +58,7 @@ BENTON_WASHINGTON: FULL_TIME: 2025-11-01: 40.7 PART_TIME: - 2025-11-01: 18.5 + 2025-11-01: 20.35 SN1: FULL_TIME: 2025-11-01: 37 @@ -84,7 +84,7 @@ BENTON_WASHINGTON: FULL_TIME: 2025-11-01: 36.3 PART_TIME: - 2025-11-01: 16.5 + 2025-11-01: 18.15 SN1: FULL_TIME: 2025-11-01: 33 @@ -110,7 +110,7 @@ BENTON_WASHINGTON: FULL_TIME: 2025-11-01: 30.8 PART_TIME: - 2025-11-01: 14 + 2025-11-01: 15.4 SN1: FULL_TIME: 2025-11-01: 28 @@ -138,7 +138,7 @@ STATEWIDE: FULL_TIME: 2025-11-01: 39.6 PART_TIME: - 2025-11-01: 18 + 2025-11-01: 19.8 SN1: FULL_TIME: 2025-11-01: 36 @@ -164,7 +164,7 @@ STATEWIDE: FULL_TIME: 2025-11-01: 38.5 PART_TIME: - 2025-11-01: 17.5 + 2025-11-01: 19.25 SN1: FULL_TIME: 2025-11-01: 35 @@ -190,7 +190,7 @@ STATEWIDE: FULL_TIME: 2025-11-01: 36.3 PART_TIME: - 2025-11-01: 16.5 + 2025-11-01: 18.15 SN1: FULL_TIME: 2025-11-01: 33 @@ -216,7 +216,7 @@ STATEWIDE: FULL_TIME: 2025-11-01: 30.8 PART_TIME: - 2025-11-01: 14 + 2025-11-01: 15.4 SN1: FULL_TIME: 2025-11-01: 28 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/ar_sra.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/ar_sra.yaml new file mode 100644 index 00000000000..84d61fd6bc5 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/ar_sra.yaml @@ -0,0 +1,181 @@ +# ar_sra unit tests — exercise the top-level formula's clamps and 4% cap. +# +# Reference parameters (Nov 1, 2025 rate sheet): +# AR SMI (FFY 2026, uprated to 2026-01-01, 4-person): $95,201.95/year +# All cases use a single eligible toddler with 22 attending days/month. + +- name: Case 1, baseline LI eligible family at LE_40 SMI tier, no copay. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + employment_income: 18_000 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Toddler Statewide FT LE_40: state share 1.00, copay 0. + # daily_state_payment = 35; monthly = 35 * 22 = 770. + ar_sra: 770 + +- name: Case 2, total_expense clamp - state payment exceeds actual expenses. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + employment_income: 18_000 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_attending_days_per_month: 22 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + # State payment alone would be $770; cap at actual expense. + spm_unit_pre_subsidy_childcare_expenses: 6_000 + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Annual expense $6,000 -> monthly $500. Subsidy capped at $500. + ar_sra: 500 + +- name: Case 3, zero expense clamps subsidy to zero (even with positive state payment). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + employment_income: 18_000 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + ar_sra: 0 + +- name: Case 4, 4% cap binds - rate-sheet copay exceeds 4% of gross. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + # GT_40_LE_60 tier: rate-sheet copay = $7/day = $154/month. + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Monthly gross = 30,695 / 12 = $2,557.92 + # 4% cap = $102.32; rate-sheet copay $154 exceeds cap. + # cap_savings = $154 - $102.32 = $51.68 + # uncapped subsidy = daily_state_payment * 22 = $28 * 22 = $616 + # ar_sra = $616 + $51.68 = $667.68 + ar_sra: 667.68 + +- name: Case 5, negative gross income is clamped at zero before applying 4% cap. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + # Self-employment loss exceeds wages; gross_income would be negative. + self_employment_income: -20_000 + employment_income: 5_000 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # Net income < 0 -> LE_40 tier (state share 1.00, copay 0). + # No copay so 4% cap is moot; full state payment. + # ar_sra = $35 * 22 = $770. Without the max_(gross, 0) clamp, + # cap_savings could become negative and corrupt the subsidy. + ar_sra: 770 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml index 69916bcf374..5b27e05bfd7 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml @@ -62,7 +62,7 @@ output: is_ar_sra_age_eligible: [false, true] -- name: Case 5, disabled child age 15 is age-eligible under the disability extension (under 18). +- name: Case 5, disabled child age 15 is age-eligible under the disability extension (under 19). period: 2026-01 input: people: @@ -96,7 +96,7 @@ output: is_ar_sra_age_eligible: [false, false] -- name: Case 7, disabled child age 18 is at the disability extension boundary and not age-eligible (strict less than). +- name: Case 7, disabled child age 18 is age-eligible (disability extension covers under 19). period: 2026-01 input: people: @@ -110,5 +110,24 @@ household: members: [person1, person2] state_code: AR + output: + # FSU §5.6.1 / CCDF State Plan §2.2.1: disabled children eligible + # "under nineteen (19)". + is_ar_sra_age_eligible: [false, true] + +- name: Case 8, disabled child age 19 is at the disability extension boundary and not age-eligible (strict less than). + period: 2026-01 + input: + people: + person1: + age: 45 + person2: + age: 19 + is_tax_unit_dependent: true + is_disabled: true + households: + household: + members: [person1, person2] + state_code: AR output: is_ar_sra_age_eligible: [false, false] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml index 9fee21585fa..0ae613ae063 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml @@ -382,9 +382,10 @@ person1: age: 28 weekly_hours_worked: 15 - # AR TEA income limit for 2-person SPM is well under $30k/year; - # $30k earnings make the family TEA-income-ineligible. - employment_income: 30_000 + # AR TEA income limit is $513/month; $30k/yr ($2,500/mo) earnings + # make the family TEA-income-ineligible. tanf_gross_earned_income + # reads employment_income_before_lsr, so set that directly. + employment_income_before_lsr: 30_000 person2: age: 2 is_tax_unit_dependent: true diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.yaml new file mode 100644 index 00000000000..5d0d196bfd6 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.yaml @@ -0,0 +1,88 @@ +# ar_sra_gross_income sums income across ALL household members (children +# included), unlike ar_sra_countable_income which excludes child income. +# It feeds the 4% copay-cap denominator under CCDF State Plan §3.1.1. + +- name: Case 1, adult-only earnings flow through to gross income. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 24_000 + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: AR + output: + # 24,000 / 12 = 2,000 monthly + ar_sra_gross_income: 2_000 + +- name: Case 2, child SSI is INCLUDED in gross income (contrast with countable). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 24_000 + person2: + age: 5 + ssi: 11_604 # /year (federal SSI max) + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Gross: (24,000 + 11,604) / 12 = 2,967 + ar_sra_gross_income: 2_967 + # Countable excludes child SSI: 24,000 / 12 = 2,000 + ar_sra_countable_income: 2_000 + +- name: Case 3, child SSDI (social_security_disability) is INCLUDED in gross. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 32 + employment_income: 36_000 + person2: + age: 10 + social_security_disability: 9_000 + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + output: + # Gross: (36,000 + 9,000) / 12 = 3,750 + ar_sra_gross_income: 3_750 + # Countable excludes child SS-disability: 36,000 / 12 = 3,000 + ar_sra_countable_income: 3_000 + +- name: Case 4, non-AR household yields zero gross (defined_for guard). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 30 + employment_income: 24_000 + spm_units: + spm_unit: + members: [person1] + households: + household: + members: [person1] + state_code: TX + output: + ar_sra_gross_income: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml index 363f2b06b66..582b429c7f7 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml @@ -225,7 +225,7 @@ output: ar_sra_daily_base_rate: 36.30 -- name: Case 14, Statewide infant Night/Weekend with part-time hours uses the Night/Weekend FT rate (39.60) per OEC 5-category structure. +- name: Case 14, Statewide infant Night/Weekend with part-time hours uses the PT Night/Weekend rate (19.80 = PT REGULAR 18 x 1.10). period: 2026-01 absolute_error_margin: 0.01 input: @@ -240,10 +240,10 @@ county_str: PULASKI_COUNTY_AR state_code: AR output: - # Per OEC Oct 7 2025 Provider Call: Night/Weekend is its own service category - # (110% of FT typical), not a FT/PT subdimension. PT hours still use the - # Night/Weekend FT rate. - ar_sra_daily_base_rate: 39.60 + # Per OEC Oct 7 2025 Provider Call ("Weekend and night time rates are set + # at a standard 10% increase of typical rates"), PT Night/Weekend + # = PT REGULAR x 1.10 = 18 x 1.10 = 19.80. + ar_sra_daily_base_rate: 19.80 - name: Case 15, Benton/Washington infant SN2 full time base rate is 53.20. period: 2026-01 diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py index 312c22a9a98..762534901dc 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_age_eligible.py @@ -8,14 +8,13 @@ class is_ar_sra_age_eligible(Variable): definition_period = MONTH defined_for = StateCode.AR reference = ( - "https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11", "https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=18", + "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=32", ) def formula(person, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.eligibility age = person("age", period.this_year) is_disabled = person("is_disabled", period.this_year) - # CCDF State Plan §2.2.1: disabled children eligible up to age 18. age_limit = where(is_disabled, p.child_age_limit_disabled, p.child_age_limit) return age < age_limit diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py index 36c84b11bd9..47d2bffa501 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py @@ -19,10 +19,4 @@ def formula(person, period, parameters): age_category = person("ar_sra_age_category", period) care_type = person("ar_sra_care_type", period) time_category = person("ar_sra_time_category", period) - rate = p.base_rate[zone][age_category][care_type][time_category] - # Per OEC Oct 7 2025 Provider Call: Night/Weekend is a separate - # 110%-of-FT category, not a FT/PT subdimension. Override with FT rate. - time_categories = time_category.possible_values - ft_rate = p.base_rate[zone][age_category][care_type][time_categories.FULL_TIME] - is_night_weekend = care_type == care_type.possible_values.NIGHT_WEEKEND - return where(is_night_weekend, ft_rate, rate) + return p.base_rate[zone][age_category][care_type][time_category] From 8b2cc5aedddbbb26188445770c2b298315cba06e Mon Sep 17 00:00:00 2001 From: Ziming Date: Mon, 18 May 2026 21:09:17 -0400 Subject: [PATCH 15/17] fix --- changelog.d/ar-ccap.added.md | 2 +- .../eligibility/child_age_limit_disabled.yaml | 2 +- .../gov/states/ar/ade/oec/sra/in_effect.yaml | 2 +- .../oec/sra/rates/age_category_months.yaml | 2 +- .../ar/ade/oec/sra/rates/base_rate.yaml | 4 + .../max_copay_share_of_gross_income.yaml | 5 +- .../oec/sra/rates/no_copay_smi_threshold.yaml | 7 +- .../ade/oec/sra/ar_child_care_subsidies.yaml | 66 ++++++++ .../gov/states/ar/ade/oec/sra/ar_sra.yaml | 53 +++++- .../sra/eligibility/ar_sra_age_eligible.yaml | 19 +++ .../sra/eligibility/ar_sra_ess_eligible.yaml | 31 ++++ .../oec/sra/income/ar_sra_gross_income.yaml | 88 ---------- .../states/ar/ade/oec/sra/integration.yaml | 68 ++++++++ .../oec/sra/rates/ar_sra_daily_base_rate.yaml | 66 ++++++++ .../ade/oec/sra/rates/ar_sra_daily_copay.yaml | 157 ++++++++++++++++++ .../sra/rates/ar_sra_daily_state_payment.yaml | 155 +++++++++++++++++ .../ar/ade/oec/sra/rates/ar_sra_zone.yaml | 11 ++ .../ade/oec/sra/ar_months_since_tea_exit.py | 2 +- .../gov/states/ar/ade/oec/sra/ar_sra.py | 25 ++- .../ar/ade/oec/sra/ar_sra_age_category.py | 12 +- .../ar/ade/oec/sra/ar_sra_income_tier.py | 7 +- .../ar/ade/oec/sra/ar_was_tea_recipient.py | 2 +- .../sra/eligibility/is_ar_sra_ess_eligible.py | 11 +- .../ade/oec/sra/income/ar_sra_gross_income.py | 22 --- .../oec/sra/rates/ar_sra_daily_base_rate.py | 9 +- .../ade/oec/sra/rates/ar_sra_daily_copay.py | 13 +- .../sra/rates/ar_sra_daily_state_payment.py | 7 +- .../ade/oec/sra/rates/ar_sra_state_share.py | 7 +- 28 files changed, 714 insertions(+), 141 deletions(-) create mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/ar_child_care_subsidies.yaml delete mode 100644 policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.yaml delete mode 100644 policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.py diff --git a/changelog.d/ar-ccap.added.md b/changelog.d/ar-ccap.added.md index fc1f53f1bc8..3d5bcb1f69e 100644 --- a/changelog.d/ar-ccap.added.md +++ b/changelog.d/ar-ccap.added.md @@ -1 +1 @@ -Add Arkansas School Readiness Assistance (SRA) child care subsidy program. +Add Arkansas School Readiness Assistance (SRA) child care subsidy program. The 4% per-family copay ceiling is computed against countable (adult) income — children's SSI and Social Security are excluded per FSU §4.3.3 — and the per-child copay used in that ceiling is clamped to the child's actual provider charge. The ESS Year-1 alt path (FSU §4.1.5.1) is gated on earned income alone exceeding the TEA limit, consistent with the regulation's "earnings alone" wording. diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit_disabled.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit_disabled.yaml index 69b57d06ba1..9d7c238cb39 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit_disabled.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/child_age_limit_disabled.yaml @@ -9,5 +9,5 @@ metadata: reference: - title: Arkansas CCDF Plan 2025-2027, Section 2.2.1 Eligibility Definitions href: https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=18 - - title: Arkansas FSU Procedural Manual, Section 5.6.1 Special Needs Child + - title: Arkansas FSU Procedural Manual, Section 5.6.1 Priority and Waiver Types — Children with Special Needs href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=32 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml index 462c3404514..59d00512ce6 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml @@ -16,4 +16,4 @@ metadata: - title: OEC Rights & Responsibilities (Nov 2025) href: https://dese.ade.arkansas.gov/Files/R_&_R__Nov_2025_(English)_(1)_OEC.pdf#page=1 - title: OEC SRA Announcement Regarding Rates and Copays Effective November 1 - href: https://dese.ade.arkansas.gov/Files/OEC_SRA_Announcement_Regarding_Rates_and_Copays_Effective_November_1_OEC.pdf + href: https://dese.ade.arkansas.gov/Files/OEC_SRA_Announcement_Regarding_Rates_and_Copays_Effective_November_1_OEC.pdf#page=1 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml index 07dc1eb52bc..bec601e36cf 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml @@ -33,6 +33,6 @@ metadata: - title: SRA Sliding Fee Scale with Rates and Copays - Statewide Full Time (Nov 1, 2025) - age category labels href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf - title: AR Minimum Licensing Requirements for Child Care Centers (DCCECE, 2020) - Infant Center (item 13), Toddler Center (item 21), School Age Care (item 22) - href: https://humanservices.arkansas.gov/wp-content/uploads/2020-Child-Care-centers.pdf + href: https://humanservices.arkansas.gov/wp-content/uploads/2020-Child-Care-centers.pdf#page=45 - title: Ark. Code Sec. 6-18-207 (kindergarten enrollment age 5 by August 1) href: https://law.justia.com/codes/arkansas/title-6/subtitle-2/chapter-18/subchapter-2/section-6-18-207/ diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml index 5204095f984..d50facf0ebd 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/base_rate.yaml @@ -2,6 +2,10 @@ description: Arkansas provides these daily base reimbursement rates under the Sc # Source rate sheets have no Part-Time Night/Weekend row. Per the October 7 2025 # Provider Call ("Weekend and night time rates are set at a standard 10% increase # of typical rates"), PT NIGHT_WEEKEND cells below are derived as PT REGULAR × 1.10. +# Note: under the Nov 1 2025 schedule, Benton/Washington and Statewide rates +# converge for Preschool ($33 FT / $16.50 PT) and School-Aged ($28 FT / $14 PT) — +# the regional premium only applies to Infant and Toddler. Verified at 1200 DPI +# against the four Nov-2025 Sliding Fee Scale PDFs. metadata: period: day unit: currency-USD diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/max_copay_share_of_gross_income.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/max_copay_share_of_gross_income.yaml index e32f04d702c..72df0715652 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/max_copay_share_of_gross_income.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/max_copay_share_of_gross_income.yaml @@ -1,7 +1,10 @@ -description: Arkansas caps the total family copay at this share of gross monthly income under the School Readiness Assistance program. +description: Arkansas caps the total family copay at this share of countable monthly income under the School Readiness Assistance program. # CCDF rules cap copays at 7% of gross family income; Arkansas's CCDF State # Plan §3.1.1 self-certifies a stricter 4% maximum. The cap applies per # family, regardless of the number of children participating in CCDF. +# The State Plan's "gross income" wording is reconciled against FSU §4.3.3 +# (file p.20), which excludes children's SSI and Social Security from the +# budget — the cap base is therefore countable (adult) income. values: 2025-11-01: 0.04 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml index f23675e1d5f..389e0bc43bf 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/no_copay_smi_threshold.yaml @@ -1,4 +1,9 @@ -description: Arkansas sets this share of state median income as the no-copay threshold for non-school-aged children under the School Readiness Assistance program. +description: Arkansas zeroes the family copay for non-school-aged children whose family income is at or below this share of state median income under the School Readiness Assistance program. School-aged children always incur a copay (state share is 80% / 70%, not 100%) and are unaffected by this threshold. +# Source conflict: CCDF State Plan §2.3.1(b) describes a no-cost-of-care waiver +# for families at or below 75% SMI, while the Nov 2025 operational rate sheet +# only zeroes the copay for families at or below 40% SMI. The model follows +# the rate sheet (40%) because it is the operational document the agency uses +# to compute family copays. The 75% State Plan provision is not modeled. values: 2025-11-01: 0.4 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/ar_child_care_subsidies.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/ar_child_care_subsidies.yaml new file mode 100644 index 00000000000..84f52c778f6 --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/ar_child_care_subsidies.yaml @@ -0,0 +1,66 @@ +# Federal aggregator: ar_child_care_subsidies = adds ar_sra (annual sum +# of monthly ar_sra). Verifies the YEAR-level wiring from the federal +# child_care_subsidies path to AR's monthly benefit. + +- name: Case 1, eligible AR family's annual ar_child_care_subsidies equals 12 times the monthly ar_sra (LE_40 tier, no copay). + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + employment_income: 18_000 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + # Statewide / Toddler / REGULAR / FT / LE_40: monthly ar_sra = $770. + # Annual ar_child_care_subsidies = 12 * 770 = 9_240. + ar_child_care_subsidies: 9_240 + +- name: Case 2, non-AR household's ar_child_care_subsidies is zero (defined_for guard). + period: 2026 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + employment_income: 18_000 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_attending_days_per_month: 22 + 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: TX + output: + ar_child_care_subsidies: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/ar_sra.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/ar_sra.yaml index 84d61fd6bc5..378a83765a6 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/ar_sra.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/ar_sra.yaml @@ -104,7 +104,7 @@ is_ar_sra_eligible: true ar_sra: 0 -- name: Case 4, 4% cap binds - rate-sheet copay exceeds 4% of gross. +- name: Case 4, 4% cap binds - rate-sheet copay exceeds 4% of countable income. period: 2026-01 absolute_error_margin: 0.01 input: @@ -135,14 +135,14 @@ county_str: PULASKI_COUNTY_AR output: is_ar_sra_eligible: true - # Monthly gross = 30,695 / 12 = $2,557.92 + # Monthly countable income = 30,695 / 12 = $2,557.92 # 4% cap = $102.32; rate-sheet copay $154 exceeds cap. # cap_savings = $154 - $102.32 = $51.68 # uncapped subsidy = daily_state_payment * 22 = $28 * 22 = $616 # ar_sra = $616 + $51.68 = $667.68 ar_sra: 667.68 -- name: Case 5, negative gross income is clamped at zero before applying 4% cap. +- name: Case 5, negative countable income is clamped at zero before applying 4% cap. period: 2026-01 absolute_error_margin: 0.01 input: @@ -150,7 +150,7 @@ person1: age: 28 weekly_hours_worked: 35 - # Self-employment loss exceeds wages; gross_income would be negative. + # Self-employment loss exceeds wages; countable income would be negative. self_employment_income: -20_000 employment_income: 5_000 immigration_status: CITIZEN @@ -174,8 +174,49 @@ county_str: PULASKI_COUNTY_AR output: is_ar_sra_eligible: true - # Net income < 0 -> LE_40 tier (state share 1.00, copay 0). + # Net countable income < 0 -> LE_40 tier (state share 1.00, copay 0). # No copay so 4% cap is moot; full state payment. - # ar_sra = $35 * 22 = $770. Without the max_(gross, 0) clamp, + # ar_sra = $35 * 22 = $770. Without the max_(countable, 0) clamp, # cap_savings could become negative and corrupt the subsidy. ar_sra: 770 + +- name: Case 6, per-child payable-copay clamp - actual expense below rate-sheet copay. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + # GT_40_LE_60 tier: rate-sheet copay = $7/day = $154/month. + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_attending_days_per_month: 22 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + # Annual $1,500 -> monthly $125, below $154/mo rate-sheet copay. + spm_unit_pre_subsidy_childcare_expenses: 1_500 + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + is_ar_sra_eligible: true + # monthly_expense = $125; rate-sheet monthly_copay = $154. + # payable_copay = min($154, $125) = $125 (per-child clamp). + # Monthly countable income = $30,695 / 12 = $2,557.92; 4% cap = $102.32. + # cap_savings = $125 - $102.32 = $22.68. + # uncapped_subsidy per child = min(max($125 - $154, 0), $616) = 0. + # Return = min(0 + $22.68, $125) = $22.68. + # Without the per-child clamp, cap_savings would be $51.68 and ar_sra $51.68. + ar_sra: 22.68 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml index 5b27e05bfd7..8963a63029e 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_age_eligible.yaml @@ -131,3 +131,22 @@ state_code: AR output: is_ar_sra_age_eligible: [false, false] + +- name: Case 9, disabled child age 13 is age-eligible (disability extension activates at the standard cutoff). + period: 2026-01 + input: + people: + person1: + age: 40 + person2: + age: 13 + is_tax_unit_dependent: true + is_disabled: true + households: + household: + members: [person1, person2] + state_code: AR + output: + # Confirms the disability extension picks up where the standard 13-year + # cutoff leaves off; a disabled 13-year-old remains eligible (< 19). + is_ar_sra_age_eligible: [false, true] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml index 0ae613ae063..27bd278889a 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/eligibility/ar_sra_ess_eligible.yaml @@ -450,3 +450,34 @@ state_code: AR output: is_ar_sra_ess_eligible: false + +- name: Case 20, ESS Year-1 alt path - unearned income alone does NOT trigger the gate (FSU 4.1.5.1 'earnings alone'). + period: 2026-01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 15 + # Zero earned income keeps TEA-earned-income at $0, below the $513/mo limit. + employment_income: 0 + # High unearned income ($30k/yr = $2,500/mo) would push total TEA + # countable income above $513 — but FSU 4.1.5.1 says 'earnings alone'. + social_security: 30_000 + person2: + age: 2 + is_tax_unit_dependent: true + spm_units: + spm_unit: + members: [person1, person2] + ar_was_tea_recipient: true + ar_months_since_tea_exit: 6 + ar_tea: 0 + households: + household: + members: [person1, person2] + state_code: AR + output: + # Earned income = $0 (under $513 TEA limit); work hours = 15 (under 20). + # No adult student. Alt path does not trigger because earnings alone do + # not exceed the TEA limit; unearned income is excluded from this gate. + is_ar_sra_ess_eligible: false diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.yaml deleted file mode 100644 index 5d0d196bfd6..00000000000 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.yaml +++ /dev/null @@ -1,88 +0,0 @@ -# ar_sra_gross_income sums income across ALL household members (children -# included), unlike ar_sra_countable_income which excludes child income. -# It feeds the 4% copay-cap denominator under CCDF State Plan §3.1.1. - -- name: Case 1, adult-only earnings flow through to gross income. - period: 2026-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 30 - employment_income: 24_000 - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: AR - output: - # 24,000 / 12 = 2,000 monthly - ar_sra_gross_income: 2_000 - -- name: Case 2, child SSI is INCLUDED in gross income (contrast with countable). - period: 2026-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 30 - employment_income: 24_000 - person2: - age: 5 - ssi: 11_604 # /year (federal SSI max) - spm_units: - spm_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: AR - output: - # Gross: (24,000 + 11,604) / 12 = 2,967 - ar_sra_gross_income: 2_967 - # Countable excludes child SSI: 24,000 / 12 = 2,000 - ar_sra_countable_income: 2_000 - -- name: Case 3, child SSDI (social_security_disability) is INCLUDED in gross. - period: 2026-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 32 - employment_income: 36_000 - person2: - age: 10 - social_security_disability: 9_000 - spm_units: - spm_unit: - members: [person1, person2] - households: - household: - members: [person1, person2] - state_code: AR - output: - # Gross: (36,000 + 9,000) / 12 = 3,750 - ar_sra_gross_income: 3_750 - # Countable excludes child SS-disability: 36,000 / 12 = 3,000 - ar_sra_countable_income: 3_000 - -- name: Case 4, non-AR household yields zero gross (defined_for guard). - period: 2026-01 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 30 - employment_income: 24_000 - spm_units: - spm_unit: - members: [person1] - households: - household: - members: [person1] - state_code: TX - output: - ar_sra_gross_income: 0 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml index 8289f6f0e02..8e9955a49d7 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml @@ -760,3 +760,71 @@ # Negative income -> LE_40 tier (share=1.00, copay=0) -> cap_savings=0. # Toddler Statewide FT LE_40: monthly state payment = $35 * 22 = $770. ar_sra: 770 + +- name: Case 21, October 2025 is the last pre-effect month - eligibility is false, benefit is zero. + period: 2025-10 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + employment_income: 18_000 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + # in_effect flips to true on 2025-11-01; otherwise-eligible families + # produce no benefit in October. + is_ar_sra_eligible: false + ar_sra: 0 + +- name: Case 22, November 2025 is the first post-effect month - same family is eligible and receives the full Statewide Toddler LE_40 benefit. + period: 2025-11 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + weekly_hours_worked: 35 + employment_income: 18_000 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + childcare_attending_days_per_month: 22 + 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: AR + county_str: PULASKI_COUNTY_AR + output: + # in_effect now true; LE_40 tier (share=1.00, copay=0) gives full base. + # Toddler Statewide FT LE_40: monthly state payment = $35 * 22 = $770. + is_ar_sra_eligible: true + ar_sra: 770 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml index 582b429c7f7..88a5fb824a8 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.yaml @@ -278,3 +278,69 @@ state_code: AR output: ar_sra_daily_base_rate: 40.70 + +- name: Case 17, Benton/Washington preschool REGULAR full time base rate is 33.00. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 4 + childcare_hours_per_day: 8 + households: + household: + members: [person1] + county_str: BENTON_COUNTY_AR + state_code: AR + output: + # B/W preschool rate matches Statewide ($33) at the regular tier. + ar_sra_daily_base_rate: 33.00 + +- name: Case 18, Benton/Washington school-aged REGULAR full time base rate is 28.00. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 7 + childcare_hours_per_day: 8 + households: + household: + members: [person1] + county_str: WASHINGTON_COUNTY_AR + state_code: AR + output: + # B/W school-aged rate matches Statewide ($28) at the regular tier. + ar_sra_daily_base_rate: 28.00 + +- name: Case 19, Benton/Washington preschool REGULAR part time base rate is 16.50. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 4 + childcare_hours_per_day: 4 + households: + household: + members: [person1] + county_str: BENTON_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 16.50 + +- name: Case 20, Benton/Washington school-aged REGULAR part time base rate is 14.00. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 7 + childcare_hours_per_day: 4 + households: + household: + members: [person1] + county_str: WASHINGTON_COUNTY_AR + state_code: AR + output: + ar_sra_daily_base_rate: 14.00 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml index d6410e0ca10..ecdc0cbccf0 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.yaml @@ -92,3 +92,160 @@ # Statewide / Preschool / REGULAR / FT base = $33.00, share = 0.60 # daily copay = $33 * (1 - 0.60) = $13.20 ar_sra_daily_copay: [0, 13.20] + +- name: Case 4, Infant Benton/Washington FT at GT_60 SMI has positive copay (30 percent of B/W base). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + # 75% SMI -> GT_60 tier + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: BENTON_COUNTY_AR + output: + # Benton/Washington / Infant / REGULAR / FT base = $38.00, share = 0.70 + # daily copay = $38 * (1 - 0.70) = $11.40 + ar_sra_daily_copay: [0, 11.40] + +- name: Case 5, Toddler Statewide PT at GT_40_LE_60 SMI has positive copay (40 percent of PT base). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + # 50% SMI -> GT_40_LE_60 tier + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + # Below the 7-hr FT threshold -> PART_TIME + childcare_hours_per_day: 4 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + # Statewide / Toddler / REGULAR / PT base = $17.50, share = 0.60 + # daily copay = $17.50 * (1 - 0.60) = $7.00 + ar_sra_daily_copay: [0, 7.00] + +- name: Case 6, Infant Statewide FT NIGHT_WEEKEND at GT_60 SMI shows the 10 percent supplement flows to copay. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + # 75% SMI -> GT_60 tier + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + ar_sra_care_type: NIGHT_WEEKEND + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + # Statewide / Infant / NIGHT_WEEKEND / FT base = $39.60, share = 0.70 + # daily copay = $39.60 * (1 - 0.70) = $11.88 + ar_sra_daily_copay: [0, 11.88] + +- name: Case 7, Toddler Statewide FT SN2 at GT_40_LE_60 SMI shows the 40 percent special-needs supplement flows to copay. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + ar_sra_care_type: SN2 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + # Statewide / Toddler / SN2 / FT base = $49.00, share = 0.80 + # daily copay = $49 * (1 - 0.80) = $9.80 + ar_sra_daily_copay: [0, 9.80] + +- name: Case 8, Toddler Statewide FT SN3 at GT_60 SMI confirms SN3 matches SN2 (premium tier). + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + ar_sra_care_type: SN3 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + # Statewide / Toddler / SN3 / FT base = $49.00, share = 0.70 + # daily copay = $49 * (1 - 0.70) = $14.70 + ar_sra_daily_copay: [0, 14.70] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml index 45f5039fa9a..753ce393150 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.yaml @@ -95,3 +95,158 @@ # Benton/Washington / Infant / REGULAR / FT base = $38.00; share = 0.70 # daily state payment = $38.00 * 0.70 = $26.60 ar_sra_daily_state_payment: [0, 26.60] + +- name: Case 4, Toddler Statewide PT at GT_40_LE_60 SMI uses the PT base rate. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + # 50% SMI -> GT_40_LE_60 tier + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + # Below the 7-hr FT threshold -> PART_TIME + childcare_hours_per_day: 4 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + # Statewide / Toddler / REGULAR / PT base = $17.50; share = 0.60 + # daily state payment = $17.50 * 0.60 = $10.50 + ar_sra_daily_state_payment: [0, 10.50] + +- name: Case 5, Infant Statewide FT NIGHT_WEEKEND at GT_60 SMI shows the 10 percent supplement flows to state payment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 0 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + ar_sra_care_type: NIGHT_WEEKEND + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + # Statewide / Infant / NIGHT_WEEKEND / FT base = $39.60; share = 0.70 + # daily state payment = $39.60 * 0.70 = $27.72 + ar_sra_daily_state_payment: [0, 27.72] + +- name: Case 6, Toddler Statewide FT SN2 at GT_40_LE_60 SMI shows the 40 percent special-needs supplement flows to state payment. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + employment_income: 30_695 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + ar_sra_care_type: SN2 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + # Statewide / Toddler / SN2 / FT base = $49.00; share = 0.80 + # daily state payment = $49 * 0.80 = $39.20 + ar_sra_daily_state_payment: [0, 39.20] + +- name: Case 7, Toddler Statewide FT SN3 at GT_60 SMI confirms SN3 rates match SN2. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 2 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 8 + ar_sra_care_type: SN3 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: PULASKI_COUNTY_AR + output: + # Statewide / Toddler / SN3 / FT base = $49.00; share = 0.70 + # daily state payment = $49 * 0.70 = $34.30 + ar_sra_daily_state_payment: [0, 34.30] + +- name: Case 8, Preschool Benton/Washington PT at GT_60 SMI uses B/W PT rate. + period: 2026-01 + absolute_error_margin: 0.01 + input: + people: + person1: + age: 28 + employment_income: 46_043 + immigration_status: CITIZEN + person2: + age: 4 + is_tax_unit_dependent: true + immigration_status: CITIZEN + childcare_hours_per_day: 4 + tax_units: + tax_unit: + members: [person1, person2] + spm_units: + spm_unit: + members: [person1, person2] + households: + household: + members: [person1, person2] + state_code: AR + county_str: BENTON_COUNTY_AR + output: + # B/W preschool PT rate matches Statewide ($16.50); share = 0.50 + # daily state payment = $16.50 * 0.50 = $8.25 + ar_sra_daily_state_payment: [0, 8.25] diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_zone.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_zone.yaml index f8525bd7956..94d650c0c77 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_zone.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/rates/ar_sra_zone.yaml @@ -24,3 +24,14 @@ state_code: AR output: ar_sra_zone: STATEWIDE + +- name: Case 4, non-AR household with a B/W county string still defaults to STATEWIDE (state-guard). + period: 2026-01 + input: + # defined_for filters output, not the rate-table lookup; the formula's + # explicit state == "AR" check is what prevents non-AR rows from being + # classified as Benton/Washington when the county string coincides. + county_str: BENTON_COUNTY_AR + state_code: TX + output: + ar_sra_zone: STATEWIDE diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_months_since_tea_exit.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_months_since_tea_exit.py index f5d4a72fd4e..df962eceef4 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_months_since_tea_exit.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_months_since_tea_exit.py @@ -8,4 +8,4 @@ class ar_months_since_tea_exit(Variable): definition_period = MONTH defined_for = StateCode.AR default_value = 0 - reference = "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16" + reference = "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=12" diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py index 759be0c49b9..41d97651275 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra.py @@ -10,7 +10,11 @@ class ar_sra(Variable): defined_for = "is_ar_sra_eligible" reference = ( "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", "https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=39", + "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=20", ) def formula(spm_unit, period, parameters): @@ -27,14 +31,19 @@ def formula(spm_unit, period, parameters): monthly_max_state_payment, ) total_uncapped_subsidy = spm_unit.sum(uncapped_subsidy * is_eligible_child) - # CCDF State Plan §3.1.1: per-family copay capped at 4% of gross income. + # CCDF State Plan §3.1.1 caps family copay at 4% of monthly income. + # FSU §4.3.3 (file p.20) excludes children's SSI and Social Security + # from the budget, so the cap base is countable (adult) income — not + # the literal "gross income" wording. p = parameters(period).gov.states.ar.ade.oec.sra.rates - total_uncapped_copay = spm_unit.sum(monthly_copay * is_eligible_child) - # Clamp at 0 so a negative self-employment loss doesn't inflate cap_savings. - gross_income = max_(spm_unit("ar_sra_gross_income", period), 0) - copay_ceiling = p.max_copay_share_of_gross_income * gross_income - cap_savings = max_(total_uncapped_copay - copay_ceiling, 0) - # Clamp at actual expense: when a child has $0 expense, the rate-sheet - # copay still appears in total_uncapped_copay and could inflate cap_savings. + # Each child's payable copay is the lesser of the rate-sheet copay and + # the child's actual provider charge — a child whose expense is below + # the scheduled copay does not owe the full scheduled amount. + payable_copay = min_(monthly_copay, monthly_expense) + total_payable_copay = spm_unit.sum(payable_copay * is_eligible_child) + # Clamp at 0 so a self-employment loss doesn't inflate cap_savings. + countable_income = max_(spm_unit("ar_sra_countable_income", period), 0) + copay_ceiling = p.max_copay_share_of_gross_income * countable_income + cap_savings = max_(total_payable_copay - copay_ceiling, 0) total_expense = spm_unit.sum(monthly_expense * is_eligible_child) return min_(total_uncapped_subsidy + cap_savings, total_expense) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py index 9baba36d547..47caed46d21 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_age_category.py @@ -16,9 +16,19 @@ class ar_sra_age_category(Variable): definition_period = MONTH defined_for = StateCode.AR label = "Arkansas SRA child age category" - reference = "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", + "https://law.justia.com/codes/arkansas/title-6/subtitle-2/chapter-18/subchapter-2/section-6-18-207/", + ) def formula(person, period, parameters): + # Infant/Toddler boundaries follow AR Min Licensing (DCCECE 2020). + # The 72-month School-Aged boundary tracks typical kindergarten entry + # under Ark. Code §6-18-207 (age 5 by Aug 1 of the school year); + # Preschool spans the 36-71 month gap. p = parameters(period).gov.states.ar.ade.oec.sra.rates.age_category_months age_months = person("age", period.this_year) * MONTHS_IN_YEAR return p.calc(age_months) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py index 522b868304a..b5ecd0ed1fc 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_sra_income_tier.py @@ -15,7 +15,12 @@ class ar_sra_income_tier(Variable): definition_period = MONTH defined_for = StateCode.AR label = "Arkansas SRA family income tier (% SMI)" - reference = "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", + ) def formula(spm_unit, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_was_tea_recipient.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_was_tea_recipient.py index aea459f7c9c..e4784ec1732 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_was_tea_recipient.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/ar_was_tea_recipient.py @@ -8,4 +8,4 @@ class ar_was_tea_recipient(Variable): definition_period = YEAR defined_for = StateCode.AR default_value = False - reference = "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=16" + reference = "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=12" diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py index 7dc74d7c7c1..634549209a1 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_ess_eligible.py @@ -26,12 +26,17 @@ def formula(spm_unit, period, parameters): "is_full_time_college_student", period.this_year ) any_adult_student = spm_unit.sum(adult_is_student) > 0 - # FSU §4.1.5.1 Year-1 alt path: earnings make family TEA-income-ineligible. - tea_income_ineligible = ~spm_unit("ar_tea_income_eligible", period) + # FSU §4.1.5.1 Year-1 alt path: earnings *alone* make family + # TEA-income-ineligible. The "alone" qualifier constrains the gate + # input to earned income — unearned income (pension, child support, + # Social Security) does not count toward this specific test. + tea_earned = spm_unit("ar_tea_countable_earned_income", period) + tea_limit = parameters(period).gov.states.ar.dhs.tea.income.income_limit + earnings_make_tea_ineligible = tea_earned > tea_limit year_1_active = ( (max_adult_hours >= p.activity_hours_ess_year_1) | any_adult_student - | tea_income_ineligible + | earnings_make_tea_ineligible ) year_2_active = ( max_adult_hours >= p.activity_hours_ess_year_2 diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.py deleted file mode 100644 index 367b7dff4d1..00000000000 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/income/ar_sra_gross_income.py +++ /dev/null @@ -1,22 +0,0 @@ -from policyengine_us.model_api import * - - -class ar_sra_gross_income(Variable): - value_type = float - entity = SPMUnit - label = "Arkansas SRA gross income for the per-family copay ceiling" - unit = USD - definition_period = MONTH - defined_for = StateCode.AR - reference = ( - "https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=39", - "https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=19", - ) - - def formula(spm_unit, period, parameters): - p = parameters(period).gov.states.ar.ade.oec.sra.income - # CCDF State Plan §3.1.1 caps the family copay at 4% of gross income, - # which includes all members (children's SSI and SS included). - person = spm_unit.members - per_person_income = sum(person(source, period) for source in p.sources) - return spm_unit.sum(per_person_income) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py index 47d2bffa501..7d406d5f959 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_base_rate.py @@ -10,10 +10,17 @@ class ar_sra_daily_base_rate(Variable): defined_for = "is_ar_sra_child_eligible" reference = ( "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", - "https://dese.ade.arkansas.gov/Files/October_2025_Provider_Call_10.7.25_OEC.pdf#page=5", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/October_2025_Provider_Call_10.7.25_OEC.pdf#page=4", ) def formula(person, period, parameters): + # Benton/Washington rates exceed Statewide for INFANT and TODDLER only; + # PRESCHOOL and SCHOOL_AGED rates are identical across both zones. The + # zone × age × care_type × time table preserves all four rate sheets + # so the structure stays explicit even where two cells collapse. p = parameters(period).gov.states.ar.ade.oec.sra.rates zone = person.household("ar_sra_zone", period) age_category = person("ar_sra_age_category", period) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py index a10df87c8ea..8cf141dc34e 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_copay.py @@ -8,9 +8,20 @@ class ar_sra_daily_copay(Variable): label = "Arkansas SRA daily family copay" definition_period = MONTH defined_for = "is_ar_sra_child_eligible" - reference = "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", + ) def formula(person, period, parameters): + # Source conflict: CCDF State Plan §2.3.1(b) describes a no-cost-of-care + # waiver for families at or below 75% SMI, while the Nov 2025 operational + # rate sheet only zeroes the copay for families at or below 40% SMI. The + # model follows the rate sheet (40%) because it is the operational + # document the agency uses to compute family copays. The 75% State Plan + # provision is not modeled. base = person("ar_sra_daily_base_rate", period) state_share = person("ar_sra_state_share", period) return base * (1 - state_share) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py index f8c23fd5062..e9cc2eff4d7 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_daily_state_payment.py @@ -8,7 +8,12 @@ class ar_sra_daily_state_payment(Variable): label = "Arkansas SRA daily state payment per child" definition_period = MONTH defined_for = "is_ar_sra_child_eligible" - reference = "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", + ) def formula(person, period, parameters): base = person("ar_sra_daily_base_rate", period) diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py index de9f41c995b..7bb27b81e29 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/rates/ar_sra_state_share.py @@ -7,7 +7,12 @@ class ar_sra_state_share(Variable): label = "Arkansas SRA state share of daily base rate" definition_period = MONTH defined_for = "is_ar_sra_child_eligible" - reference = "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf" + reference = ( + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Part_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Full_Time_20251101_OEC.pdf", + "https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Benton-Washington_Co_Part_Time_20251101_OEC.pdf", + ) def formula(person, period, parameters): p = parameters(period).gov.states.ar.ade.oec.sra.rates From 8be9b6644b6bab90919b990dcc74e245fea8038b Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 19 May 2026 23:22:00 -0400 Subject: [PATCH 16/17] fix --- .../sra/eligibility/ess_window_months.yaml | 2 +- .../gov/states/ar/ade/oec/sra/in_effect.yaml | 2 +- .../states/ar/ade/oec/sra/income/sources.yaml | 1 - .../oec/sra/rates/age_category_months.yaml | 2 +- .../states/ar/ade/oec/sra/integration.yaml | 40 ++----------------- .../eligibility/is_ar_sra_child_eligible.py | 2 +- 6 files changed, 7 insertions(+), 42 deletions(-) diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml index c68d5c655af..e2fafe1c6ff 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/eligibility/ess_window_months.yaml @@ -8,4 +8,4 @@ metadata: label: Arkansas SRA ESS post-TEA window months reference: - title: FSU Procedural Manual (June 2023), Section 5.4.1 - href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=27 + href: https://dese.ade.arkansas.gov/Files/FSU-Procedural-Manual-June-2023_UPDATED_20230629075344.pdf#page=26 diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml index 59d00512ce6..462c3404514 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/in_effect.yaml @@ -16,4 +16,4 @@ metadata: - title: OEC Rights & Responsibilities (Nov 2025) href: https://dese.ade.arkansas.gov/Files/R_&_R__Nov_2025_(English)_(1)_OEC.pdf#page=1 - title: OEC SRA Announcement Regarding Rates and Copays Effective November 1 - href: https://dese.ade.arkansas.gov/Files/OEC_SRA_Announcement_Regarding_Rates_and_Copays_Effective_November_1_OEC.pdf#page=1 + href: https://dese.ade.arkansas.gov/Files/OEC_SRA_Announcement_Regarding_Rates_and_Copays_Effective_November_1_OEC.pdf diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/sources.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/sources.yaml index 6d347a739d1..fcdfecd2200 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/sources.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/income/sources.yaml @@ -3,7 +3,6 @@ values: 2025-10-01: - employment_income - self_employment_income - - tip_income - social_security_retirement - social_security_disability - social_security_survivors diff --git a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml index bec601e36cf..d420061baf5 100644 --- a/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml +++ b/policyengine_us/parameters/gov/states/ar/ade/oec/sra/rates/age_category_months.yaml @@ -34,5 +34,5 @@ metadata: href: https://dese.ade.arkansas.gov/Files/SRA_Sliding_Fee_Scale_with_Rates_&_Copays--Statewide_Full_Time_20251101_OEC.pdf - title: AR Minimum Licensing Requirements for Child Care Centers (DCCECE, 2020) - Infant Center (item 13), Toddler Center (item 21), School Age Care (item 22) href: https://humanservices.arkansas.gov/wp-content/uploads/2020-Child-Care-centers.pdf#page=45 - - title: Ark. Code Sec. 6-18-207 (kindergarten enrollment age 5 by August 1) + - title: Arkansas Code Annotated § 6-18-207 (Compulsory school age, kindergarten by Aug 1) href: https://law.justia.com/codes/arkansas/title-6/subtitle-2/chapter-18/subchapter-2/section-6-18-207/ diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml index 8e9955a49d7..27ccfb6e6ad 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml @@ -761,8 +761,8 @@ # Toddler Statewide FT LE_40: monthly state payment = $35 * 22 = $770. ar_sra: 770 -- name: Case 21, October 2025 is the last pre-effect month - eligibility is false, benefit is zero. - period: 2025-10 +- name: Case 21, September 2025 is a pre-effect month - eligibility is false, benefit is zero. + period: 2025-09 absolute_error_margin: 0.01 input: people: @@ -791,40 +791,6 @@ county_str: PULASKI_COUNTY_AR output: # in_effect flips to true on 2025-11-01; otherwise-eligible families - # produce no benefit in October. + # produce no benefit in September. is_ar_sra_eligible: false ar_sra: 0 - -- name: Case 22, November 2025 is the first post-effect month - same family is eligible and receives the full Statewide Toddler LE_40 benefit. - period: 2025-11 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 28 - weekly_hours_worked: 35 - employment_income: 18_000 - immigration_status: CITIZEN - person2: - age: 2 - is_tax_unit_dependent: true - immigration_status: CITIZEN - childcare_hours_per_day: 8 - childcare_attending_days_per_month: 22 - 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: AR - county_str: PULASKI_COUNTY_AR - output: - # in_effect now true; LE_40 tier (share=1.00, copay=0) gives full base. - # Toddler Statewide FT LE_40: monthly state payment = $35 * 22 = $770. - is_ar_sra_eligible: true - ar_sra: 770 diff --git a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_child_eligible.py b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_child_eligible.py index 5952c5cab22..ea1ed437832 100644 --- a/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_child_eligible.py +++ b/policyengine_us/variables/gov/states/ar/ade/oec/sra/eligibility/is_ar_sra_child_eligible.py @@ -7,7 +7,7 @@ class is_ar_sra_child_eligible(Variable): label = "Eligible child for Arkansas SRA" definition_period = MONTH defined_for = StateCode.AR - reference = "https://www.publichealthlawcenter.org/sites/default/files/Arkansas%20Title%20016%20Division%2022%20Rule%208.pdf#page=11" + reference = "https://dese.ade.arkansas.gov/Files/2025-2027_CCDF_State_Plan_Final_4.26.24.1REV_OEC.pdf#page=18" def formula(person, period, parameters): age_eligible = person("is_ar_sra_age_eligible", period) From 3c9edbe6b9349642c2c7de8283dbd7aef9083e2b Mon Sep 17 00:00:00 2001 From: Ziming Date: Tue, 19 May 2026 23:31:19 -0400 Subject: [PATCH 17/17] minor --- .../states/ar/ade/oec/sra/integration.yaml | 34 ------------------- 1 file changed, 34 deletions(-) diff --git a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml index 27ccfb6e6ad..8289f6f0e02 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ar/ade/oec/sra/integration.yaml @@ -760,37 +760,3 @@ # Negative income -> LE_40 tier (share=1.00, copay=0) -> cap_savings=0. # Toddler Statewide FT LE_40: monthly state payment = $35 * 22 = $770. ar_sra: 770 - -- name: Case 21, September 2025 is a pre-effect month - eligibility is false, benefit is zero. - period: 2025-09 - absolute_error_margin: 0.01 - input: - people: - person1: - age: 28 - weekly_hours_worked: 35 - employment_income: 18_000 - immigration_status: CITIZEN - person2: - age: 2 - is_tax_unit_dependent: true - immigration_status: CITIZEN - childcare_hours_per_day: 8 - childcare_attending_days_per_month: 22 - 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: AR - county_str: PULASKI_COUNTY_AR - output: - # in_effect flips to true on 2025-11-01; otherwise-eligible families - # produce no benefit in September. - is_ar_sra_eligible: false - ar_sra: 0