PolicyEngine / PolicyEngine/microcosm
Export CPS parent pointers (PEPAR1/PEPAR2) as person-level parent ids
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 4
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 94
Description
Summary
Export the CPS ASEC parent pointers (PEPAR1/PEPAR2) as two person-level columns that resolve to the parent's person_id within the same household. The build already reads and resolves these pointers to compute own_children_in_household (eligibility_inputs.py, _own_children_in_household), but only the count is exported. Downstream models therefore know that someone has children in the household, not whose children they are.
Why
PolicyEngine US infers parent relationships from the count. is_parent is own_children_in_household > 0, and the Medicaid MAGI "child living with both parents" exception (medicaid_tax_dependent_exception_living_with_both_parents.py) fires when the family contains more than one person with own children. In a three-generation household the grandparent counts as a second parent for every grandchild, so all children are evaluated under non-filer rules with a household that pools every adult's income.
Reproduced on Build P (populace_us_2024, build populace-us-2024-buildp-sparse-rmloss100-cae8640-20260728T011454Z, policyengine-us 1.764.6), household 1009324 (OH, 10 persons, 3 tax units, one family):
| TCJA-expiration baseline | after OBBBA standard deduction | |
|---|---|---|
| 17-year-old dependent ($13,774 wages) required to file | yes ($8,300 threshold) | no ($16,100 threshold) |
| children's Medicaid household income | $141,848 (grandfather + two parents + teen) | $128,075 |
| household size used | 10 | 10 |
| percent of poverty vs Ohio child limit (211%) | 211.46% | 190.9% |
| children on Medicaid | 0 | 7 (+$55,655) |
Under 42 CFR 435.603(f)(2) the four children claimed by the 30-year-old parent would use that parent's tax household (60% of poverty) and the 3-year-old the 27-year-old's (88%); they are eligible in both worlds and the standard deduction moves nothing. The record is live at https://www.policyengine.org/us/obbba-household-explorer/?household=1009324&baseline=tcja-expiration as a $57,715 gain attributed to the standard deduction.
Aggregate impact in the OBBBA paper frames is negligible (2 records, weight ≈0.007), but the same proxy shapes every MAGI household determination for multigenerational families, and the Axiom encoding of 42 CFR 435.603 needs a real parent_of relation as a dataset input.
Proposal
- In
eligibility_inputs.py, alongsideown_children_in_household, emitparent_1_idandparent_2_id: theperson_idof the household member atA_LINENO == PEPAR1/PEPAR2within the samePH_SEQ, and0when the pointer is absent or unresolved. Names should match the input variables added on the policyengine-us side (issue linked below); adjust both together if a different name is chosen there. - Add the columns to
US_ELIGIBILITY_INPUTS_OUTPUT_COLUMNS, theoperator_boundary.pyperson allowlist, and the stage documentation insource_stages.json/spec/sources.yaml. - Consistency check in the release gates: for every person,
own_children_in_householdequals the number of persons whoseparent_1_idorparent_2_idpoints at them. - ACS-transferred records:
acs_pums.pysynthesizesPEPAR1/PEPAR2from the reference person and spouse lines (lines ~472–547). Confirm that path yields the sameperson_idresolution or leaves the ids at 0 rather than pointing at a non-parent.
A new certified data release is a separate step and is not in scope here.
Related observation (separate question)
Two weighted records in the same channel carry adult "dependents" whose earnings exceed the qualifying-relative gross-income test: household 1108166 (non-disabled 38-year-old, $13,638 wages, weight 18,661) and household 7428 (19-year-old non-student, $11,480 wages, weight 10,618). If the tax-unit builder places adult earners as dependents, that also feeds the other-dependent credit. Worth a look, but it is a different construction than the parent pointers.
Downstream
- policyengine-us consumer issue: https://github.com/PolicyEngine/policyengine-us/issues/9404
- Axiom: encoder lane for
us/regulation/42/435/603(income counting and the tax-dependent exceptions) will declareparent_ofas a supplied relation; this export is the data side of that contract.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with packages/microcosm-build/src/microcosm/build/us_runtime/eligibility_inputs.py and its existing _own_children_in_household resolution, then inspect acs_pums.py around lines 472–547. Trace the output columns, operator_boundary.py allowlist, and source_stages.json/spec/sources.yaml documentation. Done means parent_1_id and parent_2_id resolve same-household PEPAR pointers, unresolved values are 0, ACS-transferred records behave consistently, and the stated count consistency check is covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- data-engineering
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100