Skip to content

Gate the DC EITC ITIN extension to 2023 and apply the IRC 152(c)(2) relationship test to EITC qualifying children - #9643

Merged
MaxGhenis merged 9 commits into
PolicyEngine:mainfrom
MaxGhenis:dc-eitc-itin-relationship-fixes
Oct 7, 2026
Merged

MaxGhenis merged 9 commits into
PolicyEngine:mainfrom
MaxGhenis:dc-eitc-itin-relationship-fixes

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

axiom: TheAxiomFoundation/rulespec-us#1420 queued (D.C. Code § 47-1806.04(f)); TheAxiomFoundation/rulespec-us#1502 queued (26 USC 152(c)(2))

This PR fixes three pre-existing gaps that the independent review of #9549 found in the DC EITC. The third one also affects the federal EITC and five other state credits.

Ruling d1008 round, 2026-10-06

Max's ruling (d1008, 2026-10-06). For TY2021–22, a DC filer whose qualifying children have neither a Social Security number (SSN) nor an ITIN gets DC's childless credit, as on main. This head keeps main's routing for that filer in every year before 2023. The rest of the PR stands as reviewed: the 2023 ITIN gate, the Line 27a rule from 2023, the IRC 152(c)(2) relationship test and the 23-149 citation fix.

What changed (commits f63d0ba086 and e89c2b6f9c; head e89c2b6f9c):

  • Parameter. gov.states.dc.tax.income.credits.eitc.qualifying_child_tin_required is now true from 2015-01-01. The previous head had it false for 2015–2022 and true from 2023. A qualifying child now needs an SSN or ITIN in every year to put the unit on the with-child schedule.
    • ITIN children are unaffected, because has_tin is true for them. Before 2023 they still route with-child and get the match on the federal credit allowed.
    • The ITIN extension still starts in 2023 (itin_eligible).
    • The parameter's only formula reader is dc_eitc_has_qualifying_child, and its value in 2023 and later is unchanged.
  • References. The parameter now also cites (f)(4), ARPA § 9622, the 2021 booklet's "New for 2021" note (PDF p. 3) and its "Qualifying Child for EITC Purposes" page (PDF p. 12, review P3-2). Its comment and the dc_eitc_has_qualifying_child comments state both readings; see Methodology choices.
  • YAML. The four TY2021–22 cases with a no-TIN child now expect main's values (table below). The two TY2021–22 cases that used to expect the other reading now switch the parameter off and keep those values. The two TY2023 parameter-off cases are unchanged. The double blank line flagged in review P3-4 is gone.
  • Hypothesis. Two of the old invariants are false before 2023 under the ruling, so they are restated. Invariant 9 now checks, in every year, that an ITIN child routes like an SSN child, and that a qualifying child with neither number gives the same routing and the same dc_eitc as the same filer with no dependent. That compares two different households, so it no longer restates the formula (review P3-3). Invariant 10 ("removing a qualifying child's TIN never raises dc_eitc") is now checked from 2023 only; before 2023 a violation is intended. A new property test, test_dc_eitc_without_tin_rule, switches the parameter off through a reform and checks the other reading (invariants 11–13 below). Before this round no Hypothesis test switched the parameter off (review P3-3). e89c2b6f9c builds that reformed system in a module-scoped fixture and releases it when the module ends, rather than caching it for the whole pytest process (see the CI cost note under Invariants).
  • Changelog. The fragment no longer says the PR keeps no-TIN filers on the with-child schedule before 2023.
  • Main is merged at 4c900b6d3d (92802f507c, clean, no PR file conflicted).

The TY2021–22 households with a no-TIN child. Each is a DC head of household aged 50 with an SSN and one dependent with neither an SSN nor an ITIN.

TY Wages Dependent Previous head 92802f507c Main 4c900b6d3d and this head Hand check
2022 20,000 disabled adult child 0 560 (f)(1)(C): min(7.65% × 20,000, 560); 20,000 is below the 20,532 phase-out start
2022 20,000 child aged 10 0 560 same
2022 6,000 disabled adult child 321.30 459 7.65% × 6,000
2021 20,000 disabled adult child 87.33 1,480.21 min(15.3% × 20,000, 1,502) − 8.48% × (20,000 − 19,743)

Checked against main. The four cases above were also run on main 4c900b6d3d, in a detached checkout with only those cases added (the dc_eitc_has_qualifying_child output dropped, since main has no such variable). All four pass there, with the same eitc, both branch values and dc_eitc. So for these households this head reproduces main. Main's router at 4c900b6d3d requires has_tin for a DC qualifying child in every year.

