Skip to content

Divide monthly income by 4.33 weeks in New Hampshire's child care cost share - #10679

Open
MaxGhenis wants to merge 2 commits into
mainfrom
nh-ccap-cost-share-weeks
Open

MaxGhenis wants to merge 2 commits into
mainfrom
nh-ccap-cost-share-weeks

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

New Hampshire's Department of Health and Human Services sets a family's weekly child care cost share by multiplying monthly income by a percentage and dividing by 4.33 weeks. nh_ccap_cost_share on main divides by 52/12, about 4.3333. We read the 4.33 from a new parameter, so every family at step 3, above 138% of the poverty guidelines, owes 0.077% more. The model splits that share evenly across eligible children and floors each child's payment at zero, so a paid family's payment falls by up to the weekly increase.

For example, a family of two with $4,000 a month owes $64.67 a week under the rule and $64.62 on main.

The rule

Under He-C 6910.18(b), "The family cap amount and cost share shall be calculated by taking the assistance group's monthly gross income, adjusted for family size, multiplied by the cost share percent associated with the step assigned to the family from Table 6910.1 and divided by 4.33 weeks." The version effective July 1, 2020 uses the same divisor in paragraph (d), so the parameter starts there.

We found no official source for dividing the cost share by 52/12. SR 24-08, FAM 938, Form 2532 and the CCDF plan state no divisor.

nh_ccap still turns its weekly payment into a month at 52/12, because the rule sets payments by the week and names 4.33 only for the cost share.

Under He-C 6910.18(e), the state applies each year's poverty guidelines from July 1, and the model applies them from January 1. The property test draws families for July 2025, when both use the 2025 guideline.

Invariants

test_nh_ccap_cost_share_properties.py draws incomes and charges across the steps and compares the model with rule_cost_share, which restates the rule's table on its own:

  1. A family at or below 100% of the poverty guidelines owes nothing.
  2. A family above 100% and at or below 138% owes $5 a week.
  3. A family above 138% owes 7% of monthly income divided by 4.33, and within that 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.

The existing parameters place the upper steps at 1.0001 and 1.3801 of the guideline, so a family inside those slivers takes the lower step. The test skips those incomes, and we leave the parameters as they are.

Tests

  • We raise the expected share in Case 3 of integration.yaml from $80.77 to $80.83, and in Cases 3 and 7 of nh_ccap_cost_share.yaml from $71.76 to $71.81 and from $39.31 to $39.34.
  • In a new Case 10 in integration.yaml, a family at step 3 owes $64.67 a week and receives $933.12 a month.
  • At 7134a3c, 122 tests pass in New Hampshire's YAML folder and 2 in test_nh_ccap_cost_share_properties.py.
  • The two properties draw incomes and charges, which YAML can't draw, and build 41 simulations. In CI at 7134a3c, the Rest Python chunk remaining-2 ran them in 2.7 and 8.5 seconds. The whole chunk ran for 28:54, setup included, and peaked at 7.2 GiB of resident memory. CI measures memory for the whole chunk, so we have no peak for this file alone, and we didn't time it locally. The chunk's runs vary by more than those 11 seconds: on main at 3386304d28, with a different set of files, it ran for 27:23 and peaked at 6.1 GiB.

Impact

We ran the default dataset for 2026 on this branch and on its base, 040fe56. We estimate that New Hampshire's child care subsidies fall by $1.66 a year, from $16,945,702.42 to $16,945,700.76. Four of the 8 New Hampshire records that receive a payment in the model change, and their weights sum to 0.26 families, so the estimate rests on little data. National household net income falls by $1.67, and the national SPM poverty rates don't change.

axiom: TheAxiomFoundation/rulespec-us#2056 queued

🤖 Generated with Claude Code

…t share

He-C 6910.18(b) calculates the weekly cost share as monthly gross income times
the step's percent, "divided by 4.33 weeks". The variable divided by 52/12, which
understates a step 3 family's share by 0.077%. A parameter now holds the rule's
divisor, and the cost share references point to the current rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…egers

Under He-C 6910.18(e), New Hampshire applies each year's poverty
guidelines from the following July, so the property test now draws
families for July 2025, when the 2025 guideline applies under the rule
and in the model. The boundary check compares integer cross-products,
so 138% of the guideline counts as step 2. Invariant 4 now names the
family it covers: one eligible child and no disability supplement.

Case 10 stays in January 2025, since the YAML runner doesn't carry
year-long inputs into a mid-year month. Its income exceeds 138% of
both the 2024 and 2025 guidelines, and its comment gives both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis marked this pull request as ready for review November 9, 2026 09:40
@codecov

codecov Bot commented Nov 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (518fbea) to head (7134a3c).
⚠️ Report is 81 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main    #10679   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            1         1           
  Lines           29        16   -13     
