Repository navigation
Make only an infant's own mother WIC postpartum or breastfeeding - #9923
Conversation
wic_category made every woman with her own child in the household postpartum when the family had an infant, so a grandmother living with her daughter's baby was postpartum too. 7 CFR 246.2 defines postpartum and breastfeeding women by the time since their own pregnancy, so each infant can make only one woman postpartum or breastfeeding. Without parent-child links, match each infant to one mother in its tax unit (breastfeeding mothers first, then the youngest), and an infant in a tax unit without a mother to one of the family's remaining mothers. Fixes #9874. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A breastfeeding mother of a 6-12 month old took the six-month match of another mother's younger infant and left that mother uncategorized. Match breastfeeding women first, then give the remaining infants under six months to the other mothers. Adds regression tests for that case, two mothers in one tax unit, a father-only household and a 0.6-year-old infant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hua7450
left a comment
There was a problem hiding this comment.
Read wic_category.py at f27d5c7 and on main, the new test file, is_mother, is_breastfeeding, is_pregnant and the consumers (is_wic_eligible, meets_wic_categorical_eligibility, wic_food_package), against 7 CFR 246.2 ("Breastfeeding women means women up to one year postpartum who are breastfeeding their infants"; "Postpartum women means women up to six months after termination of pregnancy") and 246.10(e). The direction is right: a pregnancy belongs to one woman, so one infant makes at most one woman postpartum or breastfeeding, and ordering breastfeeding before postpartum in the select matches 246.10(e)(5) to (7). All ten new cases and the nine existing ones recompute by hand, and the consumers are unchanged.
One gap, narrow but a regression from main on an explicit input, so requesting changes:
A woman flagged is_breastfeeding loses her category when the infant is claimed in another tax unit that contains a different is_mother woman. The breastfeeding pass only looks at infants in the woman's own tax unit, and at the family level only at infants in tax units with no mother at all:
bf_tax_unit, bf_family = match(
mother,
tax_unit.sum(infant),
family.sum(infant & in_motherless_tax_unit),
)
breastfeeding_woman = breastfeeding & (bf_tax_unit | bf_family)Household: grandmother 45 (female, own_children_in_household: 1, so is_mother), daughter 20 with is_breastfeeding: true, infant 0.3; tax units {grandmother, infant} and {daughter}. The infant's unit has a mother, so it is not "motherless" and the daughter's family step sees zero infants; her own unit has none. Result at head: grandmother POSTPARTUM, daughter NONE. Main gave the daughter BREASTFEEDING. Under 246.2 the daughter is the breastfeeding woman (Package V or VII) and the grandmother is nothing, so this configuration ends up worse than before on both rows. The limitations list covers "grandparents claim the infant and the mother files alone", but not that it overrides the one input that directly asserts the mother-infant link; is_breastfeeding is also what is_mother itself reads.
Suggested shape: match women flagged is_breastfeeding to any infant under one in their family first (capped at the family's infant count), take those infants out of the pools, and leave the tax-unit heuristic to the non-breastfeeding mothers. Only the breastfeeding pass changes; the postpartum pass already works from the remaining pools.
Nits, not blocking:
- The two-mother tie (breastfeeding mother 22 with infant 0.2 and non-breastfeeding mother 30 with infant 0.8 in one unit) resolves to 30 POSTPARTUM because the breastfeeding woman is assumed to own the older infant; the inputs cannot distinguish it from case 7, so a one-line comment that this is the assumption would help the next reader.
_rank_mothersreturns a non-negative rank for ineligible, non-breastfeeding persons; both call sites mask witheligible, so it is correct today, butwhere(eligible, ..., -1)would make the helper safe on its own.- The limitations in the description (pregnant mother plus grandmother, two breastfeeding women and one infant, two-women couple) are not pinned by tests; one case each would lock the intended behaviour in.
Follow-up, pre-existing: young_infant = age < 0.5 drops an infant at exactly six months, while 246.7(g)(1)(ii) certifies the postpartum woman through the last day of the sixth month; same shape as the age < 1 windows.
A woman flagged is_breastfeeding lost her category when the infant was claimed in another tax unit that had a different mother. Breastfeeding women are now matched first: to an infant in their tax unit, else to any remaining infant in their family. The matched infants (oldest first; at family level, infants in tax units without a mother first) leave the pools, and the tax-unit heuristic matches the other mothers to the remaining infants under six months. Without is_breastfeeding inputs the results do not change. Tests: the reviewer's regression case, and one case each for the pregnant-mother, two-breastfeeding-women and two-women-couple limitations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks, fixed in 33dad79 as you suggested:
Without |
hua7450
left a comment
There was a problem hiding this comment.
Approving. Read wic_category.py and the test file at 33dad79 plus is_mother, is_breastfeeding, is_pregnant and the consumers, against 7 CFR 246.2 and 246.10(e).
The gap is fixed in the code: a woman flagged is_breastfeeding is matched first, to an infant in her tax unit or else to any infant left in her family (family.sum(infant) - family.sum(bf_in_tax_unit)), with no motherless-unit filter, and the infants she takes leave both pools (oldest first, motherless units first) before the postpartum pass runs on the remaining under-six-month infants. Walked the grandmother 45 / daughter 20 / infant 0.3 household: the daughter takes the infant at the family step, the grandmother finds no free young infant, result [NONE, BREASTFEEDING, INFANT], which is also the new regression case. The four match sets (bf_in_tax_unit, bf_in_family, pp_in_tax_unit, pp_in_family) are pairwise disjoint and each infant removal is bounded by the matched-woman count, so no woman is matched twice and no infant is counted twice, and without any is_breastfeeding input the formula reduces to the previous head, so the Populace figures in the description still hold. All 23 cases recompute by hand, including the three new pinning cases, the _rank_mothers helper is gone, and the assumption comment is in place.
Optional, not blocking: the where(in_motherless_tax_unit, 0, 2) - age ordering key reads better with a one-line note that 2 is just "larger than any infant age".
Pre-existing follow-ups, as you noted: the six-month boundary (age < 0.5 versus 246.7(g)(1)(ii)), twins beyond wic_breastfeeding_infant_count, and Package VI under 246.10(e)(6).
Fixes #9874.
Change
wic_categorymade every mother in a family with an infant postpartum (and every breastfeeding mother in a family with an infant under one breastfeeding):is_mother & (family min age < 0.5).is_motheris any woman with her own child in the household, so a grandmother living with her daughter's baby was postpartum too and got the $899 postpartum food package.The formula now matches each infant to one mother:
is_breastfeedingis matched to an infant under one in her tax unit, else to any remaining infant in her family (youngest breastfeeding women first). She is BREASTFEEDING. The infants she takes leave the pools, oldest first, so she counts against an infant aged six months to one year before a younger one; at family level, infants in tax units without a mother are taken first.nsuch infants has at mostnpostpartum women.PolicyEngine has no parent-child links (
own_children_in_householdis a count, andis_mother/is_parentonly test that count). The tax unit is the closest link the model has: in the CPS ASEC, 1,129 of the 1,148 infants (2023) and 1,163 of 1,177 (2022) whose mother lives in the household share her tax unit (TAX_ID); only 1,094 and 1,126 share her CPS family. In a three-generation tax unit, the youngest mother is usually the infant's mother. A woman reported as breastfeeding is matched first, because she is feeding an infant.is_pregnant, the infant and child categories, and the food package logic do not change.wic_categoryalso cites 7 CFR 246.2 now.Evidence
7 CFR 246.2: "Postpartum women means women up to six months after termination of pregnancy." "Breastfeeding women means women up to one year postpartum who are breastfeeding their infants." The same definitions are in 42 U.S.C. 1786(b)(10) and (b)(1). Both categories depend on the woman's own pregnancy, so one birth makes one woman postpartum or breastfeeding.
Check against CPS parent pointers. The CPS ASEC records each person's parents (
PEPAR1,PEPAR2), which PolicyEngine does not import. I ran the new formula on the raw CPS ASEC person records (PolicyEngine-US-datacensus_cps_{year}.h5, with the CPS tax units, families, ages, sex, andown_children_in_householdbuilt the same way as incps.py) and compared the postpartum women with the women whom an infant's parent pointer names:main: postpartum / wrong / missedmain→ this PR)Most remaining "wrong" cases are infants with no parent pointer in the household (for example, a foster child or a grandchild whose mother lives elsewhere) in a tax unit with a mother. Eight of the nine 2023 "missed" cases and all four 2022 cases are the second woman in a couple where both women are the infant's parents; only one of them can be postpartum. A rule that uses only the tax unit (no family step) missed 27 and 18 mothers; a rule that takes the youngest mothers in the family missed 67 and 61, because the CPS sometimes puts the mother and the infant in different families but the same tax unit.
Impact (Populace US 2024 file, 2025)
mainwic_categoryINFANT)Pregnant, infant, and child counts do not change. No record in this file has
is_breastfeeding, so the breastfeeding count is zero in both runs.Tests
New
wic_categorycases (2025):[NONE, POSTPARTUM, INFANT].maingives[POSTPARTUM, POSTPARTUM, INFANT].[NONE, POSTPARTUM, INFANT].maingives[POSTPARTUM, POSTPARTUM, INFANT].[NONE, POSTPARTUM, INFANT].maingives[POSTPARTUM, POSTPARTUM, INFANT].[NONE, BREASTFEEDING, INFANT].mainmakes the grandmother postpartum.[POSTPARTUM, INFANT](no change).[NONE, BREASTFEEDING, INFANT](no change).Added after review:
Added after the second review:
[NONE, BREASTFEEDING, INFANT]. The previous commit gave[POSTPARTUM, NONE, INFANT](maingives the mother BREASTFEEDING and the grandmother POSTPARTUM).[NONE, PREGNANT, INFANT]); two breastfeeding women and one infant (the younger is BREASTFEEDING); two mothers and one infant in one tax unit (the younger is POSTPARTUM).The first four in the first list fail on
mainand pass with this change. Results:policyengine-core test policyengine_us/tests/policy/baseline/gov/usda/wic -c policyengine_us: 90 passed (86 before the second review). With themainformula, the four new cases above fail and the other 11wic_categorycases pass.wic_category,wic,wic_food_package,wic_if_takes_up,is_wic_eligibleormeets_wic_categorical_eligibility(partner signatures, My Friend Ben, CCHIP, state tax integrations): 783 passed.[NONE, POSTPARTUM, INFANT]and WIC of $0 for the grandmother.ruff formatandruff checkpass.Limitations
is_breastfeeding. The CPS check finds this case rarely.main.main).wic_breastfeeding_infant_countalready covers twins for the food package.main. In Populace, 97 women are postpartum through the family step; 89 are under 40 (mostly mothers whose unmarried partner claims the infant), 8 are 40 or older.parent_1_id/parent_2_idinputs. When the data has them, a later change can match infants to mothers through the links. This PR does not depend on Medicaid MAGI household composition from co-resident parent ids (fixes #9404) #9406 and touches different files.🤖 Generated with Claude Code