Tests before and after. All runs were local, in the foreground, one process at a time, each a single test file (the host test-run rule lets a single file run outside the shared heavy lock, which had about 25 waiters). Python 3.14.7 and policyengine-core 3.32.8, from uv sync --locked --extra dev, as CI installs.

  • Before (fail-before). A separate detached checkout at 92802f507c, with only this round's dc_eitc.yaml and invariants file copied in:
    • dc_eitc.yaml: 4 failed, 21 passed. The four failures are exactly the four no-TIN TY2021–22 cases above, each on dc_eitc_has_qualifying_child (1 instead of 0). The four parameter-off cases pass, as expected, because they switch the parameter off themselves.
    • test_eitc_qualifying_child_invariants.py: 1 failed, 2 passed. test_dc_eitc_invariants failed on invariant 9 in TY2021, because the no-TIN child kept its unit on the with-child schedule. Hypothesis minimized the draw to earnings 0, head aged 19, child aged 0. test_dc_eitc_without_tin_rule and test_relationship_dominates_disability_across_credits passed. That is expected: the old head already applied reading A before 2023, and the relationship test did not change.
  • After: dc_eitc.yaml 25 passed and 0 failed at f63d0ba086. test_eitc_qualifying_child_invariants.py passed 3 of 3 at f63d0ba086, and again with e89c2b6f9c's fixture change. e89c2b6f9c changes only that test file. ruff format --check . (6,642 files) and ruff check . pass. CI runs the full suite on this head.

Impact. Not yet measured against the current merge base; the hub will run it. See Impact below.

Axiom. The rulespec-us#1420 comment with ruling 6 and companion cases T10–T13 was written before d1008 and encodes the other reading. This round posted a correction on that issue: rulespec-us#1420 (comment). It revises ruling 6 to the childless treatment in every year and gives the corrected values T10 560, T11 459 and T12 1,480.21; T13 (600) is unchanged. It also restates the properties: no number gives the same result as no dependent, and "removing a TIN never raises dc_eitc" holds from TY2023. The axiom: line is unchanged: #1420 stays queued.

Methodology choices

Where a DC filer whose qualifying children have neither an SSN nor an ITIN claims, before TY2023. No DC source settles TY2015–2022, and the two readings below give different credits. From TY2023 the D-40 Line 27a instructions settle it ("Each qualifying child must have a valid social security number (SSN) or individual taxpayer identification number (ITIN) issued by the IRS. If you have no children who qualify, you must claim the DC EITC without qualifying children."), so later years involve no choice.

  • Reading A, the statute alone. D.C. Code § 47-1806.04(f)(4) gives "qualifying child" its IRC 32 meaning. IRC 32(c)(3)(D) only keeps a child without an SSN out of the § 32(b) computation; it does not stop the child being a qualifying child. (f)(1)(C) is limited to "an individual without a qualifying child", so it is closed to the filer, who gets the (f)(1)(B)–(B-2) match on the self-only federal credit allowed, as with an ITIN child. The 2021 and 2022 booklets' qualifying-child rules have no identification test. The previous heads ca69e109de and 92802f507c did this before 2023.
  • Reading B, "childless" (chosen). ARPA § 9622 is headed "Taxpayer eligible for childless earned income credit in case of qualifying children who fail to meet certain identification requirements", and from TY2021 it struck former IRC 32(c)(1)(F). The 2021 D-40 booklet's "New for 2021" note (PDF p. 3) passes this on: "Taxpayers may now be eligible for childless earned income in the case of qualifying children who fail to meet certain identification requirements." From TY2023 OTR's Line 27a sends the filer to the childless credit. Main has always routed the case this way, in every year.

What the model does. Max ruled for reading B (d1008, 2026-10-06). qualifying_child_tin_required is true from 2015-01-01, so in every year dc_eitc_has_qualifying_child counts a qualifying child only if it has an SSN or ITIN, and a filer whose children have neither takes the (f)(1)(C) childless schedule. This keeps main's behaviour for TY2015–2022.

How to turn it off. Set gov.states.dc.tax.income.credits.eitc.qualifying_child_tin_required to false, in a reform or as a YAML test input. dc_eitc_has_qualifying_child then follows qualifying-child status alone, so a child with neither number keeps the unit on the with-child schedule. Before 2023 that pays the match on the federal credit allowed (reading A). From 2023 it pays the match on the (f)(1)(D)(ii) amount computed without that child, which departs from Line 27a. In that case the with-child branch applies the childless age test when no child is in the count, as the federal credit does. Four YAML cases (TY2021, TY2022 and two TY2023 cases) and the Hypothesis test test_dc_eitc_without_tin_rule cover the switched-off path.