=========================================
- Hits            29        16   -13     
Flag Coverage Δ
unittests 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@DTrim99

DTrim99 commented Nov 13, 2026

Copy link
Copy Markdown
Collaborator

PR Review: Divide monthly income by 4.33 weeks in New Hampshire's child care cost share

Summary

The fix is right. I read the rule before the code.

  • The divisor is 4.33. The current He-C 6910.18(b) (gc.nh.gov, He-C 6900, source note "ss by #13799, eff 10-28-23") reads: "The family cap amount and cost share shall be calculated by taking the assistance group's monthly gross income, adjusted for family size, multiplied by the cost share percent associated with the step assigned to the family from Table 6910.1 and divided by 4.33 weeks."
    • That is the literal 4.33, not 4.3 and not 52/12.
    • The version effective July 1, 2020 (#13063), still shown on Cornell's N-H-Admin-Code page, says in (d): "... and divided by 4.33." That supports the parameter's 2020-07-01 start.
    • He-C 6910.07(o)(2)a. uses the same divisor elsewhere in the program: "Dividing the monthly income ... by 4.33 weeks to establish weekly income."
  • The cost share is weekly. Table 6910.19 lists "$0/week", "$5/week" and "7.0% of family income". Paragraph (b) turns the monthly product into a weekly amount. He-C 6910.17(e) pays the lower of the provider's charge and the standard weekly rate, "then subtract[s] the family's cost share". Only step 3 is divided; step 2 is a flat $5 a week, and the formula adds it undivided.
  • The July test month comes from He-C 6910.18(e). It reads: "Changes in the monthly gross income limit used to calculate eligibility shall be effective on the first day of July following publication of the annual update of the federal poverty guidelines in the Federal Register."
    • It is not a table effective date: Table 6910.19 holds only percentages and carries no date of its own.
    • It is not the state fiscal year either. That year also starts July 1, but the rule ties the date to the guideline's publication.
    • In July 2025 the rule and the model (spm_unit_fpg is yearly) both use the 2025 guideline, so the test's rule_cost_share with FPG $21,150 is the rule's own value.
    • One wrinkle: (e) speaks of the "income limit used to calculate eligibility", which He-C 6910.06(b) now sets at 85% of SMI. Paragraph (a) still points its FPG steps at 6910.06(b), a stale cross-reference. Because (e) names the poverty-guideline publication, reading it to cover the FPG step edges is reasonable.

The change touches only the step 3 cost share and, through it, the payment. Every changed or new expectation checks out by hand, CI is green at the head and the branch merges cleanly with current main. I found no critical or should-address issues. I have four suggestions; two of them are pre-existing gaps outside this diff.

My basis is reading the rule, the code at the head and the CI logs, plus hand traces. I ran no Python locally. The NH DHHS pages (SR 24-08, FAM 938 and Form 2532) refuse automated requests, so I couldn't confirm the PR body's statement that they give no divisor. The binding rule settles the question regardless.

Critical (must fix)

None.

Should address

None.

Suggestions

  1. The variable's reference no longer names a section.

    • Where: nh_ccap_cost_share.py:12.
    • The old link pointed at He-C 6910.18 alone. The new one opens the whole He-C 6900 chapter, a single page with no section anchors. CLAUDE.md asks to "cite specific regulation sections in variable reference".
    • Switching to the current official text is right: the Cornell page shows the 2020 seven-step table. But nothing in the tuple now says which section to read.
    • Fix: add a # He-C 6910.18(b) comment above the href, or add a text fragment (#:~:text=He-C%206910.18%20Cost%20Share%20Determination).
    • Optional: weeks_per_month.yaml cites the 2020 version on Cornell's N-H-Admin-Code page. Cornell already shows the current #13799 text on a separate page (RSA-He-C-6910.18), so it may refresh the old one too. A Wayback snapshot would keep paragraph (d) readable.
  2. Make the Hypothesis tests deterministic.

    • Where: test_nh_ccap_cost_share_properties.py:79,101.
    • Both decorators are @settings(max_examples=..., deadline=None). Without derandomize=True, every CI run draws new incomes, so a red run may not come back on a rerun.
    • Of the 117 test files on main that use @settings, 93 pass derandomize=True.
    • The @example rows already pin the boundaries, so derandomizing loses nothing.
  3. Follow-up, pre-existing: the step edges sit at 1.0001 and 1.3801.

    • Where: weekly_flat_amount.yaml and income_share_rate.yaml, outside this PR's value changes.
    • For a family of two in 2025, two narrow bands get the wrong step:
      • Above 100% but below 100.01% of the guideline ($21,151 to $21,152 a year): step 1 ($0) instead of step 2 ($5 a week).
      • Above 138% but below 138.01% ($29,188 to $29,189): $5 instead of 7% (about $39.34 a week).
    • The new property test skips those incomes through outside_boundary_slivers, and the PR body says so.
    • Fix: set the thresholds to 1 and 1.38 and call .calc(fpg_ratio, right=True). Main uses that call in 51 variables. "Greater than" then holds exactly, and the test can drop its assume.
  4. Follow-up, pre-existing and disclosed: when new guidelines take effect.

    • Under (e), the state applies a new year's guidelines from July 1. The model applies them from January 1.
    • From January to June, the model's step edges are a year ahead of the rule's. For a family of two in 2025: 100% is $1,762.50 a month against the rule's $1,703.33, and 138% is $2,432.25 against $2,350.60.
    • None of the PR's expectations depends on this. Every changed case is in step 3 under both guidelines (checked below), and the second commit moves the property test to July.
    • The eligibility side looks similar. The companion rulespec-us issue's own table gives DHHS's 85%-of-SMI limits from July 1, 2024 as $6,428 a month for two and $7,940 for three. The model's January 2025 limits are $7,060.37 and $8,721.63.
    • The name of nh_ccap_cost_share.yaml Case 7 ("$1 above 138% FPG") holds only for the model's January guideline. Under the rule's 2024 guideline that income is $82.73 a month above the edge.
    • A tracking issue would cover all of this. The rulespec issue already defers (e).

Verified correct

Hand checks. Basis: arithmetic from the rule's formula and the parameters at the head. The FPG for two is $21,150 ($1,762.50 a month) and for three $26,650 ($2,220.83). The preschool full-time licensed-center rate is $280.

# Case Arithmetic Expected Result
1 integration.yaml Case 3, nh_ccap_cost_share 0.07 × 5,000 = 350; 350 / 4.33 = 80.8314 (old: 350 / 4.3333 = 80.77) 80.83 ✓
2 nh_ccap_cost_share.yaml Case 3 53,304 / 12 = 4,442; × 0.07 = 310.94; / 4.33 = 71.8106 (old 71.76) 71.81 ✓
3 nh_ccap_cost_share.yaml Case 7 29,200 / 12 = 2,433.33; × 0.07 = 170.3333; / 4.33 = 39.3379 (old 39.31); ratio 29,200 / 21,150 = 1.38061 ≥ 1.3801, so step 3 39.34 ✓
4 integration.yaml Case 10, nh_ccap_cost_share 48,000 / 12 = 4,000; × 0.07 = 280; / 4.33 = 64.6651 64.67 ✓
5 integration.yaml Case 10, nh_ccap min(18,720 / 52 = 360, 280) = 280; 280 − 64.6651 = 215.3349; × 52/12 = 933.1180. The old divisor gives 933.33, so the case tells the two apart. 933.12 ✓
6 Case 10, step and eligibility under both guidelines 4,000 / 1,762.50 = 2.2695; 4,000 / 1,703.33 = 2.3483; both above 1.38; 4,000 < 7,060.37 step 3, eligible ✓
7 Changed cases under the rule's January guideline (2024) Case 7: 2,433.33 > 2,350.60. Cost share Case 3: 4,442 > 2,969.30 (family of three). Integration Case 3: 5,000 > 2,969.30. All stay in step 3, where the share doesn't depend on the FPG. unchanged ✓
8 Property @example 29,187 29,187 × 100 = 2,918,700 = 21,150 × 138, so ≤ 138%: step 2. Model ratio 1.38 < 1.3801. $5 ✓
9 Property @example 80,000 with a $1,000 charge Share 6,666.67 × 0.07 / 4.33 = 107.78; charge 1,000 / 52 = 19.23; max(19.23 − 107.78, 0) = 0 (the floor). Income 6,666.67 < 7,060.37, so eligible. payment 0 ✓
10 Property @example 29,200 with an $18,720 charge (280 − 39.3379) × 52/12 = 1,042.87 invariant 4 ✓
11 Unchanged nh_ccap_cost_share.yaml Case 5 36,600 / 12 = 3,050 / 2,220.83 = 1.3734 < 1.38, so step 2; the divisor doesn't apply 5 ✓
12 PR body's 0.077% 4.3333 / 4.33 = 1.00077; example 280 / 4.3333 = 64.62 vs 64.67 — ✓

Mutation. Basis: hand traces.

  • Reverting the divisor to 52/12 fails integration Case 3 (80.77), cost-share Cases 3 and 7 (71.76, 39.31) and Case 10 (64.62 and 933.33).
  • Changing nh_ccap's 52/12 to 4.33 fails Case 10 (215.3349 × 4.33 = 932.40).
  • Every new line is pinned.

Effect on other variables. Basis: git grep at the head.

  • Only nh_ccap_cost_share.py reads the new parameter, and only nh_ccap.py reads nh_ccap_cost_share. nh_child_care_subsidies adds nh_ccap, which is the intended downstream change.
  • No other New Hampshire child care variable reads either one: eligibility, income eligibility, activity, service level, payment rate, disability supplement, age category or countable income.
  • The two cost-share parameter files change only their href lines.
  • Steps 1 and 2 are unchanged, and step 3 shares rise by a factor of 1.00077.

nh_ccap keeps 52/12. He-C 6910.17(e) sets the payment by the week, and the rule names 4.33 only for the cost share. Turning a weekly payment into a monthly one is the model's own conversion. Case 10 and invariant 4 pin it.

References (CLAUDE.md "Parameter and variable references"):

  • Each entry is a single source document, the titles carry no page text, and all are HTML pages.
  • The two cost-share parameters previously cited Cornell's page, which shows the 2020 seven-step table (4.75% to 20%). That page didn't support the 2024 values of $0, $5 and 7%. The current Table 6910.19 on gc.nh.gov does, so this PR fixes a reference that didn't support its values.
  • weeks_per_month.yaml follows the house description template, with unit: week, period: month and a plain label.

Test design (CLAUDE.md "Test design and CI cost"):

  • rule_cost_share restates the table on its own: integer boundary arithmetic and a literal 4.33, without reading the parameter.
  • The property tests draw incomes and charges, which YAML can't do, and build 41 simulations (6 + 15 examples, then 10 × 2).
  • In CI, remaining-2 ran them in 2.71 s and 8.45 s, which matches the PR body. The body also reports the chunk's runtime and memory and says no per-file memory figure is available.
  • Main already has many root-level policy property tests (for example test_co_ccap_parent_fee_properties.py). The new file joins the Rest "remaining" group automatically.

Vectorization, entity and period. The parameter is a scalar read at the month's instant, on an SPMUnit and MONTH variable. The PR adds no state-gated int or enum key, so the NH #10156 pattern doesn't apply.

Changelog. changelog.d/nh-ccap-cost-share-weeks.fixed.md uses a valid towncrier type.

Source conflicts. None needs recording. The rule is the only source that states a divisor, and the old 52/12 had no source. The diff adds no conflict-sounding comment under variables or parameters, so the #10287 ratchet doesn't change on the merged tree.

Partner files. No file under tests/policy/baseline/partners/** changes.

Axiom line assessment

axiom: TheAxiomFoundation/rulespec-us#2056 queued is valid.

  • The issue is OPEN and labelled pe-parity. It was last updated 2026-11-07 18:45 UTC, after the second commit.
  • It has everything a dispatch needs:
    • a module path (us-nh/regulations/he-c-6900/He-C 6910/18) and a corpus citation path;
    • the verbatim text of (a), (b) and (f) and Table 6910.19;
    • the required outputs and a review_finding text to paste;
    • eight companion cases taken from the rule.
  • It records the blocker: a billed encoder run needs approval, and rulespec-us's pinned corpus release leaves out the He-C 6900 scope.
  • It matches the head. It names gov.states.nh.dhhs.ccap.cost_share.weeks_per_month (4.33), and its Cases 1 to 6 match the YAML values: $0, $5, $5, $39.34, $71.81 and $80.83.

CI status

All 38 checks pass at head 7134a3c (run 42595254201, pull_request, 2026-11-09); I re-checked at the end of the review. Basis: CI logs.

  • In Baseline states-shard-4, batch 8 ran integration.yaml (10 cases) and nh_ccap_cost_share.yaml (10 cases), and all passed.
  • In Rest Python shard 4, group remaining-2, both property tests PASSED.
  • Three "skipping" entries come from the 2026-11-07 run 42391241850, made while the PR was a draft. They are the draft skip, not failures.

Branch status

  • The branch is 2 commits ahead of main and 212 behind (merge base 040fe56).
  • git merge-tree --write-tree against current main is clean.
  • Since the merge base, main hasn't changed any New Hampshire CCAP file, spm_unit_fpg, the FPG parameter or the policyengine-core pin.
  • About 140 commits landed on main after the CI run's merge ref, and none touches these paths.
  • The guards main added or changed in that time (the source-conflict ratchet and the partner contract rule) don't fire on this diff. I see no need to rerun.

Verdict: APPROVE

@DTrim99 DTrim99 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. He-C 6910.18(b) divides monthly income by "4.33 weeks", the literal divisor the PR uses, and the July 2020 rule has the same 4.33, which supports the 2020-07-01 start. The cost share is weekly, and only step 3 changes. All 12 hand checks pass, every new line is pinned, CI is green at 7134a3cf98, and the branch merges cleanly with main. The four suggestions in the report above are optional; two concern earlier code, not this PR.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants