Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/nh-ccap-cost-share-weeks.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Divide monthly income by 4.33 weeks in New Hampshire's child care cost share, as He-C 6910.18(b) directs.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ metadata:
label: New Hampshire CCAP income share rate by FPG ratio
reference:
- title: He-C 6910.18, Table 6910.19
href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.18
href: https://gc.nh.gov/rules/state_agencies/he-c6900.html
- title: SR 24-08, Cost Share and Steps (January 2024)
href: https://www.dhhs.nh.gov/sr_htm/html/sr_24-08_dated_01_24.htm
- title: New Hampshire CCDF State Plan 2025-2027, Section 3.2.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ metadata:
label: New Hampshire CCAP weekly flat cost share amount by FPG ratio
reference:
- title: He-C 6910.18, Table 6910.19
href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.18
href: https://gc.nh.gov/rules/state_agencies/he-c6900.html
- title: SR 24-08, Cost Share and Steps (January 2024)
href: https://www.dhhs.nh.gov/sr_htm/html/sr_24-08_dated_01_24.htm
- title: New Hampshire CCDF State Plan 2025-2027, Section 3.2.1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
description: New Hampshire divides monthly income by this number of weeks to calculate the weekly family cost share under the Child Care Scholarship Program.

values:
2020-07-01: 4.33

metadata:
unit: week
period: month
label: New Hampshire CCAP weeks per month for the family cost share
reference:
- title: He-C 6910.18(b)
href: https://gc.nh.gov/rules/state_agencies/he-c6900.html
- title: He-C 6910.18(d) (effective July 1, 2020)
href: https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.18
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
weekly_hours_worked_before_lsr: 40
employment_income: 60_000
# $60,000/yr = $5,000/mo > $3,064.75 (138% FPG for 3)
# Step 3: 7% * $5,000 / 4.33 = $80.77/week
# Step 3: 7% * $5,000 / 4.33 = $80.83/week
person2:
age: 35
weekly_hours_worked_before_lsr: 40
Expand Down Expand Up @@ -129,8 +129,8 @@
nh_ccap_income_eligible: true
nh_ccap_eligible: true

# Cost share: 7% * $5,000 / (52/12) = $350 / 4.3333 = $80.77/week
nh_ccap_cost_share: 80.77
# Cost share: 7% * $5,000 / 4.33 = $350 / 4.33 = $80.83/week
nh_ccap_cost_share: 80.83

- name: Case 4, two eligible children, cost share split equally.
period: 2025-01
Expand Down Expand Up @@ -379,3 +379,44 @@
nh_ccap_income_eligible: false
nh_ccap_eligible: false
nh_ccap: 0

- name: Case 10, positive benefit end-to-end at step 3, the cost share divides by 4.33 weeks.
period: 2025-01
absolute_error_margin: 0.01
input:
people:
person1:
age: 28
weekly_hours_worked_before_lsr: 40
employment_income: 48_000
# $48,000/yr = $4,000/mo, above 138% of the 2024 poverty guideline for 2 ($2,350.60),
# which He-C 6910.18(e) applies until July 2025, and of the 2025 guideline ($2,432.25),
# which the model applies from January. Below 85% SMI for 2 ($7,060.37).
person2:
age: 4
is_tax_unit_dependent: true
immigration_status: CITIZEN
childcare_hours_per_week: 40
nh_ccap_provider_type: LICENSED_CENTER
pre_subsidy_childcare_expenses: 18_720
# $18,720/yr = $360/week
spm_units:
spm_unit:
members: [person1, person2]

