diff --git a/changelog.d/ny-ccap-rate-differentials.added.md b/changelog.d/ny-ccap-rate-differentials.added.md new file mode 100644 index 00000000000..5c33fcfb48b --- /dev/null +++ b/changelog.d/ny-ccap-rate-differentials.added.md @@ -0,0 +1 @@ +Added New York CCAP payment differentials, including the 10% statutory minimum from April 2025 and the 35% combined limit from December 2025, the special-needs market rate, and New York City enhanced informal and legally exempt group rates. diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/accreditation.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/accreditation.yaml new file mode 100644 index 00000000000..34ec43bc6a3 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/accreditation.yaml @@ -0,0 +1,13 @@ +description: New York districts pay this default optional differential to nationally accredited licensed or registered providers. +# Pay nothing until a district elects this optional differential. Separate +# parameters hold confirmed local rates. +values: + 2024-10-01: 0 +metadata: + unit: /1 + label: New York CCAP accreditation differential + reference: + - title: 24-OCFS-LCM-22, differential payment rates + href: https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=10 + - title: 18 NYCRR 415.9 + href: https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9 diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/accreditation_minimum.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/accreditation_minimum.yaml new file mode 100644 index 00000000000..947133f7e9a --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/accreditation_minimum.yaml @@ -0,0 +1,11 @@ +description: New York requires at least this accreditation differential when a district elects to pay one. +values: + 2024-10-01: 0.05 +metadata: + unit: /1 + label: New York CCAP accreditation minimum differential + reference: + - title: 24-OCFS-LCM-22, differential payment rates + href: https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=10 + - title: 18 NYCRR 415.9 + href: https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9 diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/homelessness.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/homelessness.yaml new file mode 100644 index 00000000000..a0818322b65 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/homelessness.yaml @@ -0,0 +1,16 @@ +description: New York districts pay this default differential to licensed or registered providers caring for children experiencing homelessness. +# Districts without a confirmed local percentage pay the state minimum. +# Separate parameters hold confirmed local rates. +values: + 2024-10-01: 0.05 + 2025-04-01: 0.1 +metadata: + unit: /1 + label: New York CCAP homelessness differential + reference: + - title: 24-OCFS-LCM-22, differential payment rates + href: https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=10 + - title: NY Social Services Law 410-x(10)(a), effective April 1, 2025 + href: https://www.nysenate.gov/legislation/laws/SOS/410-X + - title: 18 NYCRR 415.9 + href: https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9 diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/legally_exempt_homelessness.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/legally_exempt_homelessness.yaml new file mode 100644 index 00000000000..8351f641a8c --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/legally_exempt_homelessness.yaml @@ -0,0 +1,13 @@ +description: New York districts pay this default optional differential to legally exempt providers caring for children experiencing homelessness. +# Pay nothing until a district elects this optional differential. Separate +# parameters hold confirmed local rates. +values: + 2024-10-01: 0 +metadata: + unit: /1 + label: New York CCAP legally exempt homelessness differential + reference: + - title: 24-OCFS-LCM-22, differential payment rates + href: https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=10 + - title: 18 NYCRR 415.9 + href: https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9 diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/maximum.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/maximum.yaml new file mode 100644 index 00000000000..505d5709686 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/maximum.yaml @@ -0,0 +1,18 @@ +description: New York limits combined differentials to this fraction of the lesser of actual cost and the applicable market rate unless OCFS grants a waiver. +# OCFS raised the limit from 25% to 35% in a rule effective December 24, +# 2025. The monthly model first reads the higher limit in January 2026. +values: + 2024-10-01: 0.25 + 2025-12-24: 0.35 +metadata: + unit: /1 + label: New York CCAP maximum differential + reference: + - title: 24-OCFS-LCM-22, differential payment rates + href: https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=10 + - title: NYS Register, March 12, 2025, I.D. No. CFS-10-25-00002-P + href: https://dos.ny.gov/system/files/documents/2025/03/031225.pdf#page=7 + - title: NYS Register, December 24, 2025, I.D. No. CFS-10-25-00002-A + href: https://dos.ny.gov/system/files/documents/2025/12/december-24-2025-vol.xlvii-issue-51.pdf#page=7 + - title: 18 NYCRR 415.9 + href: https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9 diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/maximum_individual.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/maximum_individual.yaml new file mode 100644 index 00000000000..b2709e92509 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/maximum_individual.yaml @@ -0,0 +1,13 @@ +description: New York limits each differential to this fraction of the lesser of actual cost and the applicable market rate. +values: + 2024-10-01: 0.15 +metadata: + unit: /1 + label: New York CCAP maximum individual differential + reference: + - title: "24-OCFS-LCM-22, differential payment rates #page 9-10" + href: https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=9 + - title: NY Social Services Law 410-x(10), effective April 1, 2025 + href: https://www.nysenate.gov/legislation/laws/SOS/410-X + - title: 18 NYCRR 415.9 + href: https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9 diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/minimum.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/minimum.yaml new file mode 100644 index 00000000000..612230292dc --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/minimum.yaml @@ -0,0 +1,14 @@ +description: New York requires at least this differential for care during nontraditional hours and for licensed or registered providers caring for children experiencing homelessness. +values: + 2024-10-01: 0.05 + 2025-04-01: 0.1 +metadata: + unit: /1 + label: New York CCAP mandatory minimum differential + reference: + - title: "24-OCFS-LCM-22, differential payment rates #page 9-10" + href: https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=9 + - title: NY Social Services Law 410-x(10), effective April 1, 2025 + href: https://www.nysenate.gov/legislation/laws/SOS/410-X + - title: 18 NYCRR 415.9 + href: https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9 diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/monroe_accreditation.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/monroe_accreditation.yaml new file mode 100644 index 00000000000..57a990e7ae0 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/monroe_accreditation.yaml @@ -0,0 +1,12 @@ +description: Monroe County pays this optional accreditation differential under its approved Child and Family Services Plan. +# OCFS approved the plan effective November 18, 2024. The monthly model +# first reads that choice in December; earlier months use the state default. +values: + 2024-10-01: 0 + 2024-11-18: 0.1 +metadata: + unit: /1 + label: Monroe County CCAP accreditation differential + reference: + - title: Monroe County approved 2024-2029 Child and Family Services Plan, Appendix N + href: https://www.monroecounty.gov/files/hs/2024-2029%20Monroe_County_Child_Family_Services_Plan_Merged.pdf diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/monroe_legally_exempt_homelessness.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/monroe_legally_exempt_homelessness.yaml new file mode 100644 index 00000000000..00d9040bef7 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/monroe_legally_exempt_homelessness.yaml @@ -0,0 +1,12 @@ +description: Monroe County pays this optional legally exempt homelessness differential under its approved Child and Family Services Plan. +# OCFS approved the plan effective November 18, 2024. The monthly model +# first reads that choice in December; earlier months use the state default. +values: + 2024-10-01: 0 + 2024-11-18: 0.05 +metadata: + unit: /1 + label: Monroe County CCAP legally exempt homelessness differential + reference: + - title: Monroe County approved 2024-2029 Child and Family Services Plan, Appendix N + href: https://www.monroecounty.gov/files/hs/2024-2029%20Monroe_County_Child_Family_Services_Plan_Merged.pdf diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/nontraditional_hours.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/nontraditional_hours.yaml new file mode 100644 index 00000000000..49448df4b40 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/nontraditional_hours.yaml @@ -0,0 +1,16 @@ +description: New York districts pay this default differential for care during nontraditional hours. +# Districts without a confirmed local percentage pay the state minimum. +# Separate parameters hold confirmed local rates. +values: + 2024-10-01: 0.05 + 2025-04-01: 0.1 +metadata: + unit: /1 + label: New York CCAP nontraditional hours differential + reference: + - title: 24-OCFS-LCM-22, differential payment rates + href: https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=9 + - title: NY Social Services Law 410-x(10)(b), effective April 1, 2025 + href: https://www.nysenate.gov/legislation/laws/SOS/410-X + - title: 18 NYCRR 415.9 + href: https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9 diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/nyc_nontraditional_hours.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/nyc_nontraditional_hours.yaml new file mode 100644 index 00000000000..02c9ebce275 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/differentials/nyc_nontraditional_hours.yaml @@ -0,0 +1,11 @@ +description: New York City pays this differential for child care during nontraditional hours. +# City officials reported implementing 15% in September 2023. Apply that +# confirmed choice from the October 2024 market-rate schedule modeled here. +values: + 2024-10-01: 0.15 +metadata: + unit: /1 + label: New York City CCAP nontraditional hours differential + reference: + - title: New York City Council Committee on Education and Committee on Women and Gender Equity, September 21, 2023 + href: https://legistar.council.nyc.gov/View.ashx?GUID=43D12D7C-D5F5-4CDC-B300-422110951852&ID=12379758&M=F#page=22 diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/daily.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/daily.yaml index be457ad47c0..816ebbead12 100644 --- a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/daily.yaml +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/daily.yaml @@ -182,15 +182,17 @@ GROUP_4: 2024-10-01: 42 SCHOOL_AGE: 2024-10-01: 39 + # Group 4 contains only New York City. ACS chose 75% of the + # registered family day care rate for enhanced informal providers. LE_ENH: INFANT: - 2024-10-01: 56 + 2024-10-01: 60 TODDLER: - 2024-10-01: 49 + 2024-10-01: 53 PRESCHOOLER: - 2024-10-01: 46 + 2024-10-01: 49 SCHOOL_AGE: - 2024-10-01: 42 + 2024-10-01: 45 metadata: propagate_metadata_to_children: true @@ -204,3 +206,5 @@ metadata: reference: - title: 24-OCFS-LCM-22 Attachment A, daily market rates for county Groups 1-4 (file pages 15-18), effective October 1, 2024 href: https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=15 + - title: NYC ACS FS-023, revised October 2024 + href: https://www.nyc.gov/assets/acs/pdf/earlycare/2024/FS023.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/enhanced_group/both.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/enhanced_group/both.yaml new file mode 100644 index 00000000000..189d121c78b --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/enhanced_group/both.yaml @@ -0,0 +1,23 @@ +description: New York districts pay this fraction of the day care center market rate to legally exempt group child care programs meeting both the enhanced health requirement and the enhanced training requirement. +# New York City publishes enhanced rates in FS-023. Outside New York City, +# use the standard group rates because no district enhancement was confirmed. +# A zero fraction preserves the standard rate rather than creating an enhancement. +GROUP_1: + 2024-10-01: 0 +GROUP_2: + 2024-10-01: 0 +GROUP_3: + 2024-10-01: 0 +GROUP_4: + 2024-10-01: 0.87 + +metadata: + unit: /1 + label: New York CCAP legally exempt group health and training enhanced rate fraction + breakdown: + - ny_ccap_county_group + reference: + - title: 24-OCFS-LCM-22 + href: https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=9 + - title: NYC ACS FS-023, revised October 2024 + href: https://www.nyc.gov/assets/acs/pdf/earlycare/2024/FS023.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/enhanced_group/single.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/enhanced_group/single.yaml new file mode 100644 index 00000000000..90045a764cc --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/enhanced_group/single.yaml @@ -0,0 +1,23 @@ +description: New York districts pay this fraction of the day care center market rate to legally exempt group child care programs meeting either the enhanced health requirement or the enhanced training requirement. +# New York City publishes enhanced rates in FS-023. Outside New York City, +# use the standard group rates because no district enhancement was confirmed. +# A zero fraction preserves the standard rate rather than creating an enhancement. +GROUP_1: + 2024-10-01: 0 +GROUP_2: + 2024-10-01: 0 +GROUP_3: + 2024-10-01: 0 +GROUP_4: + 2024-10-01: 0.81 + +metadata: + unit: /1 + label: New York CCAP legally exempt group health or training enhanced rate fraction + breakdown: + - ny_ccap_county_group + reference: + - title: 24-OCFS-LCM-22 + href: https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=9 + - title: NYC ACS FS-023, revised October 2024 + href: https://www.nyc.gov/assets/acs/pdf/earlycare/2024/FS023.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/part_day.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/part_day.yaml index 26c8520cdf8..2f921f36d52 100644 --- a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/part_day.yaml +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/part_day.yaml @@ -182,15 +182,17 @@ GROUP_4: 2024-10-01: 28 SCHOOL_AGE: 2024-10-01: 26 + # Group 4 contains only New York City. ACS chose 75% of the + # registered family day care rate for enhanced informal providers. LE_ENH: INFANT: - 2024-10-01: 37 + 2024-10-01: 40 TODDLER: - 2024-10-01: 33 + 2024-10-01: 35 PRESCHOOLER: - 2024-10-01: 30 + 2024-10-01: 32 SCHOOL_AGE: - 2024-10-01: 28 + 2024-10-01: 30 metadata: propagate_metadata_to_children: true @@ -204,3 +206,5 @@ metadata: reference: - title: 24-OCFS-LCM-22 Attachment A, part-day market rates for county Groups 1-4 (file pages 15-18), effective October 1, 2024 href: https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=15 + - title: NYC ACS FS-023, revised October 2024 + href: https://www.nyc.gov/assets/acs/pdf/earlycare/2024/FS023.pdf#page=2 diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/special_needs_multiplier.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/special_needs_multiplier.yaml new file mode 100644 index 00000000000..fcb1031b851 --- /dev/null +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/special_needs_multiplier.yaml @@ -0,0 +1,9 @@ +description: New York pays this multiple of the regular market rate for qualifying children with special needs whose costs exceed the regular rate. +values: + 2024-10-01: 1.15 +metadata: + unit: /1 + label: New York CCAP special needs market rate multiplier + reference: + - title: 24-OCFS-LCM-22, market rates for qualifying children with special needs + href: https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=7 diff --git a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/weekly.yaml b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/weekly.yaml index aa49b0b0032..4c420badd5c 100644 --- a/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/weekly.yaml +++ b/policyengine_us/parameters/gov/states/ny/ocfs/ccap/rates/weekly.yaml @@ -182,15 +182,17 @@ GROUP_4: 2024-10-01: 211 SCHOOL_AGE: 2024-10-01: 188 + # Group 4 contains only New York City. ACS chose 75% of the + # registered family day care rate for enhanced informal providers. LE_ENH: INFANT: - 2024-10-01: 280 + 2024-10-01: 300 TODDLER: - 2024-10-01: 245 + 2024-10-01: 263 PRESCHOOLER: - 2024-10-01: 228 + 2024-10-01: 244 SCHOOL_AGE: - 2024-10-01: 202 + 2024-10-01: 217 metadata: propagate_metadata_to_children: true @@ -204,3 +206,5 @@ metadata: reference: - title: 24-OCFS-LCM-22 Attachment A, weekly market rates for county Groups 1-4 (file pages 15-18), effective October 1, 2024 href: https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=15 + - title: NYC ACS FS-023, revised October 2024 + href: https://www.nyc.gov/assets/acs/pdf/earlycare/2024/FS023.pdf#page=2 diff --git a/policyengine_us/programs.yaml b/policyengine_us/programs.yaml index 7073cd8b37e..ac113bff697 100644 --- a/policyengine_us/programs.yaml +++ b/policyengine_us/programs.yaml @@ -875,7 +875,7 @@ programs: full_name: New York Child Care Assistance Program variable: ny_ccap parameter_prefix: gov.states.ny.ocfs.ccap - notes: PolicyEngine models New York income eligibility, market rates, and the family share. It includes the categorical routes for foster care, protective services and preventive care with district approval under Title XX. It applies public assistance activity conditions and the 18 NYCRR 415.1(b) age extensions for special needs and court supervision. It also applies the statutory family share exceptions for public assistance, preventive care and child-only units. The model prices excess periods for a sixth or seventh day of care, and for each day of care at or above the daily maximum hours, at the applicable daily or part-day rate under 24-OCFS-LCM-22. Without a county or county FIPS input, the model places a New York household in Albany County, in county group 2. That placement overstates rates for households in the 38 group 3 counties and understates them in New York City and the five group 1 counties. An UNKNOWN county falls to group 3, the lowest-rate group. The benefit requires childcare_hours_per_day and childcare_days_per_week as well as expenses, because OCFS sets market rates by duration of care; expenses alone yield no benefit. OCFS dropped hourly market rates on June 1, 2022 (22-OCFS-LCM-14); 18 NYCRR 415.9 and 24-OCFS-LCM-22 set weekly, daily and part-day rates only. Not modeled - the mandatory non-traditional-hours and homelessness payment differentials required by 18 NYCRR 415.9(f)(2)-(3) and the discretionary accreditation differential, the special-needs substituted market rate under 415.9(h)(4), and public assistance in countable income (omitted to avoid a circular dependency through the TANF dependent care deduction) + notes: PolicyEngine models New York income eligibility, market rates, payment differentials, the special-needs rate, New York City enhanced informal and group rates, and the family share. It includes the categorical routes for foster care, protective services and preventive care with district approval under Title XX. It applies public assistance activity conditions and the 18 NYCRR 415.1(b) age extensions for special needs and court supervision. It also applies the statutory family share exceptions for public assistance, preventive care and child-only units. The model prices excess periods for a sixth or seventh day of care, and for each day of care at or above the daily maximum hours, at the applicable daily or part-day rate under 24-OCFS-LCM-22. Without a county or county FIPS input, the model places a New York household in Albany County, in county group 2. That placement overstates rates for households in the 38 group 3 counties and understates them in New York City and the five group 1 counties. An UNKNOWN county falls to group 3, the lowest-rate group. The benefit requires childcare_hours_per_day and childcare_days_per_week as well as expenses, because OCFS sets market rates by duration of care; expenses alone yield no benefit. OCFS dropped hourly market rates on June 1, 2022 (22-OCFS-LCM-14); 18 NYCRR 415.9 and 24-OCFS-LCM-22 set weekly, daily and part-day rates only. Outside its New York City and Monroe County rates, the model uses state defaults for district choices, with the minimum for mandatory differentials (5%, then 10% from April 1, 2025, under Social Services Law 410-x(10)) and zero for optional ones. The combined limit rises from 25% to 35% on December 24, 2025. Not modeled - the optional differentials for QUALITYstarsNY and the auto-injector initiative that OCFS added on December 24, 2025, Monroe County's 75% enhanced informal rate, and public assistance in countable income (omitted to avoid a circular dependency through the TANF dependent care deduction) - state: OR status: complete name: Oregon ERDC diff --git a/policyengine_us/tests/core/test_ny_ccap_rates_invariants.py b/policyengine_us/tests/core/test_ny_ccap_rates_invariants.py new file mode 100644 index 00000000000..b1eece4f657 --- /dev/null +++ b/policyengine_us/tests/core/test_ny_ccap_rates_invariants.py @@ -0,0 +1,455 @@ +"""Check New York CCAP rate and payment bounds in batched populations. + +Hypothesis varies county groups, providers, age bands, schedules, expenses, +eligibility and family shares. Each household has twins for the payment +flags and special-needs expense boundaries. Published rate-period counts +supply the legacy reference without calling the new rate formulas. + +Python checks relationships across those twins and the person-to-SPM-unit +aggregation. YAML cases separately pin the published dollar amounts and +expense allocation. Simulations reuse the imported tax-benefit system; +three examples each calculate one population for January 2025. +""" + +import numpy as np +from hypothesis import HealthCheck, given, settings +from hypothesis import strategies as st + +from policyengine_us import Simulation +from policyengine_us.system import system + +YEAR = 2025 +MONTH = "2025-01" +TOLERANCE = dict(atol=0.01, rtol=3e-7) +GROUPS = ("GROUP_1", "GROUP_2", "GROUP_3", "GROUP_4") +PROVIDERS = ("DCC_SACC", "FDC_GFDC", "LE_GC", "LE_STD", "LE_ENH") +AGES = ("INFANT", "TODDLER", "PRESCHOOLER", "SCHOOL_AGE") +# Each schedule records hours/day, days/week and the published rate periods. +# At 12 hours, each day earns a further part-day period. At 18 hours, +# each day earns a further daily period; days six and seven also earn one. +SCHEDULES = ( + (0, 0, (0, 0, 0)), + (3, 1, (0, 0, 1)), + (5, 7, (0, 0, 7)), + (6, 4, (0, 4, 0)), + (8, 3, (0, 3, 0)), + (6, 5, (1, 0, 0)), + (8, 7, (1, 2, 0)), + (12, 5, (1, 0, 5)), + (18, 7, (1, 9, 0)), + (8, 5, (1, 0, 0)), +) +LEGACY_NYC_ENHANCED = { + "weekly": (280, 245, 228, 202), + "daily": (56, 49, 46, 42), + "part_day": (37, 33, 30, 28), +} +VARIANTS = ( + "default", + "nontraditional", + "homeless", + "accredited", + "differentials", + "health", + "training", + "enhancements", + "special", + "unqualified", + "at_regular", + "below_regular", + "special_differentials", + "all", +) +FLAGS = { + "ny_ccap_nontraditional_hours": { + "nontraditional", + "differentials", + "special_differentials", + "all", + }, + "ny_ccap_accredited_provider": { + "accredited", + "differentials", + "special_differentials", + "all", + }, + "ny_ccap_enhanced_health": {"health", "enhancements", "all"}, + "ny_ccap_enhanced_training": {"training", "enhancements", "all"}, + "ny_ccap_special_needs_care": { + "special", + "unqualified", + "at_regular", + "below_regular", + "special_differentials", + "all", + }, +} + + +@st.composite +def child(draw): + return { + "provider": draw(st.sampled_from(PROVIDERS)), + "age": draw(st.sampled_from(AGES)), + "schedule": draw(st.integers(0, len(SCHEDULES) - 1)), + "eligible": draw(st.booleans()), + "disabled": draw(st.booleans()), + } + + +@st.composite +def household(draw): + return { + "group": draw(st.sampled_from(GROUPS)), + "children": draw(st.lists(child(), min_size=1, max_size=2)), + "expenses": draw(st.integers(0, 12_000)), + "family_share": draw(st.integers(0, 20_000)), + } + + +def _coverage_households(): + # Every example includes all county/provider pairs and each schedule. + return [ + { + "group": group, + "children": [ + { + "provider": provider, + "age": AGES[(group_index + provider_index) % len(AGES)], + "schedule": (group_index * len(PROVIDERS) + provider_index) + % len(SCHEDULES), + "eligible": True, + "disabled": False, + } + ], + "expenses": 10_000, + "family_share": (0, 100, 20_000)[provider_index % 3], + } + for group_index, group in enumerate(GROUPS) + for provider_index, provider in enumerate(PROVIDERS) + ] + [ + { + "group": "GROUP_4", + "children": [ + { + "provider": "LE_GC", + "age": "PRESCHOOLER", + "schedule": SCHEDULES.index((8, 5, (1, 0, 0))), + "eligible": True, + "disabled": False, + } + ], + "expenses": 10_000, + "family_share": 0, + } + ] + + +def _table_rate(parameters, group, provider, age, schedule, legacy=False): + counts = SCHEDULES[schedule][2] + total = 0 + for table_name, count in zip(("weekly", "daily", "part_day"), counts): + if legacy and group == "GROUP_4" and provider == "LE_ENH": + cell = LEGACY_NYC_ENHANCED[table_name][AGES.index(age)] + else: + cell = parameters.rates[table_name][group][provider][age] + total += count * cell + # The model converts weekly schedules using 52 weeks and 12 months. + return total * 52 / 12 + + +def _simulate(households, parameters): + situation = { + entity: {} + for entity in ( + "people", + "tax_units", + "marital_units", + "families", + "spm_units", + "households", + ) + } + rows = [] + for household_index, unit in enumerate(households): + for variant in VARIANTS: + unit_name = f"unit_{household_index}_{variant}" + members = [] + child_rows = [] + for index, case in enumerate(unit["children"]): + name = f"{unit_name}_child_{index}" + members.append(name) + regular = _table_rate( + parameters, + unit["group"], + case["provider"], + case["age"], + case["schedule"], + ) + expense = unit["expenses"] + if variant == "at_regular": + expense = regular + elif variant == "below_regular": + expense = regular * 0.75 + disabled = case["disabled"] + if variant in { + "special", + "at_regular", + "below_regular", + "special_differentials", + "all", + }: + disabled = True + elif variant == "unqualified": + disabled = False + hours, days, _ = SCHEDULES[case["schedule"]] + person = { + "age": {YEAR: (1, 2, 4, 8)[AGES.index(case["age"])]}, + "is_disabled": {YEAR: disabled}, + "childcare_provider_type_group": {YEAR: case["provider"]}, + "ny_ccap_age_group": {YEAR: case["age"]}, + "childcare_hours_per_day": {YEAR: hours}, + "childcare_days_per_week": {YEAR: days}, + "ny_ccap_eligible_child": {MONTH: case["eligible"]}, + "ny_ccap_childcare_expenses": {MONTH: expense}, + } + # Omit false inputs so the default twins check their defaults. + for flag, variants in FLAGS.items(): + if variant in variants: + person[flag] = {YEAR: True} + situation["people"][name] = person + situation["marital_units"][name] = {"members": [name]} + child_rows.append( + { + **case, + "person_id": name, + "expense": expense, + "regular": regular, + "special_needs_inputs": disabled + and variant in FLAGS["ny_ccap_special_needs_care"], + "center_table": _table_rate( + parameters, + unit["group"], + "DCC_SACC", + case["age"], + case["schedule"], + ), + "legacy": _table_rate( + parameters, + unit["group"], + case["provider"], + case["age"], + case["schedule"], + legacy=True, + ), + } + ) + for entity in ("tax_units", "families", "spm_units"): + situation[entity][unit_name] = {"members": members} + situation["spm_units"][unit_name].update( + { + "ny_ccap_family_share": {MONTH: unit["family_share"]}, + "spm_unit_pre_subsidy_childcare_expenses": { + YEAR: unit["expenses"] + * 12 + * sum( + SCHEDULES[case["schedule"]][0] > 0 + for case in unit["children"] + ) + }, + } + ) + situation["households"][unit_name] = { + "members": members, + "state_code": {YEAR: "NY"}, + "ny_ccap_county_group": {YEAR: unit["group"]}, + "is_homeless": { + YEAR: variant + in {"homeless", "differentials", "special_differentials", "all"} + }, + } + rows.append( + { + **unit, + "spm_id": unit_name, + "variant": variant, + "children": child_rows, + } + ) + simulation = Simulation(situation=situation, tax_benefit_system=system) + person_indices = { + str(person_id): index for index, person_id in enumerate(simulation.persons.ids) + } + spm_indices = { + str(spm_id): index + for index, spm_id in enumerate(simulation.populations["spm_unit"].ids) + } + for row in rows: + row["spm_index"] = spm_indices[row["spm_id"]] + for case in row["children"]: + case["person_index"] = person_indices[case["person_id"]] + # Match the actual float32 ceiling at the expense threshold. Supplying a + # partial regular-rate input would replace every omitted person's formula + # with the variable's zero default, so leave regular rates as calculations. + regular = simulation.calculate("ny_ccap_regular_market_rate", MONTH) + expenses = simulation.calculate("ny_ccap_childcare_expenses", MONTH).copy() + for row in rows: + if row["variant"] == "at_regular": + for case in row["children"]: + index = case["person_index"] + case["expense"] = expenses[index] = regular[index] + simulation.set_input("ny_ccap_childcare_expenses", MONTH, expenses) + return simulation, rows + + +@settings( + max_examples=3, + deadline=None, + derandomize=True, + suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], +) +@given(st.lists(household(), min_size=3, max_size=8)) +def test_ny_ccap_rate_and_payment_invariants(generated): + parameters = system.parameters(f"{MONTH}-01").gov.states.ny.ocfs.ccap + multiplier = parameters.rates.special_needs_multiplier + simulation, rows = _simulate(_coverage_households() + generated, parameters) + + def calc(variable, period=MONTH): + return np.asarray(simulation.calculate(variable, period), dtype=float) + + regular = calc("ny_ccap_regular_market_rate") + market = calc("ny_ccap_market_rate") + expenses = calc("ny_ccap_childcare_expenses") + payment = calc("ny_ccap_payment_rate") + center = calc("ny_ccap_day_care_center_rate") + special_needs = calc("ny_ccap_special_needs_rate_eligible").astype(bool) + differential = calc("ny_ccap_differential") + benefit = calc("ny_ccap") + default_indices = [ + case["person_index"] + for row in rows + if row["variant"] == "default" + for case in row["children"] + ] + for flag in FLAGS: + assert not calc(flag, YEAR)[default_indices].any(), f"default flag: {flag}" + assert np.isfinite(benefit).all() and (benefit >= 0).all(), "nonnegative benefits" + assert (payment >= 0).all(), "nonnegative payment rates" + assert ((differential >= 0) & (differential <= 0.25 + 1e-7)).all(), ( + "differential bounds" + ) + # Every payment stays within the ordinary 25% differential ceiling. + assert (payment <= np.minimum(expenses, market) * 1.25 + 0.01).all(), ( + "payment bounds" + ) + + for row in rows: + row_index = row["spm_index"] + context = f"{row['spm_id']}: group={row['group']}, children={row['children']}" + indices = [case["person_index"] for case in row["children"]] + counted = np.array( + [ + case["eligible"] and SCHEDULES[case["schedule"]][0] > 0 + for case in row["children"] + ] + ) + np.testing.assert_allclose( + benefit[row_index], + max(payment[indices][counted].sum() - row["family_share"], 0), + err_msg=f"payment aggregation: {context}", + **TOLERANCE, + ) + for case in row["children"]: + i = case["person_index"] + # The special-needs rate needs disability, the parent's showing + # and expenses above the regular rate. + assert special_needs[i] == ( + case["special_needs_inputs"] and expenses[i] > regular[i] + ), f"special-needs eligibility: {context}" + if case["provider"] == "LE_GC": + # A qualifying child's center rate rises to the special-needs rate. + np.testing.assert_allclose( + center[i], + case["center_table"] * (multiplier if special_needs[i] else 1), + err_msg=f"group payment cap rate: {context}", + **TOLERANCE, + ) + assert payment[i] <= center[i] + 0.01, f"group payment cap: {context}" + if row["variant"] == "default": + if row["group"] == "GROUP_4" and case["provider"] == "LE_ENH": + # ACS's 75% informal rate intentionally exceeds main's 70%. + assert market[i] >= case["legacy"] - 0.01, ( + f"NYC enhancement: {context}" + ) + else: + np.testing.assert_allclose( + market[i], + case["legacy"], + err_msg=f"default market: {context}", + **TOLERANCE, + ) + np.testing.assert_allclose( + regular[i], + case["regular"], + err_msg=f"regular rate: {context}", + **TOLERANCE, + ) + if row["variant"] in {"special", "special_differentials", "all"}: + expected = regular[i] * (multiplier if expenses[i] > regular[i] else 1) + np.testing.assert_allclose( + market[i], + expected, + err_msg=f"special-needs substitution: {context}", + **TOLERANCE, + ) + elif row["variant"] in {"unqualified", "at_regular", "below_regular"}: + np.testing.assert_allclose( + market[i], + regular[i], + err_msg=f"special-needs exclusion: {context}", + **TOLERANCE, + ) + if row["variant"] == "default": + legacy_payment = sum( + min(case["expense"], case["legacy"]) + for case, eligible in zip(row["children"], counted) + if eligible + ) + legacy_benefit = max(legacy_payment - row["family_share"], 0) + has_nyc_enhanced = row["group"] == "GROUP_4" and any( + case["provider"] == "LE_ENH" for case in row["children"] + ) + if has_nyc_enhanced: + assert benefit[row_index] >= legacy_benefit - 0.01, ( + f"NYC benefit: {context}" + ) + else: + np.testing.assert_allclose( + benefit[row_index], + legacy_benefit, + err_msg=f"default benefit: {context}", + **TOLERANCE, + ) + + # Each twin uses the same expenses, care and family share as its default. + for start in range(0, len(rows), len(VARIANTS)): + base = rows[start] + base_indices = [case["person_index"] for case in base["children"]] + for variant in ( + "nontraditional", + "homeless", + "accredited", + "differentials", + "health", + "training", + "enhancements", + "all", + ): + position = start + VARIANTS.index(variant) + indices = [case["person_index"] for case in rows[position]["children"]] + context = f"{base['spm_id']} -> {rows[position]['spm_id']}" + assert (payment[indices] >= payment[base_indices] - 0.01).all(), context + assert ( + benefit[rows[position]["spm_index"]] + >= benefit[base["spm_index"]] - 0.01 + ), context diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/ocfs/ccap/integration.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/ocfs/ccap/integration.yaml index 7667e070c45..f5641ea168b 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ny/ocfs/ccap/integration.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/ocfs/ccap/integration.yaml @@ -95,12 +95,12 @@ ny_ccap_county_group: GROUP_4 ny_ccap_age_group: SCHOOL_AGE ny_ccap_duration_of_care: PART_DAY - # Market rate: $28/part-day * 3 days/week * 52 / 12. - ny_ccap_market_rate: 28 * 3 * 52 / 12 + # ACS FS-023: $30/part-day * 3 days/week * 52 / 12 = $390. + ny_ccap_market_rate: 30 * 3 * 52 / 12 ny_ccap_family_share: 52 / 12 - ny_ccap: (28 * 3 * 52 - 52) / 12 - ny_child_care_subsidies: (28 * 3 * 52 - 52) / 12 - child_care_subsidies: (28 * 3 * 52 - 52) / 12 + ny_ccap: (30 * 3 * 52 - 52) / 12 + ny_child_care_subsidies: (30 * 3 * 52 - 52) / 12 + child_care_subsidies: (30 * 3 * 52 - 52) / 12 absolute_error_margin: 0.01 # The activity test is the sole cause of ineligibility here: hhs_smi is set diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/ocfs/ccap/rates/ny_ccap_market_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/ocfs/ccap/rates/ny_ccap_market_rate.yaml index 50e1131d4de..3957d5b52b3 100644 --- a/policyengine_us/tests/policy/baseline/gov/states/ny/ocfs/ccap/rates/ny_ccap_market_rate.yaml +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/ocfs/ccap/rates/ny_ccap_market_rate.yaml @@ -196,3 +196,766 @@ output: ny_ccap_market_rate: 0 absolute_error_margin: 0.01 + +# ACS FS-023 pays $300 per weekly period. +# One such period per week gives $300 * 52 / 12 monthly. +- name: NYC enhanced informal care pays the published weekly rate for infant care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_ENH + ny_ccap_age_group: INFANT + ny_ccap_duration_of_care: WEEKLY + childcare_days_per_week: 1 + output: + ny_ccap_regular_market_rate: 300 * 52 / 12 + ny_ccap_market_rate: 300 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $263 per weekly period. +# One such period per week gives $263 * 52 / 12 monthly. +- name: NYC enhanced informal care pays the published weekly rate for toddler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_ENH + ny_ccap_age_group: TODDLER + ny_ccap_duration_of_care: WEEKLY + childcare_days_per_week: 1 + output: + ny_ccap_regular_market_rate: 263 * 52 / 12 + ny_ccap_market_rate: 263 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $244 per weekly period. +# One such period per week gives $244 * 52 / 12 monthly. +- name: NYC enhanced informal care pays the published weekly rate for preschooler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_ENH + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: WEEKLY + childcare_days_per_week: 1 + output: + ny_ccap_regular_market_rate: 244 * 52 / 12 + ny_ccap_market_rate: 244 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $217 per weekly period. +# One such period per week gives $217 * 52 / 12 monthly. +- name: NYC enhanced informal care pays the published weekly rate for school-age care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_ENH + ny_ccap_age_group: SCHOOL_AGE + ny_ccap_duration_of_care: WEEKLY + childcare_days_per_week: 1 + output: + ny_ccap_regular_market_rate: 217 * 52 / 12 + ny_ccap_market_rate: 217 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $60 per daily period. +# One such period per week gives $60 * 52 / 12 monthly. +- name: NYC enhanced informal care pays the published daily rate for infant care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_ENH + ny_ccap_age_group: INFANT + ny_ccap_duration_of_care: DAILY + childcare_days_per_week: 1 + output: + ny_ccap_regular_market_rate: 60 * 52 / 12 + ny_ccap_market_rate: 60 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $53 per daily period. +# One such period per week gives $53 * 52 / 12 monthly. +- name: NYC enhanced informal care pays the published daily rate for toddler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_ENH + ny_ccap_age_group: TODDLER + ny_ccap_duration_of_care: DAILY + childcare_days_per_week: 1 + output: + ny_ccap_regular_market_rate: 53 * 52 / 12 + ny_ccap_market_rate: 53 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $49 per daily period. +# One such period per week gives $49 * 52 / 12 monthly. +- name: NYC enhanced informal care pays the published daily rate for preschooler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_ENH + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: DAILY + childcare_days_per_week: 1 + output: + ny_ccap_regular_market_rate: 49 * 52 / 12 + ny_ccap_market_rate: 49 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $45 per daily period. +# One such period per week gives $45 * 52 / 12 monthly. +- name: NYC enhanced informal care pays the published daily rate for school-age care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_ENH + ny_ccap_age_group: SCHOOL_AGE + ny_ccap_duration_of_care: DAILY + childcare_days_per_week: 1 + output: + ny_ccap_regular_market_rate: 45 * 52 / 12 + ny_ccap_market_rate: 45 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $40 per part-day period. +# One such period per week gives $40 * 52 / 12 monthly. +- name: NYC enhanced informal care pays the published part-day rate for infant care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_ENH + ny_ccap_age_group: INFANT + ny_ccap_duration_of_care: PART_DAY + childcare_days_per_week: 1 + output: + ny_ccap_regular_market_rate: 40 * 52 / 12 + ny_ccap_market_rate: 40 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $35 per part-day period. +# One such period per week gives $35 * 52 / 12 monthly. +- name: NYC enhanced informal care pays the published part-day rate for toddler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_ENH + ny_ccap_age_group: TODDLER + ny_ccap_duration_of_care: PART_DAY + childcare_days_per_week: 1 + output: + ny_ccap_regular_market_rate: 35 * 52 / 12 + ny_ccap_market_rate: 35 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $32 per part-day period. +# One such period per week gives $32 * 52 / 12 monthly. +- name: NYC enhanced informal care pays the published part-day rate for preschooler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_ENH + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: PART_DAY + childcare_days_per_week: 1 + output: + ny_ccap_regular_market_rate: 32 * 52 / 12 + ny_ccap_market_rate: 32 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $30 per part-day period. +# One such period per week gives $30 * 52 / 12 monthly. +- name: NYC enhanced informal care pays the published part-day rate for school-age care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_ENH + ny_ccap_age_group: SCHOOL_AGE + ny_ccap_duration_of_care: PART_DAY + childcare_days_per_week: 1 + output: + ny_ccap_regular_market_rate: 30 * 52 / 12 + ny_ccap_market_rate: 30 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $356 per weekly period with health. +# One such period per week gives $356 * 52 / 12 monthly. +- name: NYC exempt group care receives the weekly health rate for preschooler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: WEEKLY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + output: + ny_ccap_regular_market_rate: 356 * 52 / 12 + ny_ccap_market_rate: 356 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $263 per weekly period with health. +# One such period per week gives $263 * 52 / 12 monthly. +- name: NYC exempt group care receives the weekly health rate for school-age care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: SCHOOL_AGE + ny_ccap_duration_of_care: WEEKLY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + output: + ny_ccap_regular_market_rate: 263 * 52 / 12 + ny_ccap_market_rate: 263 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $73 per daily period with health. +# One such period per week gives $73 * 52 / 12 monthly. +- name: NYC exempt group care receives the daily health rate for preschooler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: DAILY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + output: + ny_ccap_regular_market_rate: 73 * 52 / 12 + ny_ccap_market_rate: 73 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $56 per daily period with health. +# One such period per week gives $56 * 52 / 12 monthly. +- name: NYC exempt group care receives the daily health rate for school-age care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: SCHOOL_AGE + ny_ccap_duration_of_care: DAILY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + output: + ny_ccap_regular_market_rate: 56 * 52 / 12 + ny_ccap_market_rate: 56 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $49 per part-day period with health. +# One such period per week gives $49 * 52 / 12 monthly. +- name: NYC exempt group care receives the part-day health rate for preschooler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: PART_DAY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + output: + ny_ccap_regular_market_rate: 49 * 52 / 12 + ny_ccap_market_rate: 49 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $37 per part-day period with health. +# One such period per week gives $37 * 52 / 12 monthly. +- name: NYC exempt group care receives the part-day health rate for school-age care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: SCHOOL_AGE + ny_ccap_duration_of_care: PART_DAY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + output: + ny_ccap_regular_market_rate: 37 * 52 / 12 + ny_ccap_market_rate: 37 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $356 per weekly period with training. +# One such period per week gives $356 * 52 / 12 monthly. +- name: NYC exempt group care receives the weekly training rate for preschooler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: WEEKLY + childcare_days_per_week: 1 + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 356 * 52 / 12 + ny_ccap_market_rate: 356 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $263 per weekly period with training. +# One such period per week gives $263 * 52 / 12 monthly. +- name: NYC exempt group care receives the weekly training rate for school-age care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: SCHOOL_AGE + ny_ccap_duration_of_care: WEEKLY + childcare_days_per_week: 1 + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 263 * 52 / 12 + ny_ccap_market_rate: 263 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $73 per daily period with training. +# One such period per week gives $73 * 52 / 12 monthly. +- name: NYC exempt group care receives the daily training rate for preschooler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: DAILY + childcare_days_per_week: 1 + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 73 * 52 / 12 + ny_ccap_market_rate: 73 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $56 per daily period with training. +# One such period per week gives $56 * 52 / 12 monthly. +- name: NYC exempt group care receives the daily training rate for school-age care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: SCHOOL_AGE + ny_ccap_duration_of_care: DAILY + childcare_days_per_week: 1 + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 56 * 52 / 12 + ny_ccap_market_rate: 56 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $49 per part-day period with training. +# One such period per week gives $49 * 52 / 12 monthly. +- name: NYC exempt group care receives the part-day training rate for preschooler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: PART_DAY + childcare_days_per_week: 1 + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 49 * 52 / 12 + ny_ccap_market_rate: 49 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $37 per part-day period with training. +# One such period per week gives $37 * 52 / 12 monthly. +- name: NYC exempt group care receives the part-day training rate for school-age care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: SCHOOL_AGE + ny_ccap_duration_of_care: PART_DAY + childcare_days_per_week: 1 + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 37 * 52 / 12 + ny_ccap_market_rate: 37 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $382 per weekly period with health and training. +# One such period per week gives $382 * 52 / 12 monthly. +- name: NYC exempt group care receives the weekly health and training rate for preschooler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: WEEKLY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 382 * 52 / 12 + ny_ccap_market_rate: 382 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $283 per weekly period with health and training. +# One such period per week gives $283 * 52 / 12 monthly. +- name: NYC exempt group care receives the weekly health and training rate for school-age care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: SCHOOL_AGE + ny_ccap_duration_of_care: WEEKLY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 283 * 52 / 12 + ny_ccap_market_rate: 283 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $78 per daily period with health and training. +# One such period per week gives $78 * 52 / 12 monthly. +- name: NYC exempt group care receives the daily health and training rate for preschooler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: DAILY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 78 * 52 / 12 + ny_ccap_market_rate: 78 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $60 per daily period with health and training. +# One such period per week gives $60 * 52 / 12 monthly. +- name: NYC exempt group care receives the daily health and training rate for school-age care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: SCHOOL_AGE + ny_ccap_duration_of_care: DAILY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 60 * 52 / 12 + ny_ccap_market_rate: 60 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $52 per part-day period with health and training. +# One such period per week gives $52 * 52 / 12 monthly. +- name: NYC exempt group care receives the part-day health and training rate for preschooler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: PART_DAY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 52 * 52 / 12 + ny_ccap_market_rate: 52 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 pays $40 per part-day period with health and training. +# One such period per week gives $40 * 52 / 12 monthly. +- name: NYC exempt group care receives the part-day health and training rate for school-age care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: SCHOOL_AGE + ny_ccap_duration_of_care: PART_DAY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 40 * 52 / 12 + ny_ccap_market_rate: 40 * 52 / 12 + absolute_error_margin: 0.01 + +# ACS FS-023 publishes $0 for exempt group care under age three. +- name: NYC enhanced exempt group weekly care pays zero for infant care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: INFANT + ny_ccap_duration_of_care: WEEKLY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 0 + ny_ccap_market_rate: 0 + absolute_error_margin: 0.01 + +# ACS FS-023 publishes $0 for exempt group care under age three. +- name: NYC enhanced exempt group weekly care pays zero for toddler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: TODDLER + ny_ccap_duration_of_care: WEEKLY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 0 + ny_ccap_market_rate: 0 + absolute_error_margin: 0.01 + +# ACS FS-023 publishes $0 for exempt group care under age three. +- name: NYC enhanced exempt group daily care pays zero for infant care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: INFANT + ny_ccap_duration_of_care: DAILY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 0 + ny_ccap_market_rate: 0 + absolute_error_margin: 0.01 + +# ACS FS-023 publishes $0 for exempt group care under age three. +- name: NYC enhanced exempt group daily care pays zero for toddler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: TODDLER + ny_ccap_duration_of_care: DAILY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 0 + ny_ccap_market_rate: 0 + absolute_error_margin: 0.01 + +# ACS FS-023 publishes $0 for exempt group care under age three. +- name: NYC enhanced exempt group part-day care pays zero for infant care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: INFANT + ny_ccap_duration_of_care: PART_DAY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 0 + ny_ccap_market_rate: 0 + absolute_error_margin: 0.01 + +# ACS FS-023 publishes $0 for exempt group care under age three. +- name: NYC enhanced exempt group part-day care pays zero for toddler care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: TODDLER + ny_ccap_duration_of_care: PART_DAY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 0 + ny_ccap_market_rate: 0 + absolute_error_margin: 0.01 + +# Outside NYC the state default retains the standard exempt group rate. +# Group 1 preschool care pays $308 * 52 / 12 monthly for one period weekly. +- name: Enhanced health and training retain the standard exempt group weekly rate outside NYC. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_1 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: WEEKLY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 308 * 52 / 12 + ny_ccap_market_rate: 308 * 52 / 12 + absolute_error_margin: 0.01 + +# Outside NYC the state default retains the standard exempt group rate. +# Group 1 preschool care pays $64 * 52 / 12 monthly for one period weekly. +- name: Enhanced health and training retain the standard exempt group daily rate outside NYC. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_1 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: DAILY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 64 * 52 / 12 + ny_ccap_market_rate: 64 * 52 / 12 + absolute_error_margin: 0.01 + +# Outside NYC the state default retains the standard exempt group rate. +# Group 1 preschool care pays $43 * 52 / 12 monthly for one period weekly. +- name: Enhanced health and training retain the standard exempt group part-day rate outside NYC. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_1 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: PART_DAY + childcare_days_per_week: 1 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_regular_market_rate: 43 * 52 / 12 + ny_ccap_market_rate: 43 * 52 / 12 + absolute_error_margin: 0.01 + +# $900 expenses do not satisfy every condition for the $1,150 rate. +- name: Costs below the regular rate retain the regular market rate. + period: 2025-01 + input: + state_code: NY + ny_ccap_regular_market_rate: 1_000 + ny_ccap_childcare_expenses: 900 + is_disabled: true + ny_ccap_special_needs_care: true + output: + ny_ccap_market_rate: 1_000 + absolute_error_margin: 0.01 + +# $1,000 expenses do not satisfy every condition for the $1,150 rate. +- name: Costs equal to the regular rate retain the regular market rate. + period: 2025-01 + input: + state_code: NY + ny_ccap_regular_market_rate: 1_000 + ny_ccap_childcare_expenses: 1_000 + is_disabled: true + ny_ccap_special_needs_care: true + output: + ny_ccap_market_rate: 1_000 + absolute_error_margin: 0.01 + +# $1,000 * 1.15 = $1,150. +- name: Qualifying needs and costs above the regular rate receive fifteen percent more. + period: 2025-01 + input: + state_code: NY + ny_ccap_regular_market_rate: 1_000 + ny_ccap_childcare_expenses: 1_001 + is_disabled: true + ny_ccap_special_needs_care: true + output: + ny_ccap_market_rate: 1_150 + absolute_error_margin: 0.01 + +# $2,000 expenses do not satisfy every condition for the $1,150 rate. +- name: A child without a disability retains the regular rate at the same high cost. + period: 2025-01 + input: + state_code: NY + ny_ccap_regular_market_rate: 1_000 + ny_ccap_childcare_expenses: 2_000 + is_disabled: false + ny_ccap_special_needs_care: true + output: + ny_ccap_market_rate: 1_000 + absolute_error_margin: 0.01 + +# $2,000 expenses do not satisfy every condition for the $1,150 rate. +- name: A parent who has not shown the additional care need retains the regular rate. + period: 2025-01 + input: + state_code: NY + ny_ccap_regular_market_rate: 1_000 + ny_ccap_childcare_expenses: 2_000 + is_disabled: true + ny_ccap_special_needs_care: false + output: + ny_ccap_market_rate: 1_000 + absolute_error_margin: 0.01 + +# Six eight-hour days earn the enhanced $382 weekly rate and $78 daily rate. +# ($382 + $78) * 52 / 12 = $1,993.33 monthly. +- name: NYC enhanced group care prices an excess day at its enhanced daily rate. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + childcare_hours_per_day: 8 + childcare_days_per_week: 6 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_duration_of_care: WEEKLY + ny_ccap_regular_market_rate: (382 + 78) * 52 / 12 + ny_ccap_market_rate: (382 + 78) * 52 / 12 + absolute_error_margin: 0.01 + +# Five sixteen-hour days earn $382 plus five enhanced $52 part-day periods. +# ($382 + 5 * $52) * 52 / 12 = $2,782 monthly. +- name: NYC enhanced group care prices excess hours at its enhanced part-day rate. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + childcare_hours_per_day: 16 + childcare_days_per_week: 5 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + output: + ny_ccap_duration_of_care: WEEKLY + ny_ccap_regular_market_rate: (382 + 5 * 52) * 52 / 12 + ny_ccap_market_rate: (382 + 5 * 52) * 52 / 12 + absolute_error_margin: 0.01 diff --git a/policyengine_us/tests/policy/baseline/gov/states/ny/ocfs/ccap/rates/ny_ccap_payment_rate.yaml b/policyengine_us/tests/policy/baseline/gov/states/ny/ocfs/ccap/rates/ny_ccap_payment_rate.yaml new file mode 100644 index 00000000000..106d89242ac --- /dev/null +++ b/policyengine_us/tests/policy/baseline/gov/states/ny/ocfs/ccap/rates/ny_ccap_payment_rate.yaml @@ -0,0 +1,832 @@ +# Each set of parameter overrides builds a separate tax-benefit system, so +# the cases below share two sets, each listed in the same order every time: +# - a district that configures nontraditional and homelessness rates of 0, +# a 2% exempt homelessness rate, a 1% accreditation rate and an OCFS +# waiver to 40%; +# - a district that configures 30% for every differential. +# Every other case uses the default parameters. + +# 24-OCFS-LCM-22 applies each differential to min(expenses, market rate). +# $800 * 1.05 = $840, so the district can pay more than the $800 charge. +- name: Nontraditional hours raise payment above a charge below the market rate. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_1 + childcare_provider_type_group: DCC_SACC + ny_ccap_childcare_expenses: 800 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: true + output: + ny_ccap_differential: 0.05 + ny_ccap_payment_rate: 840 + absolute_error_margin: 0.01 + +# min($1,200, $1,000) * 1.05 = $1,050. +- name: Homelessness raises payment for licensed center care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_1 + childcare_provider_type_group: DCC_SACC + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + is_homeless: true + output: + ny_ccap_differential: 0.05 + ny_ccap_payment_rate: 1_050 + absolute_error_margin: 0.01 + +# Registered family providers receive the same mandatory homelessness rate. +# min($1,200, $1,000) * 1.05 = $1,050. +- name: Homelessness raises payment for registered family care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_1 + childcare_provider_type_group: FDC_GFDC + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + is_homeless: true + output: + ny_ccap_differential: 0.05 + ny_ccap_payment_rate: 1_050 + absolute_error_margin: 0.01 + +# The state default pays no optional accreditation differential. +- name: Accreditation alone leaves payment unchanged under the state default. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_1 + childcare_provider_type_group: DCC_SACC + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_accredited_provider: true + output: + ny_ccap_differential: 0 + ny_ccap_payment_rate: 1_000 + absolute_error_margin: 0.01 + +# The state default pays no optional homelessness differential to exempt care. +- name: Homelessness leaves standard exempt informal care unchanged by default. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_1 + childcare_provider_type_group: LE_STD + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + is_homeless: true + output: + ny_ccap_differential: 0 + ny_ccap_payment_rate: 1_000 + absolute_error_margin: 0.01 + +# The nontraditional-hours differential includes exempt providers: +# min($1,200, $1,000) * 1.05 = $1,050. +- name: Nontraditional hours raise payment for enhanced exempt informal care. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_1 + childcare_provider_type_group: LE_ENH + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: true + output: + ny_ccap_differential: 0.05 + ny_ccap_payment_rate: 1_050 + absolute_error_margin: 0.01 + +# Social Services Law 410-x(10) requires at least 10% from April 1, 2025. +# March keeps the 5% minimum: $1,000 * 1.05 = $1,050. +- name: March 2025 keeps the five-percent nontraditional-hours minimum. + period: 2025-03 + input: + state_code: {2025: NY} + ny_ccap_county_group: {2025: GROUP_1} + childcare_provider_type_group: {2025: DCC_SACC} + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: {2025: true} + output: + ny_ccap_differential: 0.05 + ny_ccap_payment_rate: 1_050 + absolute_error_margin: 0.01 + +# April pays the 10% statutory minimum: $1,000 * 1.10 = $1,100. +- name: April 2025 raises the nontraditional-hours minimum to ten percent. + period: 2025-04 + input: + state_code: {2025: NY} + ny_ccap_county_group: {2025: GROUP_1} + childcare_provider_type_group: {2025: DCC_SACC} + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: {2025: true} + output: + ny_ccap_differential: 0.10 + ny_ccap_payment_rate: 1_100 + absolute_error_margin: 0.01 + +# In June 2025, 410-x(10)(b) gives an exempt provider at least 10% for +# nontraditional hours, and 410-x(10)(a) gives licensed or registered +# providers at least 10% for homelessness: $1,000 * 1.10 = $1,100. +# Exempt homelessness care stays optional, at 0% by default. +- name: From April 2025 the mandatory differentials pay at least ten percent. + period: 2025-06 + input: + people: + exempt_nontraditional: + childcare_provider_type_group: {2025: LE_STD} + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: {2025: true} + center_homeless: + childcare_provider_type_group: {2025: DCC_SACC} + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + family_homeless: + childcare_provider_type_group: {2025: FDC_GFDC} + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + exempt_homeless: + childcare_provider_type_group: {2025: LE_STD} + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + households: + exempt_nontraditional: + members: [exempt_nontraditional] + state_code: {2025: NY} + ny_ccap_county_group: {2025: GROUP_1} + center_homeless: + members: [center_homeless] + state_code: {2025: NY} + ny_ccap_county_group: {2025: GROUP_1} + is_homeless: {2025: true} + family_homeless: + members: [family_homeless] + state_code: {2025: NY} + ny_ccap_county_group: {2025: GROUP_1} + is_homeless: {2025: true} + exempt_homeless: + members: [exempt_homeless] + state_code: {2025: NY} + ny_ccap_county_group: {2025: GROUP_1} + is_homeless: {2025: true} + output: + ny_ccap_differential: [0.10, 0.10, 0.10, 0] + ny_ccap_payment_rate: [1_100, 1_100, 1_100, 1_000] + absolute_error_margin: 0.01 + +# For a qualifying child, $1,000 * 1.15 = $1,150 becomes the market rate. +# The district then pays min($2,000, $1,150) * 1.05 = $1,207.50. +- name: Differentials apply after the special-needs market rate. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_1 + childcare_provider_type_group: DCC_SACC + ny_ccap_childcare_expenses: 2_000 + ny_ccap_regular_market_rate: 1_000 + is_disabled: true + ny_ccap_special_needs_care: true + ny_ccap_nontraditional_hours: true + output: + ny_ccap_market_rate: 1_150 + ny_ccap_differential: 0.05 + ny_ccap_payment_rate: 1_207.5 + absolute_error_margin: 0.01 + +# Actual expenses remain the differential base when they fall between the +# regular and special-needs rates: min($1,100, $1,150) * 1.05 = $1,155. +- name: The district applies differentials to costs below the special-needs rate. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_1 + childcare_provider_type_group: DCC_SACC + ny_ccap_childcare_expenses: 1_100 + ny_ccap_regular_market_rate: 1_000 + is_disabled: true + ny_ccap_special_needs_care: true + ny_ccap_nontraditional_hours: true + output: + ny_ccap_market_rate: 1_150 + ny_ccap_payment_rate: 1_155 + absolute_error_margin: 0.01 + +# NYC pays $382 weekly for a group program meeting both enhancements and +# $439 for a center. LCM-22 makes the special-needs rate the market rate for a +# qualifying child, so both rise by 15%: $382 * 1.15 = $439.30 and $439 * 1.15 = $504.85. +# NYC's 15% nontraditional differential gives $439.30 * 1.15 = $505.195, +# above the $504.85 center rate, so the district pays $504.85 * 52 / 12 +# = $2,187.68 monthly. +- name: A special-needs child's exempt group payment stops at the special-needs center rate. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: WEEKLY + ny_ccap_childcare_expenses: 3_000 + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + is_disabled: true + ny_ccap_special_needs_care: true + ny_ccap_nontraditional_hours: true + output: + ny_ccap_regular_market_rate: 382 * 52 / 12 + ny_ccap_special_needs_rate_eligible: true + ny_ccap_market_rate: 382 * 1.15 * 52 / 12 + ny_ccap_differential: 0.15 + ny_ccap_day_care_center_rate: 439 * 1.15 * 52 / 12 + ny_ccap_payment_rate: 439 * 1.15 * 52 / 12 + absolute_error_margin: 0.01 + +# Annual expenses of $12,000 give $1,000 monthly. After the 5% differential +# and one $100 family share, the family receives $1,000 * 1.05 - $100 = $950. +- name: The family receives the differential before subtracting one family share. + period: 2025-01 + input: + people: + child: + ny_ccap_eligible_child: true + childcare_provider_type_group: DCC_SACC + ny_ccap_market_rate: 1_200 + childcare_hours_per_day: 8 + ny_ccap_nontraditional_hours: true + spm_units: + unit: + members: [child] + spm_unit_pre_subsidy_childcare_expenses: 12_000 + ny_ccap_family_share: 100 + households: + household: + members: [child] + state_code: NY + ny_ccap_county_group: GROUP_1 + output: + ny_ccap_childcare_expenses: 1_000 + ny_ccap_payment_rate: 1_050 + ny_ccap: 950 + absolute_error_margin: 0.01 + +# Both children attend paid care, so each keeps $12,000 / 12 / 2 = $500. +# Only the eligible child receives $500 * 1.05 = $525. +- name: An ineligible sibling keeps their expense share when a differential applies. + period: 2025-01 + input: + people: + child: + ny_ccap_eligible_child: true + childcare_provider_type_group: DCC_SACC + ny_ccap_market_rate: 1_200 + childcare_hours_per_day: 8 + ny_ccap_nontraditional_hours: true + sibling: + ny_ccap_eligible_child: false + childcare_provider_type_group: DCC_SACC + ny_ccap_market_rate: 1_200 + childcare_hours_per_day: 8 + spm_units: + unit: + members: [child, sibling] + spm_unit_pre_subsidy_childcare_expenses: 12_000 + ny_ccap_family_share: 0 + households: + household: + members: [child, sibling] + state_code: NY + ny_ccap_county_group: GROUP_1 + output: + ny_ccap_childcare_expenses: [500, 500] + ny_ccap_payment_rate: [525, 500] + ny_ccap: 525 + absolute_error_margin: 0.01 + +# $1,000 * 1.05 - $2,000 falls below zero; the district pays $0. +- name: A family share above care plus the differential cannot produce a negative benefit. + period: 2025-01 + input: + people: + child: + ny_ccap_eligible_child: true + childcare_provider_type_group: DCC_SACC + ny_ccap_market_rate: 1_200 + childcare_hours_per_day: 8 + ny_ccap_nontraditional_hours: true + spm_units: + unit: + members: [child] + spm_unit_pre_subsidy_childcare_expenses: 12_000 + ny_ccap_family_share: 2_000 + households: + household: + members: [child] + state_code: NY + ny_ccap_county_group: GROUP_1 + output: + ny_ccap: 0 + absolute_error_margin: 0.01 + +# NYC elects 15% for nontraditional hours: $1,000 * 1.15 = $1,150. +- name: NYC pays its elected nontraditional-hours differential. + period: 2025-01 + input: + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: DCC_SACC + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: true + output: + ny_ccap_differential: 0.15 + ny_ccap_payment_rate: 1_150 + absolute_error_margin: 0.01 + +# Monroe County elects 10% for accreditation: $1,000 * 1.10 = $1,100. +- name: Monroe County pays its elected accreditation differential. + period: 2025-01 + input: + state_code: NY + county_str: MONROE_COUNTY_NY + childcare_provider_type_group: DCC_SACC + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_accredited_provider: true + output: + ny_ccap_differential: 0.10 + ny_ccap_payment_rate: 1_100 + absolute_error_margin: 0.01 + +# Monroe County elects 5% for exempt care of homeless children: +# $1,000 * 1.05 = $1,050. +- name: Monroe County pays its elected exempt-provider homelessness differential. + period: 2025-01 + input: + state_code: NY + county_str: MONROE_COUNTY_NY + childcare_provider_type_group: LE_STD + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + is_homeless: true + output: + ny_ccap_differential: 0.05 + ny_ccap_payment_rate: 1_050 + absolute_error_margin: 0.01 + +# Monroe's plan took effect November 18, 2024, so November 2024 still uses +# the state defaults. A Monroe center charges $340 weekly for a preschooler, +# $340 * 52 / 12 = $1,473.33 monthly. Homelessness and nontraditional hours +# pay 5% each, and accreditation pays nothing yet: $1,473.33 * 1.10 = +# $1,620.67. Exempt care for a homeless child pays nothing yet: $185 * 52 / 12 +# = $801.67. +- name: Monroe County pays state defaults in November 2024. + period: 2024-11 + input: + people: + center: + childcare_provider_type_group: {2024: DCC_SACC} + ny_ccap_age_group: {2024: PRESCHOOLER} + ny_ccap_duration_of_care: {2024: WEEKLY} + ny_ccap_childcare_expenses: 3_000 + ny_ccap_nontraditional_hours: {2024: true} + ny_ccap_accredited_provider: {2024: true} + exempt: + childcare_provider_type_group: {2024: LE_STD} + ny_ccap_age_group: {2024: PRESCHOOLER} + ny_ccap_duration_of_care: {2024: WEEKLY} + ny_ccap_childcare_expenses: 3_000 + households: + center: + members: [center] + state_code: {2024: NY} + county_str: {2024: MONROE_COUNTY_NY} + is_homeless: {2024: true} + exempt: + members: [exempt] + state_code: {2024: NY} + county_str: {2024: MONROE_COUNTY_NY} + is_homeless: {2024: true} + output: + ny_ccap_market_rate: [1_473.33, 801.67] + ny_ccap_differential: [0.10, 0] + ny_ccap_payment_rate: [1_620.67, 801.67] + absolute_error_margin: 0.01 + +# From December 2024, Monroe adds its 10% accreditation differential: +# 5% + 5% + 10% = 20%, and $1,473.33 * 1.20 = $1,768. +- name: Monroe County adds its accreditation differential from December 2024. + period: 2024-12 + input: + state_code: {2024: NY} + county_str: {2024: MONROE_COUNTY_NY} + childcare_provider_type_group: {2024: DCC_SACC} + ny_ccap_age_group: {2024: PRESCHOOLER} + ny_ccap_duration_of_care: {2024: WEEKLY} + ny_ccap_childcare_expenses: 3_000 + ny_ccap_nontraditional_hours: {2024: true} + ny_ccap_accredited_provider: {2024: true} + is_homeless: {2024: true} + output: + ny_ccap_differential: 0.20 + ny_ccap_payment_rate: 340 * 52 / 12 * 1.20 + absolute_error_margin: 0.01 + +# In June 2025, the 10% statutory minimum applies to homelessness and +# nontraditional hours: 10% + 10% + 10% = 30%, above the 25% limit. +# $1,473.33 * 1.25 = $1,841.67. +- name: Monroe County's combined differential stops at twenty-five percent in June 2025. + period: 2025-06 + input: + state_code: {2025: NY} + county_str: {2025: MONROE_COUNTY_NY} + childcare_provider_type_group: {2025: DCC_SACC} + ny_ccap_age_group: {2025: PRESCHOOLER} + ny_ccap_duration_of_care: {2025: WEEKLY} + ny_ccap_childcare_expenses: 3_000 + ny_ccap_nontraditional_hours: {2025: true} + ny_ccap_accredited_provider: {2025: true} + is_homeless: {2025: true} + output: + ny_ccap_differential: 0.25 + ny_ccap_payment_rate: 340 * 52 / 12 * 1.25 + absolute_error_margin: 0.01 + +# OCFS raised the combined limit to 35% from December 24, 2025, so the full +# 30% applies in January 2026: $1,473.33 * 1.30 = $1,915.33. +- name: Monroe County pays the full thirty percent under the 2026 limit. + period: 2026-01 + input: + state_code: NY + county_str: MONROE_COUNTY_NY + childcare_provider_type_group: DCC_SACC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: WEEKLY + ny_ccap_childcare_expenses: 3_000 + ny_ccap_nontraditional_hours: true + ny_ccap_accredited_provider: true + is_homeless: true + output: + ny_ccap_differential: 0.30 + ny_ccap_payment_rate: 340 * 52 / 12 * 1.30 + absolute_error_margin: 0.01 + +# District with low configured rates and a 40% waiver. +# An elected 1% accreditation rate rises to the 5% accreditation minimum: +# max(.01, .05) = .05; $1,000 * 1.05 = $1,050. +- name: An elected accreditation differential rises to the five-percent minimum. + period: 2025-01 + input: + gov.states.ny.ocfs.ccap.differentials.nontraditional_hours: 0 + gov.states.ny.ocfs.ccap.differentials.homelessness: 0 + gov.states.ny.ocfs.ccap.differentials.legally_exempt_homelessness: 0.02 + gov.states.ny.ocfs.ccap.differentials.accreditation: 0.01 + gov.states.ny.ocfs.ccap.differentials.maximum: 0.40 + state_code: NY + ny_ccap_county_group: GROUP_1 + childcare_provider_type_group: DCC_SACC + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_accredited_provider: true + output: + ny_ccap_differential: 0.05 + ny_ccap_payment_rate: 1_050 + absolute_error_margin: 0.01 + +# District with low configured rates and a 40% waiver, January 2025. +# Configured 0% rates rise to the 5% minimum for nontraditional hours and +# licensed homelessness; the 1% accreditation rate rises to 5%. +# All three: .05 + .05 + .05 = .15; $1,000 * 1.15 = $1,150. +# Exempt homelessness has no minimum, so 2% applies: $1,000 * 1.02 = $1,020. +- name: Configured rates below the 2024 minimums rise to five percent. + period: 2025-01 + input: + gov.states.ny.ocfs.ccap.differentials.nontraditional_hours: 0 + gov.states.ny.ocfs.ccap.differentials.homelessness: 0 + gov.states.ny.ocfs.ccap.differentials.legally_exempt_homelessness: 0.02 + gov.states.ny.ocfs.ccap.differentials.accreditation: 0.01 + gov.states.ny.ocfs.ccap.differentials.maximum: 0.40 + people: + nontraditional: + childcare_provider_type_group: DCC_SACC + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: true + homeless: + childcare_provider_type_group: DCC_SACC + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + all_three: + childcare_provider_type_group: DCC_SACC + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: true + ny_ccap_accredited_provider: true + exempt_homeless: + childcare_provider_type_group: LE_STD + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + households: + nontraditional: + members: [nontraditional] + state_code: NY + ny_ccap_county_group: GROUP_1 + homeless: + members: [homeless] + state_code: NY + ny_ccap_county_group: GROUP_1 + is_homeless: true + all_three: + members: [all_three] + state_code: NY + ny_ccap_county_group: GROUP_1 + is_homeless: true + exempt_homeless: + members: [exempt_homeless] + state_code: NY + ny_ccap_county_group: GROUP_1 + is_homeless: true + output: + ny_ccap_differential: [0.05, 0.05, 0.15, 0.02] + ny_ccap_payment_rate: [1_050, 1_050, 1_150, 1_020] + absolute_error_margin: 0.01 + +# District with low configured rates and a 40% waiver, April 2025. +# The district configures 0%, so it pays the state minimum, 10% from +# April 1, 2025, for nontraditional hours and for licensed homelessness +# care: max(0, .10) = .10; $1,000 * 1.10 = $1,100. +- name: Configured rates below the minimum rise to ten percent in April 2025. + period: 2025-04 + input: + gov.states.ny.ocfs.ccap.differentials.nontraditional_hours: 0 + gov.states.ny.ocfs.ccap.differentials.homelessness: 0 + gov.states.ny.ocfs.ccap.differentials.legally_exempt_homelessness: 0.02 + gov.states.ny.ocfs.ccap.differentials.accreditation: 0.01 + gov.states.ny.ocfs.ccap.differentials.maximum: 0.40 + people: + nontraditional: + childcare_provider_type_group: {2025: DCC_SACC} + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: {2025: true} + homeless: + childcare_provider_type_group: {2025: DCC_SACC} + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + households: + nontraditional: + members: [nontraditional] + state_code: {2025: NY} + ny_ccap_county_group: {2025: GROUP_1} + homeless: + members: [homeless] + state_code: {2025: NY} + ny_ccap_county_group: {2025: GROUP_1} + is_homeless: {2025: true} + output: + ny_ccap_differential: [0.10, 0.10] + ny_ccap_payment_rate: [1_100, 1_100] + absolute_error_margin: 0.01 + +# District with low configured rates and a 40% waiver, June 2025. +# Nontraditional hours and licensed homelessness rise to the 10% minimum, +# while accreditation keeps its 5% minimum. +# All three: .10 + .10 + .05 = .25; $1,000 * 1.25 = $1,250. +- name: Configured rates below the 2025 minimums rise to ten percent, except accreditation. + period: 2025-06 + input: + gov.states.ny.ocfs.ccap.differentials.nontraditional_hours: 0 + gov.states.ny.ocfs.ccap.differentials.homelessness: 0 + gov.states.ny.ocfs.ccap.differentials.legally_exempt_homelessness: 0.02 + gov.states.ny.ocfs.ccap.differentials.accreditation: 0.01 + gov.states.ny.ocfs.ccap.differentials.maximum: 0.40 + people: + nontraditional: + childcare_provider_type_group: {2025: DCC_SACC} + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: {2025: true} + homeless: + childcare_provider_type_group: {2025: DCC_SACC} + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + accredited: + childcare_provider_type_group: {2025: DCC_SACC} + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_accredited_provider: {2025: true} + all_three: + childcare_provider_type_group: {2025: DCC_SACC} + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: {2025: true} + ny_ccap_accredited_provider: {2025: true} + exempt_homeless: + childcare_provider_type_group: {2025: LE_STD} + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + households: + nontraditional: + members: [nontraditional] + state_code: {2025: NY} + ny_ccap_county_group: {2025: GROUP_1} + homeless: + members: [homeless] + state_code: {2025: NY} + ny_ccap_county_group: {2025: GROUP_1} + is_homeless: {2025: true} + accredited: + members: [accredited] + state_code: {2025: NY} + ny_ccap_county_group: {2025: GROUP_1} + all_three: + members: [all_three] + state_code: {2025: NY} + ny_ccap_county_group: {2025: GROUP_1} + is_homeless: {2025: true} + exempt_homeless: + members: [exempt_homeless] + state_code: {2025: NY} + ny_ccap_county_group: {2025: GROUP_1} + is_homeless: {2025: true} + output: + ny_ccap_differential: [0.10, 0.10, 0.05, 0.25, 0.02] + ny_ccap_payment_rate: [1_100, 1_100, 1_050, 1_250, 1_020] + absolute_error_margin: 0.01 + +# District with low configured rates and a 40% waiver, June 2025. +# In Monroe, nontraditional hours and homelessness rise to 10% each and +# accreditation pays Monroe's 10%: .10 + .10 + .10 = .30, within the waived +# limit, so $1,000 * 1.30 = $1,300. Without the waiver it stops at 25%. +- name: An OCFS waiver lets the district pay combined differentials above twenty-five percent. + period: 2025-06 + input: + gov.states.ny.ocfs.ccap.differentials.nontraditional_hours: 0 + gov.states.ny.ocfs.ccap.differentials.homelessness: 0 + gov.states.ny.ocfs.ccap.differentials.legally_exempt_homelessness: 0.02 + gov.states.ny.ocfs.ccap.differentials.accreditation: 0.01 + gov.states.ny.ocfs.ccap.differentials.maximum: 0.40 + state_code: {2025: NY} + county_str: {2025: MONROE_COUNTY_NY} + childcare_provider_type_group: {2025: DCC_SACC} + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: {2025: true} + ny_ccap_accredited_provider: {2025: true} + is_homeless: {2025: true} + output: + ny_ccap_differential: 0.30 + ny_ccap_payment_rate: 1_300 + absolute_error_margin: 0.01 + +# District that configures 30% for every differential, January 2025. +# Each differential stops at 15%. Exempt providers never receive the +# accreditation differential. All three: min(.15 + .15 + .15, .25) = .25, +# so a registered family provider receives $1,000 * 1.25 = $1,250. +- name: Individual and combined maxima limit excessive configured differentials. + period: 2025-01 + input: + gov.states.ny.ocfs.ccap.differentials.nontraditional_hours: 0.30 + gov.states.ny.ocfs.ccap.differentials.homelessness: 0.30 + gov.states.ny.ocfs.ccap.differentials.legally_exempt_homelessness: 0.30 + gov.states.ny.ocfs.ccap.differentials.accreditation: 0.30 + people: + nontraditional: + childcare_provider_type_group: DCC_SACC + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: true + homeless: + childcare_provider_type_group: DCC_SACC + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + accredited: + childcare_provider_type_group: DCC_SACC + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_accredited_provider: true + exempt_homeless: + childcare_provider_type_group: LE_STD + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + exempt_accredited: + childcare_provider_type_group: LE_STD + ny_ccap_childcare_expenses: 1_200 + ny_ccap_market_rate: 1_000 + ny_ccap_accredited_provider: true + all_three: + childcare_provider_type_group: FDC_GFDC + ny_ccap_childcare_expenses: 2_000 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: true + ny_ccap_accredited_provider: true + households: + nontraditional: + members: [nontraditional] + state_code: NY + ny_ccap_county_group: GROUP_1 + homeless: + members: [homeless] + state_code: NY + ny_ccap_county_group: GROUP_1 + is_homeless: true + accredited: + members: [accredited] + state_code: NY + ny_ccap_county_group: GROUP_1 + exempt_homeless: + members: [exempt_homeless] + state_code: NY + ny_ccap_county_group: GROUP_1 + is_homeless: true + exempt_accredited: + members: [exempt_accredited] + state_code: NY + ny_ccap_county_group: GROUP_1 + all_three: + members: [all_three] + state_code: NY + ny_ccap_county_group: GROUP_1 + is_homeless: true + output: + ny_ccap_differential: [0.15, 0.15, 0.15, 0.15, 0, 0.25] + ny_ccap_payment_rate: [1_150, 1_150, 1_150, 1_150, 1_000, 1_250] + absolute_error_margin: 0.01 + +# District that configures 30% for every differential, December 2025. +# The 35% limit took effect December 24, 2025; the monthly model first +# reads it in January 2026. min(.45, .25) = .25; $1,000 * 1.25 = $1,250. +- name: December 2025 keeps the twenty-five percent combined limit. + period: 2025-12 + input: + gov.states.ny.ocfs.ccap.differentials.nontraditional_hours: 0.30 + gov.states.ny.ocfs.ccap.differentials.homelessness: 0.30 + gov.states.ny.ocfs.ccap.differentials.legally_exempt_homelessness: 0.30 + gov.states.ny.ocfs.ccap.differentials.accreditation: 0.30 + state_code: {2025: NY} + ny_ccap_county_group: {2025: GROUP_1} + childcare_provider_type_group: {2025: FDC_GFDC} + ny_ccap_childcare_expenses: 2_000 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: {2025: true} + ny_ccap_accredited_provider: {2025: true} + is_homeless: {2025: true} + output: + ny_ccap_differential: 0.25 + ny_ccap_payment_rate: 1_250 + absolute_error_margin: 0.01 + +# District that configures 30% for every differential, January 2026. +# min(.15 + .15 + .15, .35) = .35; $1,000 * 1.35 = $1,350. +- name: From January 2026 the combined differential stops at thirty-five percent. + period: 2026-01 + input: + gov.states.ny.ocfs.ccap.differentials.nontraditional_hours: 0.30 + gov.states.ny.ocfs.ccap.differentials.homelessness: 0.30 + gov.states.ny.ocfs.ccap.differentials.legally_exempt_homelessness: 0.30 + gov.states.ny.ocfs.ccap.differentials.accreditation: 0.30 + state_code: NY + ny_ccap_county_group: GROUP_1 + childcare_provider_type_group: FDC_GFDC + ny_ccap_childcare_expenses: 2_000 + ny_ccap_market_rate: 1_000 + ny_ccap_nontraditional_hours: true + ny_ccap_accredited_provider: true + is_homeless: true + output: + ny_ccap_differential: 0.35 + ny_ccap_payment_rate: 1_350 + absolute_error_margin: 0.01 + +# District that configures 30% for every differential, January 2025. +# NYC's enhanced group rate pays $382 weekly for both requirements. NYC's +# 15% nontraditional rate plus the exempt homelessness rate, capped at 15%, +# give min(.15 + .15, .25) = .25. min($3,000, $382 * 52 / 12) * 1.25 +# exceeds $439 * 52 / 12, so the district pays the center rate, $1,902.33. +- name: Exempt group payment stops at the center rate after differentials. + period: 2025-01 + input: + gov.states.ny.ocfs.ccap.differentials.nontraditional_hours: 0.30 + gov.states.ny.ocfs.ccap.differentials.homelessness: 0.30 + gov.states.ny.ocfs.ccap.differentials.legally_exempt_homelessness: 0.30 + gov.states.ny.ocfs.ccap.differentials.accreditation: 0.30 + state_code: NY + ny_ccap_county_group: GROUP_4 + childcare_provider_type_group: LE_GC + ny_ccap_age_group: PRESCHOOLER + ny_ccap_duration_of_care: WEEKLY + ny_ccap_childcare_expenses: 3_000 + ny_ccap_nontraditional_hours: true + ny_ccap_enhanced_health: true + ny_ccap_enhanced_training: true + is_homeless: true + output: + ny_ccap_market_rate: 382 * 52 / 12 + ny_ccap_differential: 0.25 + ny_ccap_day_care_center_rate: 439 * 52 / 12 + ny_ccap_payment_rate: 439 * 52 / 12 + absolute_error_margin: 0.01 diff --git a/policyengine_us/tools/ny_ccap.py b/policyengine_us/tools/ny_ccap.py new file mode 100644 index 00000000000..ec0b0292385 --- /dev/null +++ b/policyengine_us/tools/ny_ccap.py @@ -0,0 +1,54 @@ +from policyengine_us.model_api import * + + +def ny_ccap_monthly_rate( + person, period, parameters, weekly_rate, daily_rate, part_day_rate +): + """Price the scheduled and excess care periods under 24-OCFS-LCM-22.""" + p = parameters(period).gov.states.ny.ocfs.ccap + duration = person("ny_ccap_duration_of_care", period.this_year) + durations = duration.possible_values + hours_per_day = person("childcare_hours_per_day", period.this_year) + days_per_week = person("childcare_days_per_week", period.this_year) + base_rate = select( + [ + duration == durations.WEEKLY, + duration == durations.DAILY, + duration == durations.PART_DAY, + ], + [ + weekly_rate, + daily_rate * days_per_week, + part_day_rate * days_per_week, + ], + default=0, + ) + # A weekly rate covers the weekly maximum days; each further day is an + # additional period priced by that day's own hours. + excess_days = where( + duration == durations.WEEKLY, + max_(days_per_week - p.duration.weekly_maximum_days, 0), + 0, + ) + excess_day_rate = where( + hours_per_day >= p.duration.daily_minimum_hours, + daily_rate, + part_day_rate, + ) + # 24-OCFS-LCM-22 sec. III.4: care of 12 hours or more in a day earns + # one further period on each day, priced by the time over 12 hours, + # so a day of exactly 12 hours draws the part-day rate. + reaches_daily_maximum = hours_per_day >= p.duration.daily_maximum_hours + excess_hours = max_(hours_per_day - p.duration.daily_maximum_hours, 0) + excess_hour_rate = where( + excess_hours >= p.duration.daily_minimum_hours, + daily_rate, + part_day_rate, + ) + excess_hour_periods = where(reaches_daily_maximum, days_per_week, 0) + rate_per_week = ( + base_rate + + excess_days * excess_day_rate + + excess_hour_periods * excess_hour_rate + ) + return rate_per_week * (WEEKS_IN_YEAR / MONTHS_IN_YEAR) diff --git a/policyengine_us/variables/gov/states/ny/ocfs/ccap/ny_ccap.py b/policyengine_us/variables/gov/states/ny/ocfs/ccap/ny_ccap.py index 766beea851c..28bfd48e0d4 100644 --- a/policyengine_us/variables/gov/states/ny/ocfs/ccap/ny_ccap.py +++ b/policyengine_us/variables/gov/states/ny/ocfs/ccap/ny_ccap.py @@ -10,32 +10,23 @@ class ny_ccap(Variable): defined_for = StateCode.NY reference = ( "https://ocfs.ny.gov/programs/childcare/regulations/415-Child-Care-Services.pdf#page=39", + # PDF pages 3, 9-10 "https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=3", ) def formula(spm_unit, period, parameters): person = spm_unit.members - market_rate = person("ny_ccap_market_rate", period) # ny_ccap_eligible_child carries New York's income test as well as the # categorical routes that waive it, so no separate income gate is # applied here. eligible = person("ny_ccap_eligible_child", period) in_care = person("childcare_hours_per_day", period.this_year) > 0 counted = eligible & in_care - # The unit's expenses are shared across every child in paid care, so - # an ineligible child's share stays with that child rather than - # raising an eligible sibling against its own rate ceiling. - children_in_care = spm_unit.sum(in_care) - total_expenses = spm_unit("spm_unit_pre_subsidy_childcare_expenses", period) - per_child_expenses = total_expenses / max_(children_in_care, 1) - # 18 NYCRR 415.6(e)(1) and (e)(3): payments do not exceed the actual - # cost of care, and payments per child do not exceed the applicable - # rate for the type of provider used and the age of the child. Capping - # per child rather than on pooled totals stops one child's unused rate - # headroom from absorbing a sibling's above-rate expenses. - reimbursable_care = spm_unit.sum( - min_(spm_unit.project(per_child_expenses), market_rate) * counted - ) + # Each child keeps their expense share, including an ineligible + # sibling's share. Apply differentials after the actual-cost cap so + # a qualifying payment can exceed the provider's charge. + payment = person("ny_ccap_payment_rate", period) + reimbursable_care = spm_unit.sum(payment * counted) # 415.3(e)(5): one family share per family regardless of the number of # children receiving care, so it is subtracted once from the total. family_share = spm_unit("ny_ccap_family_share", period) diff --git a/policyengine_us/variables/gov/states/ny/ocfs/ccap/ny_ccap_childcare_expenses.py b/policyengine_us/variables/gov/states/ny/ocfs/ccap/ny_ccap_childcare_expenses.py new file mode 100644 index 00000000000..02182e5b1de --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/ocfs/ccap/ny_ccap_childcare_expenses.py @@ -0,0 +1,23 @@ +from policyengine_us.model_api import * + + +class ny_ccap_childcare_expenses(Variable): + value_type = float + entity = Person + label = "New York CCAP monthly expenses allocated to the child" + definition_period = MONTH + unit = USD + defined_for = StateCode.NY + documentation = ( + "Allocates family expenses equally among all children in paid care, " + "including children who do not qualify for CCAP. Each child keeps " + "their own expense share when applying the market rate and " + "differentials under 18 NYCRR 415.9." + ) + reference = "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9" + + def formula(person, period, parameters): + in_care = person("childcare_hours_per_day", period.this_year) > 0 + children_in_care = person.spm_unit.sum(in_care) + total = person.spm_unit("spm_unit_pre_subsidy_childcare_expenses", period) + return total / max_(children_in_care, 1) diff --git a/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_accredited_provider.py b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_accredited_provider.py new file mode 100644 index 00000000000..841af35318f --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_accredited_provider.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class ny_ccap_accredited_provider(Variable): + value_type = bool + entity = Person + label = "New York CCAP nationally accredited provider" + definition_period = YEAR + default_value = False + defined_for = StateCode.NY + documentation = ( + "Records whether a nationally recognized child care organization has " + "accredited the child's licensed or registered provider, under 18 " + "NYCRR 415.9 and 24-OCFS-LCM-22. " + ) + reference = ( + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9", + "https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=9", + ) diff --git a/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_day_care_center_rate.py b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_day_care_center_rate.py new file mode 100644 index 00000000000..beb0af3aab7 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_day_care_center_rate.py @@ -0,0 +1,40 @@ +from policyengine_us.model_api import * +from policyengine_us.tools.ny_ccap import ny_ccap_monthly_rate + + +class ny_ccap_day_care_center_rate(Variable): + value_type = float + entity = Person + label = "New York CCAP monthly day care center payment limit" + definition_period = MONTH + unit = USD + defined_for = StateCode.NY + documentation = ( + "Prices the child's schedule at the day care center market rate that " + "applies to the child. A child who qualifies for the special-needs " + "market rate gets that rate here too. 24-OCFS-LCM-22 caps legally " + "exempt group payments at this amount, including enhancements and " + "differentials." + ) + reference = ( + # PDF pages 7, 9 + "https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=7", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ny.ocfs.ccap.rates + county_group = person.household("ny_ccap_county_group", period.this_year) + age_group = person("ny_ccap_age_group", period.this_year) + center_rate = ny_ccap_monthly_rate( + person, + period, + parameters, + p.weekly[county_group]["DCC_SACC"][age_group], + p.daily[county_group]["DCC_SACC"][age_group], + p.part_day[county_group]["DCC_SACC"][age_group], + ) + # LCM-22 makes the special-needs rate the market rate for a + # qualifying child, so the center rate that caps group payments + # rises with it. + special_needs = person("ny_ccap_special_needs_rate_eligible", period) + return center_rate * where(special_needs, p.special_needs_multiplier, 1) diff --git a/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_differential.py b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_differential.py new file mode 100644 index 00000000000..4831e3089ac --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_differential.py @@ -0,0 +1,68 @@ +from policyengine_us.model_api import * + + +class ny_ccap_differential(Variable): + value_type = float + entity = Person + label = "New York CCAP combined payment differential" + definition_period = MONTH + defined_for = StateCode.NY + documentation = ( + "Adds the child's nontraditional-hours, homelessness and eligible " + "provider accreditation differentials, subject to the combined limit. " + "From April 1, 2025, Social Services Law 410-x(10) raises the " + "nontraditional-hours and licensed or registered homelessness minimum " + "from 5% to 10%; an elected accreditation differential keeps its 5% " + "minimum. The default limit assumes no OCFS waiver. Confirmed district " + "rates replace state defaults." + ) + reference = ( + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9", + # PDF pages 9-10 + "https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=9", + "https://www.nysenate.gov/legislation/laws/SOS/410-X", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ny.ocfs.ccap.differentials + provider = person("childcare_provider_type_group", period.this_year) + providers = provider.possible_values + licensed = (provider == providers.DCC_SACC) | (provider == providers.FDC_GFDC) + county = person.household("county_str", period.this_year) + group = person.household("ny_ccap_county_group", period.this_year) + nyc = group == group.possible_values.GROUP_4 + monroe = county == "MONROE_COUNTY_NY" + nontraditional_rate = where( + nyc, p.nyc_nontraditional_hours, p.nontraditional_hours + ) + accreditation_rate = where(monroe, p.monroe_accreditation, p.accreditation) + exempt_homelessness_rate = where( + monroe, p.monroe_legally_exempt_homelessness, p.legally_exempt_homelessness + ) + # Optional accreditation pays zero until a district adopts it, then + # its own minimum and the shared individual maximum apply. + accreditation_rate = where( + accreditation_rate > 0, + min_( + max_(accreditation_rate, p.accreditation_minimum), + p.maximum_individual, + ), + 0, + ) + homelessness_rate = where( + licensed, + min_(max_(p.homelessness, p.minimum), p.maximum_individual), + min_(max_(exempt_homelessness_rate, 0), p.maximum_individual), + ) + nontraditional_rate = min_( + max_(nontraditional_rate, p.minimum), p.maximum_individual + ) + nontraditional = person("ny_ccap_nontraditional_hours", period.this_year) + homeless = person.household("is_homeless", period.this_year) + accredited = person("ny_ccap_accredited_provider", period.this_year) + combined = ( + nontraditional * nontraditional_rate + + homeless * homelessness_rate + + accredited * licensed * accreditation_rate + ) + return min_(combined, p.maximum) diff --git a/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_enhanced_health.py b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_enhanced_health.py new file mode 100644 index 00000000000..ac86b7cbb5c --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_enhanced_health.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class ny_ccap_enhanced_health(Variable): + value_type = bool + entity = Person + label = "New York CCAP legally exempt group enhanced health requirement" + definition_period = YEAR + default_value = False + defined_for = StateCode.NY + documentation = ( + "Records whether the child's enrolled legally exempt group program " + "meets the enhanced health requirement for the district's enhanced " + "market rate, under 24-OCFS-LCM-22 and 18-OCFS-ADM-10. " + ) + reference = ( + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9", + "https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=9", + ) diff --git a/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_enhanced_training.py b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_enhanced_training.py new file mode 100644 index 00000000000..333960de1af --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_enhanced_training.py @@ -0,0 +1,19 @@ +from policyengine_us.model_api import * + + +class ny_ccap_enhanced_training(Variable): + value_type = bool + entity = Person + label = "New York CCAP legally exempt group enhanced training requirement" + definition_period = YEAR + default_value = False + defined_for = StateCode.NY + documentation = ( + "Records whether the child's enrolled legally exempt group program " + "meets the enhanced training requirement for the district's enhanced " + "market rate, under 24-OCFS-LCM-22 and 18-OCFS-ADM-10. " + ) + reference = ( + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9", + "https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=9", + ) diff --git a/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_market_rate.py b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_market_rate.py index d79b2d8affb..7e57349a322 100644 --- a/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_market_rate.py +++ b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_market_rate.py @@ -9,71 +9,22 @@ class ny_ccap_market_rate(Variable): unit = USD defined_for = StateCode.NY documentation = ( - "The applicable market rate ceiling for one child, converted to a " - "monthly amount. Under 18 NYCRR 415.9(d) care exceeding one weekly or " - "daily period earns an additional period, priced at the rate for the " - "amount of time that period covers: the daily rate at or above the " - "daily minimum hours, the part-day rate below it. A weekly schedule " - "earns one additional period per day past the weekly maximum days, " - "and any schedule earns one on each day of care at or above the daily " - "maximum hours." + "Returns the regular monthly rate, including excess care periods " + "and any legally exempt group enhancement. A child with a disability " + "receives the special-needs rate only when the parent demonstrates " + "additional care needs and the child's expense share exceeds the " + "regular rate, under 18 NYCRR 415.9 and 24-OCFS-LCM-22. Payment " + "differentials apply separately to the lesser of expenses and this rate." ) reference = ( - "https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=6", - "https://ocfs.ny.gov/programs/childcare/regulations/415-Child-Care-Services.pdf#page=45", + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9", + "https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=7", ) def formula(person, period, parameters): - p = parameters(period).gov.states.ny.ocfs.ccap - county_group = person.household("ny_ccap_county_group", period.this_year) - provider_type = person("childcare_provider_type_group", period.this_year) - age_group = person("ny_ccap_age_group", period.this_year) - duration = person("ny_ccap_duration_of_care", period.this_year) - durations = duration.possible_values - hours_per_day = person("childcare_hours_per_day", period.this_year) - days_per_week = person("childcare_days_per_week", period.this_year) - weekly_rate = p.rates.weekly[county_group][provider_type][age_group] - daily_rate = p.rates.daily[county_group][provider_type][age_group] - part_day_rate = p.rates.part_day[county_group][provider_type][age_group] - base_rate = select( - [ - duration == durations.WEEKLY, - duration == durations.DAILY, - duration == durations.PART_DAY, - ], - [ - weekly_rate, - daily_rate * days_per_week, - part_day_rate * days_per_week, - ], - default=0, - ) - # A weekly rate covers the weekly maximum days; each further day is an - # additional period priced by that day's own hours. - excess_days = where( - duration == durations.WEEKLY, - max_(days_per_week - p.duration.weekly_maximum_days, 0), - 0, - ) - excess_day_rate = where( - hours_per_day >= p.duration.daily_minimum_hours, - daily_rate, - part_day_rate, - ) - # 24-OCFS-LCM-22 sec. III.4: care of 12 hours or more in a day earns - # one further period on each day, priced by the time over 12 hours, - # so a day of exactly 12 hours draws the part-day rate. - reaches_daily_maximum = hours_per_day >= p.duration.daily_maximum_hours - excess_hours = max_(hours_per_day - p.duration.daily_maximum_hours, 0) - excess_hour_rate = where( - excess_hours >= p.duration.daily_minimum_hours, - daily_rate, - part_day_rate, - ) - excess_hour_periods = where(reaches_daily_maximum, days_per_week, 0) - rate_per_week = ( - base_rate - + excess_days * excess_day_rate - + excess_hour_periods * excess_hour_rate - ) - return rate_per_week * (WEEKS_IN_YEAR / MONTHS_IN_YEAR) + regular = person("ny_ccap_regular_market_rate", period) + qualifies = person("ny_ccap_special_needs_rate_eligible", period) + multiplier = parameters( + period + ).gov.states.ny.ocfs.ccap.rates.special_needs_multiplier + return regular * where(qualifies, multiplier, 1) diff --git a/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_nontraditional_hours.py b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_nontraditional_hours.py new file mode 100644 index 00000000000..70c8e96d64c --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_nontraditional_hours.py @@ -0,0 +1,25 @@ +from policyengine_us.model_api import * + + +class ny_ccap_nontraditional_hours(Variable): + value_type = bool + entity = Person + label = "New York CCAP care during nontraditional hours" + definition_period = YEAR + default_value = False + defined_for = StateCode.NY + documentation = ( + "Records whether the child receives care before 6 a.m. or after " + "7 p.m. Monday through Friday. Any care on Saturday, Sunday, " + "New Year's Day, Memorial Day, Independence Day, Labor Day, " + "Thanksgiving Day, or Christmas Day also qualifies under " + "24-OCFS-LCM-22. Districts pay the differential on care provided " + "during those hours. The inputs don't split a child's care by hour, " + "so the model applies the differential to the child's whole monthly " + "payment whenever a user sets this input." + ) + reference = ( + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9", + "https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=9", + "https://www.nysenate.gov/legislation/laws/SOS/410-X", + ) diff --git a/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_payment_rate.py b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_payment_rate.py new file mode 100644 index 00000000000..4debee622da --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_payment_rate.py @@ -0,0 +1,31 @@ +from policyengine_us.model_api import * + + +class ny_ccap_payment_rate(Variable): + value_type = float + entity = Person + label = "New York CCAP monthly payment before family share" + definition_period = MONTH + unit = USD + defined_for = StateCode.NY + documentation = ( + "Applies the combined differential to the lesser of the child's " + "expenses and applicable market rate. Under 24-OCFS-LCM-22, the " + "result can exceed the provider's charge. Legally exempt group " + "payments cannot exceed the day care center rate that applies to " + "the child, including the special-needs rate." + ) + reference = ( + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9", + "https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=9", + ) + + def formula(person, period, parameters): + expenses = person("ny_ccap_childcare_expenses", period) + market_rate = person("ny_ccap_market_rate", period) + differential = person("ny_ccap_differential", period) + payment = min_(expenses, market_rate) * (1 + differential) + provider = person("childcare_provider_type_group", period.this_year) + group_provider = provider == provider.possible_values.LE_GC + center_rate = person("ny_ccap_day_care_center_rate", period) + return where(group_provider, min_(payment, center_rate), payment) diff --git a/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_regular_market_rate.py b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_regular_market_rate.py new file mode 100644 index 00000000000..bda3763923f --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_regular_market_rate.py @@ -0,0 +1,55 @@ +from policyengine_us.model_api import * +from policyengine_us.tools.ny_ccap import ny_ccap_monthly_rate + + +class ny_ccap_regular_market_rate(Variable): + value_type = float + entity = Person + label = "New York CCAP regular monthly market rate" + definition_period = MONTH + unit = USD + defined_for = StateCode.NY + documentation = ( + "Prices scheduled and excess care periods before the special-needs " + "substitution or payment differentials. New York City pays enhanced " + "legally exempt group rates when the program meets its health or " + "training requirements. Other districts retain standard group rates " + "where no district enhancement has been confirmed." + ) + reference = ( + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9", + # PDF pages 6, 8-9 + "https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=6", + "https://ocfs.ny.gov/programs/childcare/regulations/415-Child-Care-Services.pdf#page=45", + "https://www.nyc.gov/assets/acs/pdf/earlycare/2024/FS023.pdf#page=2", + ) + + def formula(person, period, parameters): + p = parameters(period).gov.states.ny.ocfs.ccap.rates + county_group = person.household("ny_ccap_county_group", period.this_year) + provider_type = person("childcare_provider_type_group", period.this_year) + age_group = person("ny_ccap_age_group", period.this_year) + providers = provider_type.possible_values + health = person("ny_ccap_enhanced_health", period.this_year) + training = person("ny_ccap_enhanced_training", period.this_year) + enhanced_fraction = select( + [health & training, health | training], + [ + p.enhanced_group.both[county_group], + p.enhanced_group.single[county_group], + ], + default=0, + ) + enhanced = (provider_type == providers.LE_GC) & (enhanced_fraction > 0) + # OCFS rounds each enhanced period rate to the nearest whole dollar, + # with a half dollar rounded up. Under-three group rates stay zero. + has_group_rate = p.weekly[county_group]["LE_GC"][age_group] > 0 + period_rates = [] + for table in (p.weekly, p.daily, p.part_day): + standard = table[county_group][provider_type][age_group] + center = table[county_group]["DCC_SACC"][age_group] + enhanced_rate = np.floor(center * enhanced_fraction + 0.5) + period_rates.append( + where(enhanced & has_group_rate, enhanced_rate, standard) + ) + return ny_ccap_monthly_rate(person, period, parameters, *period_rates) diff --git a/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_special_needs_care.py b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_special_needs_care.py new file mode 100644 index 00000000000..ea579f9a48c --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_special_needs_care.py @@ -0,0 +1,21 @@ +from policyengine_us.model_api import * + + +class ny_ccap_special_needs_care(Variable): + value_type = bool + entity = Person + label = "New York CCAP parent demonstrates additional special needs care" + definition_period = YEAR + default_value = False + defined_for = StateCode.NY + documentation = ( + "Records whether the parent or caretaker has demonstrated to the " + "district that the child needs child care services beyond those " + "children of similar age generally require, under 18 NYCRR 415.9 and " + "24-OCFS-LCM-22. The rate also requires disability and expenses " + "exceeding the regular market rate. " + ) + reference = ( + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9", + "https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=7", + ) diff --git a/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_special_needs_rate_eligible.py b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_special_needs_rate_eligible.py new file mode 100644 index 00000000000..e6d9c8502d6 --- /dev/null +++ b/policyengine_us/variables/gov/states/ny/ocfs/ccap/rates/ny_ccap_special_needs_rate_eligible.py @@ -0,0 +1,26 @@ +from policyengine_us.model_api import * + + +class ny_ccap_special_needs_rate_eligible(Variable): + value_type = bool + entity = Person + label = "New York CCAP special-needs market rate eligible" + definition_period = MONTH + defined_for = StateCode.NY + documentation = ( + "A child with a disability receives the special-needs market rate " + "when the parent demonstrates additional care needs and the child's " + "expense share exceeds the regular rate, under 18 NYCRR 415.9 and " + "24-OCFS-LCM-22." + ) + reference = ( + "https://www.law.cornell.edu/regulations/new-york/18-NYCRR-415.9", + "https://ocfs.ny.gov/main/policies/external/2024/lcm/24-OCFS-LCM-22.pdf#page=7", + ) + + def formula(person, period, parameters): + disabled = person("is_disabled", period.this_year) + additional_care = person("ny_ccap_special_needs_care", period.this_year) + expenses = person("ny_ccap_childcare_expenses", period) + regular = person("ny_ccap_regular_market_rate", period) + return disabled & additional_care & (expenses > regular)