An intended consequence. Under reading B, before 2023, giving a qualifying child no number instead of an ITIN can raise dc_eitc, because DC's childless schedule can pay more than the with-child match on the self-only federal credit. In TY2022 at $6,000 of wages, an ITIN child gives 70% × 459 = 321.30 and a child with no number gives the childless 459. Invariant 10 is therefore checked only from 2023.

Review round, 2026-10-06 (earlier fix round)

The gate review of 06f7d19db9 found one problem. dc_eitc_has_qualifying_child required has_tin when it chose between the with-child and childless schedules. For TY2022, a 50-year-old SSN filer with $20,000 of wages got $0 with an ITIN child, and $560 from the (f)(1)(C) childless schedule once the child had no TIN.

That round (head ca69e109de) made the routing depend on the tax year through the new parameter qualifying_child_tin_required, false before 2023 and true from 2023. Before 2023 that applied reading A above. Ruling d1008 replaced that pre-2023 routing (see the round above). What remains from that round:

  • From 2023 a qualifying child needs an SSN or ITIN, citing Line 27a, which applies to every filing status.
  • The with-child base's 2023+ demographic test is (child_count > 0) | eitc_demographic_eligible. For every unit this branch covers with the parameter on, the value is the same as the old child_count > 0. It differs only with the parameter switched off: a unit with no child in the count must then meet the childless age rules, as the federal credit requires.
  • Main was merged (50464ee65b, then b812bd46a0); pyproject.toml and uv.lock match main.

Sources by year. Where a qualifying child with neither an SSN nor an ITIN routes:

TY Instruction (OTR D-40 booklet, PDF page) Schedule in this PR
2021 None for children. "Qualifying Child for EITC Purposes" (p. 12) sets relationship, age, disability, residence and marital-status rules but no identification requirement. The "New for 2021" note (p. 3) passes on ARPA § 9622 childless (f)(1)(C), by ruling d1008
2022 None. Same rules (p. 11), and Line 27a (p. 19) says only "Refer to Instructions, page 11" childless, by ruling d1008
2023 Line 27a (p. 18): "Each qualifying child must have a valid social security number (SSN) or individual taxpayer identification number (ITIN) issued by the IRS. If you have no children who qualify, you must claim the DC EITC without qualifying children." Also p. 10 childless
2024 Same text, pp. 10 and 18 childless
2025 Same text, pp. 13 and 21 childless

The reviewer's household:

TY2022, $20,000, SSN head aged 50 06f7d19db9 ca69e109de and 92802f507c this head and main
ITIN child 0 0 0
child with no TIN 560 0 560

Impact

Real microsimulations for 2025 and 2026 on the default dataset, hf://datasets/policyengine/populace-us/populace_us_2024.h5@populace-us-2024-spm-20260909. Base: this PR's merge base, main dd9cb3f683 (re-run after the main merge). Branch: this head, 7422391a46. Each side ran in its own process from a detached checkout, one run at a time under the hub's shared heavy lock, and each run's recorded module path confirms it imported its own checkout. Outputs were compared record by record with compare.py.

Nothing changes. All variables present on both sides are bit-identical in both years, both before and after the main merge (the re-run also covers mn_child_and_working_families_credits, which the merge touched). No person, tax unit or household differs. The variables:

  • dc_eitc, dc_income_tax and both DC branches;
  • eitc, eitc_child_count, and the CA, CO, IL, MN and WA credits;
  • income_tax, state_income_tax and household_net_income;
  • the person flags.
2025 2026
DC EITC (unchanged) $132.0M $134.2M
DC EITC recipients 72 records, 56,367 weighted units (50 with-child, 22 childless) 71 records, 55,783 weighted units (49 with-child, 22 childless)

This is expected. With ruling d1008, qualifying_child_tin_required is true in every year, so the default reproduces main's routing. The dataset also has no one without a TIN (has_tin is false for 0 of 166,321 people) and no parent, grandparent or permanently disabled flags set. The PR's changes only bite in household calculations that supply those inputs, which the YAML cases cover. DC invariants 4 and 5 hold on the branch arrays.

Evidence: ~/reviews/us-hub/fixes/9643-evidence/finish3/impact/summary.txt.