tax_units:
tax_unit:
members: [person1, person2]
households:
household:
members: [person1, person2]
state_code: NH
output:
nh_ccap_eligible: true
# Cost share: 7% * $4,000 / 4.33 = $280 / 4.33 = $64.67/week
nh_ccap_cost_share: 64.67
# Preschool, full-time, licensed center: $280/week
# min($360/wk charge, $280 rate) = $280
# Weekly payment: $280 - $280 / 4.33 = $215.3349
# Monthly: $215.3349 * (52/12) = $933.12
nh_ccap: 933.12
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# 2025 FPG family of 3: 15,650 + 5,500*2 = $26,650/year = $2,220.83/month
# Step 1: <= 100% FPG ($2,220.83/mo) → $0/week
# Step 2: > 100% to <= 138% FPG ($3,064.75/mo) → $5/week
# Step 3: > 138% FPG → 7% * monthly income / (52/12)
# Step 3: > 138% FPG → 7% * monthly income / 4.33
#
# 2025 FPG family of 2: 15,650 + 5,500 = $21,150/year = $1,762.50/month
# 2025 FPG family of 1: $15,650/year = $1,304.17/month
Expand Down Expand Up @@ -66,7 +66,7 @@
age: 30
employment_income: 53_304
# $53,304/yr = $4,442/mo > $3,064.75 (138% FPG)
# Step 3: 7% * $4,442 / (52/12) = $71.77/week
# Step 3: 7% * $4,442 / 4.33 = $71.81/week
person2:
age: 5
person3:
Expand All @@ -79,8 +79,8 @@
members: [person1, person2, person3]
state_code: NH
output:
# $4,442 * 0.07 / (52/12) = $310.94 / 4.3333 = $71.76
nh_ccap_cost_share: 71.76
# $4,442 * 0.07 / 4.33 = $310.94 / 4.33 = $71.81
nh_ccap_cost_share: 71.81

- name: Case 4, income exactly at 100% FPG boundary, step 1.
period: 2025-01
Expand Down Expand Up @@ -175,8 +175,8 @@
state_code: NH
output:
# $2,433.33 * 0.07 = $170.33
# $170.33 / (52/12) = $170.33 / 4.3333 = $39.31
nh_ccap_cost_share: 39.31
# $170.33 / 4.33 = $39.34
nh_ccap_cost_share: 39.34

- name: Case 8, zero income, step 1, $0 cost share.
period: 2025-01
Expand Down
110 changes: 110 additions & 0 deletions policyengine_us/tests/test_nh_ccap_cost_share_properties.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"""Invariants of New Hampshire's child care family cost share, He-C 6910.18.

1. Step 1: a family at or below 100% of the poverty guidelines owes nothing.
2. Step 2: a family above 100% and at or below 138% owes $5 a week.
3. Step 3: a family above 138% owes 7% of monthly income divided by 4.33 weeks,
and within the step the share rises with income.
4. For a family with one eligible child and no disability supplement, the
monthly payment equals 52/12 weeks of the lesser of the charge and the standard
rate, less the cost share, floored at zero.

rule_cost_share restates the rule's table on its own, so the variable and the
table must agree. The YAML cases pin single families; these draw incomes and
charges across the steps.
"""

from hypothesis import assume, example, given, settings
from hypothesis import strategies as st
import pytest

from policyengine_us import Simulation

YEAR = 2025
# He-C 6910.18(e) applies each year's poverty guidelines from the following July,
# so July 2025 uses the 2025 guideline for a family of two.
MONTH = "2025-07"
FPG = 21_150
WEEKLY_RATE = 280 # Preschool, full time, licensed center.
TOLERANCE = 0.01


def rule_cost_share(annual_income):
if annual_income <= FPG:
return 0
if annual_income * 100 <= FPG * 138:
return 5
return annual_income / 12 * 0.07 / 4.33


def outside_boundary_slivers(annual_income):
# The parameters place the steps at 1.0001 and 1.3801 of the guideline, so a
# family inside those slivers takes the lower step.
# Integer cross-products keep 138% of the guideline, $29,187, out of the sliver.
in_first = FPG * 10_000 < annual_income * 10_000 < FPG * 10_001
in_second = FPG * 13_800 < annual_income * 10_000 < FPG * 13_801
return not (in_first or in_second)


