Repository navigation
Count Missouri TANF parents claimed as tax dependents as unit members - #9676
Merged
MaxGhenis merged 14 commits intoOct 9, 2026
Merged
Conversation
13 CSR 40-2.300(5)(C) and the Combined IM Policy Manual 4.2.2 (formerly DSS Manual 0210.005.05) make the biological or adoptive parents of the eligible children mandatory members, whoever claims them for taxes. mo_tanf_is_assistance_unit_member admitted only tax-unit heads and spouses, so a 20-year-old mother claimed by her own mother was left out and the unit was her child alone. A tax-unit member marked mo_tanf_is_parent_of_dependent_child is now a member unless they receive SSI, are marked a non-parent caretaker, or are a dependent child (then they are a member as a child, and the three-generation family files as one group). The default for that input now also requires being 12 to 50 years older than one of the tax unit's dependent children, which rules out, for example, the head's elderly mother. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #9676 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 4 5 +1
Lines 76 106 +30
Branches 2 1 -1
=========================================
+ Hits 76 106 +30
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…scope wording Review round on PolicyEngine#9676 (findings 1, 5, 6, 7, 9-12): - Replace the vacuous adult-only-child YAML case with a two-tax-unit household where an explicit parent flag must not add someone whose own tax unit has no dependent child (fails if the guard is dropped). - Add the mandatory dependent parent's income case (her $1,200 makes the unit of four ineligible; main pays the three children $292.08996) and its zero-income pair ($341.8074). - Property suite: restate non-parent caretaker identification person by person, including households where one must be found, and an explicit-flag guard grid; say where expectations still read model outputs and that the flag-off comparison does not run pre-change code. - Label the 18-year-old high-school parent's one-unit grouping as the retained interpretation (i), not settled law. - Parent flag docs: January snapshot, adoptive parents outside the 12-50 window need the input, explicit input zeroes others only for that year; drop the dataset-specific accuracy claim from the formula comment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…window in the default-input test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
marked this pull request as draft
October 8, 2026 23:18
MaxGhenis
marked this pull request as ready for review
October 9, 2026 00:28
Contributor
Author
|
US + core hub merge audit, us#9676 at
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This change includes a biological or adoptive parent in Missouri's TANF assistance unit when someone else claims that parent as a tax dependent. In the target household—a marked non-parent grandparent, a dependent adult mother, and her child—the mother and child form the unit. The mother's income counts and can reduce or eliminate the children's grant. Max's d1049 ruling (2026-10-08) makes explicit
parent_1_id/parent_2_idinputs the first source for parenthood, retaining the 12–50-year age-window imputation only for dependent children whose two parent ids are unknown (0).The implementation retains main's #9741
get_override_branchhelpers. Coverage checks income loss and its zero-income counterpart, the own-tax-unit child guard, the complete non-parent-caretaker identification vector and converse, annual input overrides, and the January snapshot. A separate-return biological-parent case also records the remaining cross-tax-unit membership limitation.axiom: TheAxiomFoundation/rulespec-us#1444 queued (still open; this does not claim that the dependent-parent rule has been encoded).
Rule and retained interpretation
Parents of eligible children are mandatory members regardless of tax dependency. SSI recipients are excluded, and a biological or adoptive parent's presence excludes a non-parent caretaker. These rules follow 13 CSR 40-2.300 and 40-2.310 and Combined IM Policy Manual 4.2.
Max's d1049 ruling (2026-10-08) approves interpretation (i) for an 18-year-old parent enrolled in secondary school: the 18-year-old, her baby and her own parent form one combined unit, size three in the zero-income example. This is the approved modeling interpretation rather than a claim of settled law. Both archived 0210.005.30 and current 4.3 define minor parent as under 18, including the birthday month. Alternative readings give size two; separate grouping and major-parent deeming remain outside this build.
The default
mo_tanf_is_parent_of_dependent_childfirst reads each relevant dependent child'sparent_1_idandparent_2_id. A known id naming the person establishes parenthood regardless of their age gap; known ids naming other people do not establish parenthood. Only a child with both ids unknown (0) uses the existing 12–50-year age-window fallback, using the existingis_parentsignal. The fallback imputes a relationship; it is not an eligibility rule. The same precedence applies to the presumed parenthood of unmarked tax-unit heads and spouses in membership and non-parent-caretaker identification: known ids identify named adults without distinguishing parent type, while unknown ids retain the existing proxy. This follows Max's 2026-10-07 principle to "make inputs as leaf-nodey as possible": callers can supply the underlying parent ids instead of overriding a derived parenthood flag. The flag is annual and uses January's dependent-child status: changingmonthly_agelater in the year does not recalculate that year's flag.The d1049 implementation prefers explicit parent ids and preserves the existing unknown-id fallback, including the grandmother regression. A direct read-only check of the pinned Populace HDF at snapshot
9a814a3b3b53c0ecd6e1737b6ec862c31300ef6fverified SHA-2566496cc4393d4d3c6574f76eca231de5898c803b9067645591fd5c4d3e65aee84:parent_1_idandparent_2_idare both absent from its 318 person columns and from every other entity table (166,321 people). Raw CPSPEPAR1/PEPAR2columns exist, but the loader does not convert them to these PolicyEngine inputs. Both leaf inputs have no formula and default to0; dataset loading and uprating preserve the existing columns. Thus d1049's three Missouri formulas take their unchanged unknown-id path for this dataset. No new microsimulations were run.An explicit flag overrides the default for the supplied year. Supplying it for one person makes unspecified people false for that year, so callers should supply it for every applicable parent. Other years can still use the formula. An explicit
truedoes not add a real biological or adoptive parent whose own tax unit has no dependent child, even when another tax unit supplies the SPM unit's eligible child. The formulas group children within tax units, and this boolean input cannot attach a child from another tax unit. Mandatory membership for a separately filing parent under 13 CSR 40-2.300(5)(C) therefore remains unmodeled; the new YAML case explicitly verifies that the flag is true while that parent remains excluded.Caller contract and remaining relationship limits
The shared
parent_1_id/parent_2_idinputs name natural, adoptive and step-parents alike; they do not record parent type. Missouri's automatic parent flag consequently treats a named step-parent as biological or adoptive, incorrectly adding their needs and full income and potentially blocking an NPCR. Only natural or adoptive parents are mandatory and block an NPCR under 13 CSR 40-2.300(5)(C)/(D); 40-2.310(8)(B)1.D.(II) instead deems a step-parent's income after deductions. This round discloses that limitation, as permitted by review r3 P2; it does not implement relationship typing or step-parent income deeming.Preserve the shared parent ids for other programs. When ids include a step-parent, explicitly supply
mo_tanf_is_parent_of_dependent_childfor every person for that year:truefor every applicable biological or adoptive parent andfalsefor step-parents and other people. Supplying one person's flag makes every unspecified person's flag false for that year. This corrects parent membership and NPCR identification when each relevant child's links are known. If any dependent child has both ids unknown, the head/spouse proxy remains active even with an explicit false; that inference limitation remains.Known child parent ids do not identify a non-parent caretaker relative. Callers must explicitly mark an NPCR with
mo_tanf_is_non_parent_caretaker; a grandmother with a grandchild naming an absent parent otherwise remains outside the child-only unit. Marking her permits consideration of her needs, subject to neediness, opt-out and other eligibility rules. This addresses review r3 P3.Tests and hand-computed expectations
Review r3 adds three paired-year input-contract scenarios: a named step-parent's exclusion from membership and member income under a complete annual override; the same override restoring an NPCR when the natural parent is absent; and a known-absent-parent grandmother changing from child-only to consideration as NPCR when explicitly marked. The automatic named-step-parent outcomes remain asserted as evidence of the disclosed limitation. These fixtures verify the documented inputs, not step-parent deeming.
The new focused differential property restates the three
b9e7fff948caf4f33313c942c09caa7c7ccc3deaformulas independently on 224 controlled households (784 people) per mode. With parent ids omitted or explicitly zero, invariants are unchanged age-and-own-child parent flags, unmarked caretaker presumption, parent-in-home NPCR exclusion, SSI exclusion, membership, unit size and zero-income payment. It covers age gaps 11/12/50/51, 18-year-old secondary-school status, zero/nonzero own-child counts, marked caretakers, spouses and SSI receipt. Existing property and differential coverage remains.Review-documentation regressions are evidence-only audits: the reviewed head fails the P1 dataset/equivalence disclosure and P2/P3 caller-contract checks; the updated body and variable documentation pass. A documentation-only remedy cannot honestly create a failing-before/passing-after model result; the new behavioral fixtures characterize the unchanged model and its supported overrides.
D1049 adds YAML cases for an adoptive parent with a 55-year age gap and explicit parent ids, an unrelated adult 30 years older when the child's ids name someone else, and unchanged age-window behavior when both ids are
0. The property tests check that known parent-id relationships give the same parenthood result across age changes. The grandmother case and all existing cases remain.R3 validation at
87d460fd1a6bf5fb8f7054fb7632f1234bd1ac15on Python 3.13.9 / Core 3.32.15: 3 new paired-year YAML scenarios and all 29 expanded parent-property tests passed, including both 224-household unknown-id modes. Each file ran separately in the foreground.make format, lint and whitespace checks passed. The P1 and P2/P3 documentation audits failed against the preserved reviewed-head body/source and pass against this body and committed source. Formula ASTs are unchanged in this round, and the existing NPCR property file and all existing YAML cases remain intact. Partner files are untouched and partner tests were not rerun in this round. No microsimulations were run.Saved validation at the reviewed d1049 head on Python 3.13.9 / Core 3.32.15: 13 parent YAML cases, 17 existing membership YAML cases, and 27 property tests passed. The new property spans 270 explicit-id combinations, including repeated ids in separate households.
make formatand lint passed. Each test file ran separately in the foreground; no microsimulations were run.Against
baf3fd187a16b0a77116f088a6d17ba1152d5027, the expanded parent YAML produced 10 assertion failures and 3 passes, and the new explicit-id property failed (1 failed, 26 deselected). Only main's two leaf input definitions were supplied as baseline prerequisites; the three Missouri formulas remained byte-for-byte unchanged. The named-head fixture was also rechecked with SSI explicitly zero and still failed on the baseline parent flag. The updated implementation passes all new cases. Original property functions and YAML cases, including the grandmother regression, are preserved; partner contract test expectations are untouched. Main was merged to reuse #9406's parent-id inputs and shared household-resolution helpers. Baseline failure receipts and final passing logs are retained outside the committed tree.[true, true, false], size two, and$234.08628(678 × 0.34526). It closes a coverage gap: main and the old PR head pass, while droppinghas_dependent_childmust fail.$14,400produce size four and$1,200monthly countable income. That exceeds the$990need standard, so the grant is zero. Main excludes the mother and pays$292.08996to the children.$341.8074(990 × 0.34526),$49.71744/monthabove main.R2 adds two annual-input YAML cases and a real separate-return parent case. The annual tests verify that an explicit 2026 override leaves the 2025 and 2027 defaults active, and that January's parent flag still governs July membership after the older child ages out. All people's monthly ages are supplied in the snapshot fixture, because a partial monthly-age input otherwise fills unspecified people with zero. The separate-return case expects parent flags
[false, false, true], membership[true, true, false], size two, and$234.08628, documenting the unsupported legally mandatory father.Historical r2 targeted validation ran one YAML file at a time on Python 3.14.4 and Core 3.32.8: the annual parent-input file passed both cases, and the membership file passed all 17 cases, including the real separately filing parent. Each of the three r2 cases passed. Formatting and lint passed at r2; its formula ASTs matched
b9e7fff, and partner test files were untouched. These are historical r2 results, not checks of the d1049 formula.Saved pre-r2 evidence passed 214 Missouri TANF YAML cases across 26 files, 66 property cases, four explicit-source-role checks, four input-definition cases, and 623 partner cases across 144 files. Both YAML folders ran with one worker, and partner expectations remain unchanged. The pre-r2 member file passes all 16 cases; removing
has_dependent_childfails the intended guard case, while the original 14-case file passes that mutation. The saved properties detect both the guard removal andnpcr_never; the original properties pass both mutations. Every intended failure is a saved call-phaseAssertionError. The original PR head passes all 16 pre-r2 member cases; frozen main has five passes and eleven expected call-phase assertions, including the income-loss and zero-income pair.Missouri non-parent caretaker (NPCR) behavior changes despite those unchanged partner expectations. Review r1 identifies three revised non-partner expectations, which it checked against 13 CSR 40-2.300(5)(C) and (D) and found to move in the legally correct direction:
$234.08628.$234.08628.adult_parentmembership to be true rather than false. Its test is renamed to describe that current behavior.The original evidence workflow remains failed: its case-sensitive detecting-name wrapper misses the authored guard title, and its two cross-checkout comparisons initially encountered pytest
ImportPathMismatchError. The successful minimal continuation reran only those two comparisons from an exact temporary fixture outside the package checkouts. Combined saved-evidence validation isvalid=true,errors=[], with completed controller provenance checked and 126 source files preserved; all other completed tests and simulations were reused byte-for-byte. The original failing receipts and wrapper exit remain preserved. See the compact artifact and full evidence report. Normal PR CI is a separate check.Saved pre-d1049 performance evidence: the added Python coverage checks the complete NPCR identification vector and converse, while retaining the existing simulation-isolation grid. It belongs to the existing Rest/core CI group. On the sequential Linux runner, both property files took 55.25 seconds wall / 55.56 seconds CPU, peak RSS 1,242,112 kbytes. The old/new dependent-property commands, each including import/setup and three mutation sessions, took 86.08 / 85.80 seconds wall, with peaks 1,198,112 / 1,201,612 kbytes. Their unmutated pytest sessions were 24 cases in 14.55 seconds versus 26 in 14.57 seconds; per-session CPU/RSS were not separately measured. These are single-run measurements, not a measurement of the whole Rest group. Permanent CI routing and runner count are unchanged; all evidence runs are sequential.
Payment expectations retain the model's unrounded convention; payment rounding is a separate limitation.
Parent-pointer evidence
The precision and recall figures below record the saved age-window evaluation before d1049, not a new run of the explicit-id-first formula. The direct schema/digest check above now establishes that this pinned default dataset contains neither PolicyEngine parent-id input. For this dataset, d1049 therefore uses the same fallback relationship rule as
b9e7fff; this is an equivalence inference by construction. The raw CPS pointers used for the historical evaluation are distinct from loadedparent_1_id/parent_2_idinputs.The saved 2026-10-06 rescore uses the actual
noneschool variant, rather than imputing school enrollment fromA_HSCOL. A direct read of the pinned Populace HDF table's 318 person-column names confirms thatA_HSCOLexists butis_in_secondary_schooldoes not. The school input defaults to false in the model.These figures measure agreement with resolved CPS parent pointers among the tax-dependent, non-child candidate population with a dependent child in its own tax unit. They are not a legal determination of parenthood. The Populace build is
populace-us-2024-spm-20260909, snapshot9a814a3b3b53c0ecd6e1737b6ec862c31300ef6f, SHA-2566496cc4393d4d3c6574f76eca231de5898c803b9067645591fd5c4d3e65aee84.none)In Populace, the guarded default retains three false positives and loses two pointer parents, all with very small weights. Missouri has only four selected records, three distinct source persons, and Kish effective sample size 2.92; pointer precision and recall are 100% in that thin sample. The pooled Census Missouri sample selects no candidates, so its precision and recall are undefined. The Census tax-unit artifact explanation is an inference from the observed structures.
The out-of-unit-parent statistic runs in this direction: 73% of parents in another tax unit from their child cohabit with the child's other parent. It does not establish that most cohabiting parents file separately. Parents whose own tax unit has no dependent child remain outside this implementation even when their child lives in the same SPM unit.
Unknown-id relationship regressions can raise or lower grants
The available child count and ages cannot establish the correct relationships when both parent ids are unknown. The retained fallback can wrongly add a dependent adult: with no income, their needs raise the grant; with income, counting it can reduce or eliminate the grant. These fallback regressions run in both directions. The table records saved pre-d1049 outcomes, which remain applicable to these fixtures with unknown parent ids; known parent ids now take precedence.
$234.08628$292.08996$234.08628$292.08996$500/monthUC; child 12$234.08628$0The two zero-income cases each overpay
$58.00368/month, or$696.04416/year. The UC case underpays$234.08628/month, or$2,809.03536/year: the grandmother's 46-year gap passes the 12–50 imputation window, and her income eliminates the grant. This is the PR's own grandmother-with-UC test. Callers can now supply the child's parent ids when those relationships are known; the derived parenthood flag can still be overridden explicitly. The grandmother case remains unchanged when the ids are unknown.Impact and resources
The saved unmodified-dataset comparison reports $0 entitlement change and $0 takeup-adjusted/actual TANF change against frozen main. The direct dataset-coverage check establishes that d1049 adds $0 further change relative to
b9e7ffffor this exact pinned Populace dataset, both unmodified and under the saved NPCR/bank-asset interventions, which did not supply parent ids. This follows by construction from absent parent-id columns, zero-default leaf inputs, and the unchanged unknown-id branches; it is an equivalence inference, not a fresh microsimulation. All impact table figures remain historical paired measurements against the recorded frozen main, and no current-head comparison with today's main was measured. No new microsimulations were run; data containing supplied parent ids remains outside these population impact claims.The excluded-grandparent resource defect predates this PR. A marked grandparent's separately owned
$5,000still counts against the otherwise asset-free mother/child unit, producing zero rather than$234.08628. The legal counterexample is preserved outside the passing suite with a prepared resource follow-up. Saved household checks also confirmed the opposite error on the then-tested main, original head and candidate: an included NPCR's spouse's$5,000is dropped, leaving zero countable resources and a$234.086273grant. Those resources must count under current Manual 10.11. Excluding every nonmember would be wrong because excluded financially responsible people can still contribute resources.The completed source run compares frozen main
5b1d5bdf47044607341d76f3c932ba2e7b74a060with candidateb9e7fff948caf4f33313c942c09caa7c7ccc3dea, through evidence checkoute39bb2c4c248ac4699032d7053f7429213014e75. Candidate and evidence checkout have identical model, test and changelog contents. All twelve simulations completed on Python 3.14.7 and Core 3.32.15, using the exact default dataset digest above. The full population was 166,321 people / 59,900 SPM units; saved Missouri diagnostics contain 2,892 people / 1,051 units. Each intervention applied to both codes, with identities, weights and intervention vectors checked before comparison.$0$0$0−$20,456,426.63−$1,704,702.22$0−$15,230,533.09−$1,269,211.09$0$0$0$0−$20,311,380.00−$1,692,615.00$0−$15,122,540.56−$1,260,211.71$0The gain/loss counts are SPM-unit entitlement records from the saved paired main/
b9e7fffcomparisons, identical in every month in each scenario/year. Actual TANF records gaining/losing are0 / 0in all six rows. These saved impact runs were not rerun for r2.Every month's payment, membership and failure partition equals January's within each scenario/year; the twelve monthly entitlement sums reconcile to annual totals. Actual annual Missouri TANF remains
$5,497,666.85in 2026 and$5,458,685.75in 2025 on both codes; national actual TANF changes are also zero. The separately saved entitlement × takeup diagnostic is unchanged and is not substituted for actual TANF.Four members are added in four units every month, with none removed: 22,417.537 weighted in 2026 and 22,258.586 in 2025. Under unmodified data, all four units fail income tests and three also fail resources. After marking, SPM 17211's mandatory mother's disability income (
$1,290.69/monthin 2026,$1,247.64in 2025) eliminates the children's$292.089966/monthgrant; there is one new income failure and no new resource failure in each month. SPM 76134 still fails on its own parent's income after bank assets are zeroed. Zeroing bank assets lets SPM 1017211 gain$49.717438/month; SPM 1134143, with tiny weight, gains$98.399094. None of the four affected records takes up TANF. SPM 17211 and 1017211 account for 99.999232% of absolute annual change in the bank sensitivity. Complete drivers, failure partitions and receipts are in the evidence report.For context, the saved 2026-09-29 study measured the following 2026 sensitivities under core 3.32.8 and branch
0771d2c498. These are historical results, not measurements against today's main. Its unmodified comparison used then-branch code with the parent flag off; its marked sensitivities separately executed pre-branch code10e3f989ba.$0$0$0−$20,456,424(−15.7%)−$1,704,702$0−$15,230,525(−9.5%)−$1,269,211$0Four members, about 22,418 weighted, were added in the unmodified study. All four affected units failed the income tests, and three also failed the resource limit. Grandparents' income alone does not explain all the failures: the mandatory mother's disability income eliminates one children's grant after marking, while another unit retains income from its own parent. In the asset sensitivity another mother/children unit gains
$49.71744/month. Two records weighted about 5,836 and 8,759 dominate the totals; none of the moved records takes up TANF.