1. Wrong citation for the DC ITIN rule

The DC EITC variables and one test cited D.C. Law 23-149 for the ITIN rule. That law is the Fiscal Year 2021 Budget Support Act of 2020, and it has no EITC, § 47-1806.04 or ITIN language. The rule is D.C. Code § 47-1806.04(f)(1)(D). It was added by D.C. Law 24-167 § 7012, the Earned Income Tax Credit Expansion Amendment Act of 2022, and it applies to taxable years beginning after December 31, 2022. The section's history note lists "D.C. Law 24-167, § 7012" and never mentions 23-149. Every 23-149 citation under policyengine_us/ is replaced; the only remaining mention is the historical CHANGELOG.md entry.

2. ITIN eligibility now starts in 2023

The router and both DC branches accepted ITIN filers and ITIN children in every year. A new parameter, gov.states.dc.tax.income.credits.eitc.itin_eligible, is false before 2023 and true from 2023-01-01.

  • With-child branch. (f)(1)(B)–(B-2) match "the earned income tax credit allowed under section 32". Before 2023 the base is therefore the federal eitc itself. That credit leaves out a qualifying child without a Social Security number (IRC 32(c)(3)(D)) and denies an ITIN filer (IRC 32(c)(1)(E)). From 2023 the base is the existing federal-like amount, computed as if an ITIN met IRC 32(m).
  • Childless branch. Before 2023 the filer needs the federal Social Security number (filer_meets_eitc_identification_requirements).
  • Routing. A qualifying child with an ITIN keeps the unit on the with-child schedule in every year. Before 2023 IRC 32(c)(3)(D) only keeps that child out of the § 32(b) computation, so the unit gets the match on the self-only federal credit allowed and cannot use the (f)(1)(C) childless schedule. This follows ruling 3 in rulespec-us#1420. A qualifying child with neither an SSN nor an ITIN does not count in any year (qualifying_child_tin_required; see Methodology choices).

The example household is a DC head of household aged 50 with $20,000 of wages and a 30-year-old dependent. The dependent is permanently and totally disabled and has an ITIN.

TY eitc dc_eitc on main (53c82c6c52) dc_eitc here Why
2021 218.33 1,416.52 87.33 40% × the ARPA childless credit actually allowed: 1,502 − 15.3% × (20,000 − 11,610)
2022 0 2,613.10 0 70% × 0, since 560 − 7.65% × (20,000 − 9,160) < 0
2023 0 2,796.50 2,796.50 (f)(1)(D)(ii): 70% × 3,995

The issue reported a 2021 value of 0. The statute gives 87.33, because under ARPA § 9622 the filer is allowed the self-only federal credit in 2021. In 2022 the same credit phases out to 0 at this income, which is why that year's value is 0.

All nine companion cases (T1–T9) in rulespec-us#1420 match this branch. The two that differed on main were T8 (2022, $20,000: now 0) and T9 (2022, $6,000: now 70% × 459 = 321.30). The no-TIN cases T10–T13 are covered under Axiom in the d1008 round above.

3. Disabled parents and grandparents are not EITC qualifying children

The EITC qualifying child is the IRC 152(c) qualifying child (IRC 32(c)(3)(A)). The 152(c)(3)(B) disability rule treats only the age test of 152(c)(3)(A) as met. It does not waive the 152(c)(2) relationship test, which admits only the taxpayer's children, siblings and their descendants. A parent or grandparent can be a qualifying relative under 152(d)(2)(C), but not a qualifying child.

Nine variables counted every permanently and totally disabled dependent as a qualifying child. The new person variable is_eitc_qualifying_child is (is_qualifying_child_dependent | disabled dependent) & ~(is_parent_of_filer_or_spouse | is_grandparent_of_filer_or_spouse). It replaces that pattern in:

  • federal eitc_child_count;
  • DC: the new dc_eitc_has_qualifying_child, which the router and both branches now share;
  • ca_is_qualifying_child_for_caleitc, co_eitc, il_eitc and mn_child_and_working_families_credits;
  • wa_working_families_tax_credit and wa_working_families_tax_credit_maximum_qualifying_income.

The IRC 32(c)(3)(D) identification requirement stays in each credit, since the states differ on ITINs. The research for this PR checked each state's law. CA RTC 17052, C.R.S. 39-22-123.5, 35 ILCS 5/212, Minn. Stat. 290.0671 subd. 1a, RCW 82.08.0206(2)(f) and D.C. Code 47-1806.04(f)(4) all take the IRC 32 qualifying child, changing only ITIN, residency and age rules. So the relationship test applies in every one.