def cost_share_and_payment(annual_income, annual_charge):
members = ["parent", "child"]
parent = {
"age": {YEAR: 28},
"weekly_hours_worked_before_lsr": {YEAR: 40},
"employment_income": {YEAR: annual_income},
}
child = {
"age": {YEAR: 4},
"is_tax_unit_dependent": {YEAR: True},
"immigration_status": {YEAR: "CITIZEN"},
"childcare_hours_per_week": {YEAR: 40},
"nh_ccap_provider_type": {YEAR: "LICENSED_CENTER"},
"pre_subsidy_childcare_expenses": {YEAR: annual_charge},
}
situation = {
"people": {"parent": parent, "child": child},
"tax_units": {"tax_unit": {"members": members}},
"spm_units": {"spm_unit": {"members": members}},
"families": {"family": {"members": members}},
"marital_units": {"marital_unit": {"members": ["parent"]}},
"households": {"household": {"members": members, "state_name": {YEAR: "NH"}}},
}
simulation = Simulation(situation=situation)
return [
float(simulation.calculate(name, MONTH)[0])
for name in ("nh_ccap_cost_share", "nh_ccap")
]


@settings(max_examples=15, deadline=None)
# Zero income, each step's upper edge, the first dollars above 138%, and a charge
# below the rate that the cost share exceeds.
@example(annual_income=0, annual_charge=18_720)
@example(annual_income=FPG, annual_charge=18_720)
@example(annual_income=FPG * 138 // 100, annual_charge=18_720)
@example(annual_income=29_200, annual_charge=18_720)
@example(annual_income=48_000, annual_charge=18_720)
@example(annual_income=80_000, annual_charge=1_000)
@given(
annual_income=st.integers(min_value=0, max_value=80_000),
annual_charge=st.integers(min_value=1, max_value=40_000),
)
def test_cost_share_and_payment_follow_the_rule(annual_income, annual_charge):
assume(outside_boundary_slivers(annual_income))
share, payment = cost_share_and_payment(annual_income, annual_charge)
expected_share = rule_cost_share(annual_income)
assert share == pytest.approx(expected_share, abs=TOLERANCE)
weekly_cap = min(annual_charge / 52, WEEKLY_RATE)
expected_payment = max(weekly_cap - expected_share, 0) * 52 / 12
assert payment == pytest.approx(expected_payment, abs=TOLERANCE)


@settings(max_examples=10, deadline=None)
@given(
lower=st.integers(min_value=29_190, max_value=79_999),
gap=st.integers(min_value=1, max_value=20_000),
)
def test_step_three_share_rises_with_income(lower, gap):
higher = min(lower + gap, 80_000)
lower_share, _ = cost_share_and_payment(lower, 18_720)
higher_share, _ = cost_share_and_payment(higher, 18_720)
assert higher_share > lower_share
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,17 @@ class nh_ccap_cost_share(Variable):
definition_period = MONTH
defined_for = StateCode.NH
reference = (
"https://www.law.cornell.edu/regulations/new-hampshire/N-H-Admin-Code-SS-He-C-6910.18",
"https://gc.nh.gov/rules/state_agencies/he-c6900.html",
"https://www.dhhs.nh.gov/sr_htm/html/sr_24-08_dated_01_24.htm",
)

def formula(spm_unit, period, parameters):
p = parameters(period).gov.states.nh.dhhs.ccap.cost_share
countable_income = spm_unit("nh_ccap_countable_income", period)
fpg = spm_unit("spm_unit_fpg", period)
weeks_per_month = WEEKS_IN_YEAR / MONTHS_IN_YEAR

fpg_ratio = where(fpg > 0, countable_income / fpg, 0)
income_based_share = (
countable_income * p.income_share_rate.calc(fpg_ratio) / weeks_per_month
countable_income * p.income_share_rate.calc(fpg_ratio) / p.weeks_per_month
)
return p.weekly_flat_amount.calc(fpg_ratio) + income_based_share
Loading