Example: TY2023 head of household aged 50, with a dependent parent aged 75 who is permanently and totally disabled.

Case main here
Federal eitc, wages $6,000 2,040 (one-child 34%) 459 (childless 7.65%)
dc_eitc, wages $20,000 2,796.50 600 ((f)(1)(C))
dc_eitc, wages $20,000, parent has an ITIN 2,796.50 600
WA WFTC, TY2023, $10,000, ITIN filer and parent 625 315
MN CWFC older-child bonus +1,000 none

A disabled adult child still takes the with-child schedule, so the 152(c)(3)(B) waiver is unchanged.

Only parents and grandparents are excluded. PolicyEngine does not record other relatives outside 152(c)(2), such as aunts, uncles, in-laws or unrelated household members. is_related_to_head_or_spouse is not used, because an eligible foster child (IRC 152(f)(1)(C)) counts as a child even though it can be unrelated.

Invariants

These hold for every input the Hypothesis strategies draw (wages and interest), except where marked as an intended violation. One known exception sits outside that domain: farm income. A TY2023 DC filer aged 50 with an SSN, $6,000 of farm-only income and an SSN child gets $0, while removing the child's TIN gives about $426.57, which violates invariant 10. The cause is a farm-income defect in the shared earned-income helper that predates this PR; it is one of the follow-ups below. They are checked by the Hypothesis tests in tests/policy/baseline/gov/irs/credits/earned_income/test_eitc_qualifying_child_invariants.py:

  1. A dependent flagged as a parent or grandparent is never an EITC qualifying child. It never makes dc_eitc_has_qualifying_child true, and it never counts in eitc_child_count.
  2. For a parent or grandparent dependent, the disability flag changes no credit: eitc, dc_eitc, ca_eitc, co_eitc, il_eitc, mn_child_and_working_families_credits or wa_working_families_tax_credit. It is checked in each of DC, CA, CO, IL, MN, WA and TX.
  3. Making an adult child dependent disabled never moves a DC unit off the with-child schedule.
  4. Both DC branches are ≥ 0, and at most one is positive. dc_eitc == where(dc_eitc_has_qualifying_child, with, without) == max(with, without).
  5. The with-child branch is 0 without a qualifying child, and the childless branch is 0 with one.
  6. Before 2023, dc_eitc_with_qualifying_child == match × eitc whenever the unit has a qualifying child. This is a differential check against the federal variable.
  7. Before 2023, an ITIN filer gets dc_eitc == 0, and swapping a qualifying child's SSN for an ITIN never raises dc_eitc.
  8. From 2023, swapping a qualifying child's SSN for an ITIN leaves dc_eitc unchanged.
  9. In every year, an ITIN qualifying child routes its unit like an SSN child, and a qualifying child with neither number gives the same routing and the same dc_eitc as the same filer with no dependent.
  10. From 2023, removing a qualifying child's TIN never raises dc_eitc. Before 2023 it can, as intended (see Methodology choices).

With qualifying_child_tin_required switched off (reading A):

  1. Schedule selection follows qualifying-child status, whatever the child's identification.
  2. Before 2023, a qualifying child with no number gives the same dc_eitc as one with an ITIN, since IRC 32(m) treats the two alike.
  3. In every year, removing a qualifying child's TIN never raises dc_eitc.

Each Hypothesis example draws earnings, interest, the filer's age and the child's age. It builds one vectorized simulation that holds every combination of dependent kind, dependent ID, filer ID and state, and checks TY2021, 2022, 2023 and 2025. CI runs 8 derandomized examples for each property. The switched-off test builds its reformed tax-benefit system once per session and reuses it read-only. CI cost. The file runs in CI's Rest policy pytest group. At 92802f507c (run 37463810232) that group took 6:20 and peaked at 12.4 GB RSS on the 16 GB runner, and this file's two tests then took 7.7 s and 1.0 s. The new test adds one reformed tax-benefit system. It is built in a module-scoped fixture, used read-only, and collected when the module ends, so it does not stay resident for the rest of that group. The first version, f63d0ba086, cached it for the whole process. Local macOS measurements only, on a host at load 40–70 where file-system calls were starved, so not comparable to Linux CI: building the reformed system took 293 s, test_dc_eitc_without_tin_rule 155 s and test_dc_eitc_invariants 7.4 s, and the file peaked at 1.64 GB RSS (a bare model import peaked at 0.81 GB). The group's CI time and peak at this head will show in the Rest job's rest-test-timings artifact.

Mutation check. In the first round the tests were run against main's formulas, using shims that reproduce main's logic for the two new variables. Both property tests then failed: invariant 1 on the disabled-parent row, and invariant 6 (with invariant 1 disabled) on TY2021, minimized to earnings of $1. In the d1008 round, invariant 9 and the four no-TIN TY2021–22 YAML cases fail on 92802f507c's routing and pass here (see the round above).

Tests

  • dc_eitc.yaml (25 cases):
    • ITIN pairs for TY2021, 2022 and 2023, at $20,000 and $6,000;
    • no-TIN cases with the parameter on: TY2021, TY2022 (×3) and TY2023, all on the childless schedule;
    • four cases with qualifying_child_tin_required switched off: TY2021, TY2022, and TY2023 with heads aged 50 and 22;
    • an ITIN filer before and from 2023;
    • a disabled adult child against a disabled parent, grandparent and ITIN parent;
    • the Route a disabled adult dependent to the DC EITC with-child branch #9549 end-to-end case, with the correct citation and is_tax_unit_spouse: false.
  • is_eitc_qualifying_child.yaml (new), and eitc_child_count.yaml cases 6–8.
  • One disabled-parent case each for CA, CO, IL, WA and MN.
  • Hypothesis properties in test_eitc_qualifying_child_invariants.py, with invariants 1–13 above.
  • The d1008 round's runs are listed in that round above. The first fix round's run at ca69e109de: 904 passed across irs/credits/earned_income, all of states/dc, and states/{ca,co,il,mn,wa}/tax/income/credits.

Not in this PR

These gaps were found along the way. None has an issue yet; the hub's fix report lists them for filing.

  • Former IRC 32(c)(1)(F) is not modeled. Through TY2020, a filer whose only qualifying children lacked SSNs got no federal EITC; ARPA § 9622 struck the rule from 2021. PolicyEngine gives these filers the childless credit in every year. Before 2023 the DC with-child branch uses eitc, so a federal fix would carry over to DC. Until then, a TY2015–2020 DC filer whose only child has an ITIN gets 40% of the federal childless credit; the law gives 0. (A child with neither number sends the filer to DC's childless schedule under ruling d1008.)
  • CalEITC and ITIN children. ca_eitc counts children with the SSN-gated eitc_child_count, but RTC 17052(p) has accepted ITIN qualifying children since 2020.
  • State federal-like EITC amounts omit farm and partnership earnings. calculate_eitc_like_amount in tools/state_eitc_helpers.py phases in on filer_adjusted_earnings, which is built from earned_income: wages, self-employment and SSTB self-employment income. The federal eitc_earned_income also counts farm_operations_income and partnership_self_employment_net_earnings. The review of the first fix round found it. The bug predates this PR, and four variable files call these helpers.

The third follow-up in the earliest version of this body was that adult dependents defaulted to spouse. That is addressed by #9630, now merged into this branch: head_or_spouse_candidates drops adults input as tax-unit dependents whenever the unit has another adult.

🤖 Generated with Claude Code

MaxGhenis and others added 5 commits September 26, 2026 23:23
…elationship test to EITC qualifying children

- Cite D.C. Law 24-167 section 7012 (D.C. Code 47-1806.04(f)(1)(D)) for the
  DC ITIN rule instead of D.C. Law 23-149, which has no EITC language.
- Add gov.states.dc.tax.income.credits.eitc.itin_eligible (true from
  2023-01-01). Before 2023 the DC with-child credit matches the federal
  credit allowed and the childless credit needs a Social Security number.
- Add dc_eitc_has_qualifying_child so the router and both branches share one
  qualifying-child test.
- Add is_eitc_qualifying_child (IRC 32(c)(3)(A) / 152(c)): age test or the
  152(c)(3)(B) disability waiver, and not a parent or grandparent of the
  filer. Use it in the federal eitc_child_count and the CA, CO, DC, IL, MN
  and WA credits.
- YAML cases for TY2021/2022/2023 ITIN households and disabled
  parent/grandparent dependents, plus Hypothesis invariant tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Before 2023 a qualifying child without a Social Security number stays a
qualifying child whether it has an ITIN or no number at all: D.C. Code
47-1806.04(f)(4) adopts the IRC 32 definition, IRC 32(c)(3)(D) only keeps
the child out of the IRC 32(b) computation, and IRC 32(m) treats the two
alike. dc_eitc_has_qualifying_child still required has_tin, so a TY2022
SSN filer aged 50 with $20,000 of wages got $0 with an ITIN child but
$560 from the childless schedule once the child's TIN was removed.

From 2023 the D-40 instructions (2023 and 2024 booklets p. 10, 2025
booklet p. 13) say: "If you and your spouse have SSNs or ITINs but your
child(ren) do not, you need to claim the DC EITC for filers without a
qualifying child." The 2021 and 2022 booklets have no such rule. A new
parameter, qualifying_child_tin_required, is false before 2023 and true
from 2023, and gates the TIN test in the router.

The with-child branch's 2023+ eligibility now uses the router's
predicate instead of child_count > 0. The two agree under current law;
the change keeps the parameter coherent when it is switched off.

Tests: five YAML cases (TY2021, TY2022 x3, TY2023) plus a counterfactual
with the parameter off, and Hypothesis invariants 9 (routing follows
qualifying-child status; no TIN equals ITIN before 2023) and 10 (removing
a child's TIN never raises dc_eitc).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An independent review of the routing fix found three loose ends:

- The p. 10 sentence the router cited is framed around joint filers.
  Line 27a (2023 and 2024 booklets p. 18, 2025 booklet p. 21) states
  the rule for every filing status: "Each qualifying child must have a
  valid social security number (SSN) or individual taxpayer
  identification number (ITIN) issued by the IRS. If you have no
  children who qualify, you must claim the DC EITC without qualifying
  children." The router and the parameter now cite it.
- With qualifying_child_tin_required switched off, the with-child
  branch's 2023+ base skipped the childless age test that the federal
  credit, the pre-2023 base, applies. It now uses
  (child_count > 0) | eitc_demographic_eligible, which equals the old
  child_count > 0 for every unit the branch covers under current law.
  A new counterfactual case (head aged 22) fails on the previous commit
  (321.30) and passes here (0).
- The TY2022 $6,000 no-TIN case now asserts the routing too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis and others added 2 commits October 6, 2026 17:09
Max's ruling d1008 (2026-10-06): before TY2023, a DC filer whose
qualifying children have neither a Social Security number nor an ITIN
gets the childless credit, as on main.

- qualifying_child_tin_required is now true from 2015-01-01 (was false
  for 2015-2022). It cites D.C. Code 47-1806.04(f)(4), ARPA section
  9622 and the 2021 D-40 booklet (pp. 3 and 12) and states both
  readings; setting it to false applies the statute-alone reading.
- dc_eitc.yaml: the four TY2021-22 no-TIN cases expect main's values
  (560, 560, 459, 1,480.21); the two cases that held the other reading
  now switch the parameter off (321.30, 87.33).
- Invariant 9 now compares a no-TIN child with the same filer alone;
  invariant 10 is checked from 2023, its earlier violation intended.
  New test_dc_eitc_without_tin_rule checks the switched-off reading.
- Router comment and changelog fragment updated to match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_dc_eitc_without_tin_rule built its tax-benefit system with
qualifying_child_tin_required switched off through functools.cache,
which kept a second full system resident for the rest of the pytest
process. CI runs this file in the Rest "policy" group, which peaked at
12.4 GB RSS on the 16 GB runner at 92802f5 (run 37463810232). Build
it in a module-scoped fixture instead, used read-only, and collect it
when the module finishes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit to MaxGhenis/policyengine-us that referenced this pull request Oct 7, 2026
…convention

Review follow-ups:
- The addback defaulted to foreign_earned_income_exclusion through `adds`,
  which passed a negative entry straight through. Every federal reader of
  that input floors it at zero (worksheet line 2c: "If zero or less, enter
  -0-"), so the default is now max(0, foreign_earned_income_exclusion). A
  YAML case covers a -5,000 entry.
- The documentation now states that other income inputs must already
  exclude the line 43 amount, says the default equals line 43 when line 50
  equals line 44 plus line 2b (not "only when" all are zero), keeps line
  2b's "or exclusions", and cites the 2025 Form 1 instructions (line 3).
- The property tests release the reformed system and cached results when
  the module ends, as PolicyEngine#9643 does, and the Hypothesis test is derandomized.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Preserve Minnesota's updated EITC earned-income calculation alongside
this branch's qualifying-child relationship rule. Keep both sides' MN
regressions and align the disabled-parent fixture with eitc_earned_income.
@MaxGhenis
MaxGhenis merged commit fc71844 into PolicyEngine:main Oct 7, 2026
35 checks passed
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

US + core hub merge audit, us#9643 at 7422391a46dd76bdf92f6f3cd0e2f8449342db15 (squash)

  • Review: independent review APPROVE at e89c2b6, then delta review APPROVE at 7422391 (main merge; MN conflict resolved keeping both sides), with no new P1 or P2.
    • Its METHODOLOGY_CHOICE flag is the TY2021–22 no-TIN routing. Max ruled on it in d1008: the childless credit, as on main. It's implemented by qualifying_child_tin_required, which is true from 2015 and has one reader.
    • Both P3s are applied to the body (description-only; the head is unchanged): the invariant claim is narrowed to the drawn domain, with the known farm-income exception, and the impact section is refreshed.
  • Gates checked live at merge:
    • gh pr checks exits 0;
    • MERGEABLE;
    • not a draft;
    • no CHANGES_REQUESTED review;
    • head pinned with --match-head-commit.
  • Impact: real microsims, merge base 4c900b6d3d against this head, 2025 and 2026, on the default dataset. Each run's module path confirms it imported its own checkout.
    • All 19 shared variables are bit-identical, including dc_eitc, dc_income_tax, household_net_income and the other state EITCs. The dataset has no person without a TIN.
    • The fixes bite only in household calculations that supply those inputs.
  • --admin: used only because a required approving review is the sole block.
  • Follow-ups, unfiled pending Max's go:
    • farm and partnership earnings in state EITCs;
    • pre-2021 IRC 32(c)(1)(F);
    • CalEITC ITIN children.

MaxGhenis added a commit that referenced this pull request Oct 9, 2026
* Add excluded foreign earned income to Massachusetts gross income

M.G.L. c. 62 s. 2(a)(1)(C) lists "Earned income from foreign sources
excluded under section nine hundred and eleven of the Code" among the
items added to federal gross income. ma_gross_income subtracted the
federal stacking amount instead, so a $10,000 exclusion left Massachusetts
gross income $20,000 too low.

The new TaxUnit input ma_foreign_earned_income_exclusion_addback is the
section 911(a) amount actually excluded (Form 2555 line 43, before line 44
allocable deductions, without the line 50 housing deduction). It defaults
to foreign_earned_income_exclusion, which is exact when Form 2555 lines 44
and 50 and Foreign Earned Income Tax Worksheet line 2b are zero; an
entered amount, including zero, replaces the default. The restored wages
reach Part B through its residual definition in s. 2(b)(2); Parts A and C
are unchanged.

Adds the hub spec's five YAML cases plus explicit-zero, non-MA and
zero-floor controls, and property/differential tests against the old
formula.

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

* Check that the MA foreign earnings addition offsets losses before the floor

The zero-floor property only checked that gross income is non-negative,
zero at the floor and monotone in the addback. The formula before this
change satisfies all three, so the test passed on main. It now also checks
that where federal gross income less the Massachusetts exclusions is
negative but the addback lifts it above zero, gross income equals their
sum, which main gets wrong (it returns zero).

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

* Floor the MA foreign earnings default at zero and document its input convention

Review follow-ups:
- The addback defaulted to foreign_earned_income_exclusion through `adds`,
  which passed a negative entry straight through. Every federal reader of
  that input floors it at zero (worksheet line 2c: "If zero or less, enter
  -0-"), so the default is now max(0, foreign_earned_income_exclusion). A
  YAML case covers a -5,000 entry.
- The documentation now states that other income inputs must already
  exclude the line 43 amount, says the default equals line 43 when line 50
  equals line 44 plus line 2b (not "only when" all are zero), keeps line
  2b's "or exclusions", and cites the 2025 Form 1 instructions (line 3).
- The property tests release the reformed system and cached results when
  the module ends, as #9643 does, and the Hypothesis test is derandomized.

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

* Use the specified Massachusetts foreign earnings fallback

* Floor Massachusetts foreign earnings addback at zero

* Add section 911 exclusion and deduction leaf inputs

* Derive federal and Massachusetts section 911 amounts from leaves

* test: cover ambiguous section 911 batches and zero stacking CTC

* fix: reject ambiguous section 911 tax-unit input histories

* fix: integrate Form 2555 leaves with MAGI and CTC eligibility

* test: keep Form 2555 policy examples in variable YAML files

* test: preserve main capital-loss allocation in section 911 coverage

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@MaxGhenis
MaxGhenis deleted the dc-eitc-itin-relationship-fixes branch October 14, 2026 06:21
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.

1 participant