Repository navigation
Conversation
PR Review: Fix pre-2018 AMT child exemption and income basePR #10308 (author: MaxGhenis), head
The PR has no comments or reviews yet. It touches no partner test file. Path prefixes:
Sources read for this review (all fetched 2026-10-21):
SummaryWhat is right.
There are no critical findings and three should-address items:
There are also four suggestions: the stale PR body, gaps left in the child test, pre-existing pre-2018 AMTI gaps, and references for the pre-2019 child amounts. Status.
Critical (must fix)None. Should addressS1. The Axiom line
|
| Case | Taxable income | AMTI | amt_exemption |
amt_income_less_exemptions |
amt_base_tax |
Old base |
|---|---|---|---|---|---|---|
| Itemizer: interest 60,000; SALT 6,000; misc 1,500 (2,700 of expenses less 2% × 60,000); charity 1,000; exemption 4,050 | 47,450 | 59,000 | 7,500 | 51,500 | 13,390 | 39,950 |
| Wages 46,000 + interest 30,000; standard deduction 6,350; exemption 4,050 | 65,600 | 76,000 | 53,500 (cap binds) | 22,500 | 5,850 | 12,100 |
| Wages 47,000 + interest 30,000; same deductions | 66,600 | 77,000 | 54,300 (cap 54,500 does not bind) | 22,700 | 5,902 | 12,300 |
- The itemizer row. Line 1 = 60,000 − 8,500 = 51,500. Add line 3 (6,000) and line 5 (1,500) to get 59,000. The charitable deduction stays deducted. AGI is below the $261,500 Pease threshold.
- The wage rows sit on either side of the boundary at earned income of $46,800, where 46,800 + 7,500 = 54,300.
S3. The Python property test keeps old formulas, locks in the old predicate and has no cost report
- Where:
T/test_post_2017_child_amt_invariance.py. - What it does. Lines 36-74 restate both old formulas as a
Reform. Lines 77-79 build that reformed system in a module fixture. The test then compares the two systems over 2018-2030 for about 365 tax units in each of 3 Hypothesis examples. - It locks in the old predicate. Line 216 asserts that
amt_kiddie_tax_applieschanges only for JOINT rows. Line 214 asserts that it changes somewhere in every year.- Why it matters. The predicate still omits the §1(g)(2)(A)(ii)(II) support test for 18-year-olds and students (G2). A later legal fix there would change only pre-2018 results, yet it would fail this test.
- What it really checks. The test pins the variable to the legacy formula, which is more than its docstring ("post-2017 AMT unchanged") says.
- CLAUDE.md ("Test design and CI cost"):
- Duplicated formula. "Do not duplicate a policy formula in Python merely to test it against itself." After merge, the reform is a frozen copy of code the PR deletes.
- YAML can do this. The post-2017 claim is already covered in YAML: the 2018 transition case, the 2021 and 2022 controls, and the 2025 and 2026 cases.
- No measurement. "Measure simulation-heavy additions" asks for elapsed time, including setup, and peak memory for tests that build models. The PR body gives neither.
- The cost, as measured in CI (Linux; not a controlled before/after):
- Quick Feedback: 11.70 s call and 8.36 s setup.
- Rest Python
policygroup: 17.94 s call and 3.99 s setup, the eighth-slowest of 981 tests. - Memory. That group peaked at 11,954,096 KiB (11.4 GiB). Two PR runs on the same
mainbase peaked at 11,590,704 and 11,608,628 KiB, so about 340-355 MiB more here. The Makefile's stated goal for these groups is about 10 GB per process, on a 16 GB runner.
- Severity: should (a code-pattern violation of the repository's test rules).
- Fix: delete the file, since the YAML controls carry the post-2017 claim. If you keep it, drop the assertions on lines 214-216, say in the PR body which failure only this test catches, and give the CI cost above.
Suggestions
G1. The PR body is stale
- Draft language. It opens with "WIP:" although the PR is not a draft.
- Stale validation section. It says folder validation is incomplete:
qualified_dividend_netting.yamlwas stopped andregular_tax_before_credits.yamlwasn't started. The Baseline (irs) suite has since passed in CI, including both files. - Hub analysis is still listed as pending.
- Fix (optional): replace the validation section with the CI result, and fix the Axiom line (S1).
G2. Gaps left in the child test, all pre-existing
- The support test. §1(g)(2)(A)(ii)(II) applies the cap to an 18-year-old, or a full-time student aged 19-23, only if "earned income ... does not exceed one-half of the amount of the individual's support". The 2017 instructions list this as conditions 2 and 3.
amt_kiddie_tax_appliesdoesn't model it, so the 2017 test "A young separate filer remains subject to the child limitation" (T/kiddie_tax/amt_kiddie_tax_applies.yaml:110) holds only because the filer has no earnings. - The spouse-age clause is now redundant. After the joint exclusion,
no_or_young_spouse(V/kiddie_tax/amt_kiddie_tax_applies.py:49) matters only for a non-joint unit that contains a spouse. That happens only with a hand-setfiling_status. In that case §1(g)(2) looks at the filer alone, so the clause would wrongly drop the cap. - The living-parent condition (§1(g)(2)(B)) is assumed, as the test comment notes.
- Fix (optional):
- Drop the spouse clause.
- Note the support-test approximation in the variable's documentation, or model it from
care_and_support_costsif that is reliable. - Link Unify AMT "kiddie tax" child definition with EITC one #3908 or Refactor the Kiddie Tax logic and separate it from AMT #5087, which track the kiddie-tax definition.
G3. Pre-existing pre-2018 AMTI gaps that child filers now inherit
These predate the PR, which doesn't claim them. Because children now go through amt_income, they apply to child filers too.
- Line 6, the overall limit (Pease). The 2017 instructions say: if Form 1040 line 38 is over $261,500 ($313,800 joint), "enter the amount from line 9 of the Itemized Deductions Worksheet ... Enter it as a negative amount".
amt_incomeadds back SALT and miscellaneous deductions in full but never subtracts the §68 reduction (itemized_taxable_income_deductions_reduction, active 2013-2017). So it overstates 2013-2017 AMTI for high-income itemizers. - Line 7 (tax refunds) isn't modelled either. Draft Leave state tax refunds and the section 68 reduction out of federal AMTI, and fix Colorado AMTI to match #10099 (same author) addresses lines 6 and 7.
- Line 4 (home mortgage interest adjustment) isn't modelled.
- The standard deduction (
gov.irs.deductions.standard.amount) has no values before 2018, so 2017 backdates $12,000/$24,000. The PR's tests work around this by supplying 2017 amounts. AMTI for non-itemizers is AGI either way, but end-to-end 2017 regular tax, and so AMT, is still off. - Fix (optional): mention these in the PR body, and open an issue for the standard deduction and line 4 if none exists.
G4. References for the pre-2019 child amounts
- The gap.
policyengine_us/parameters/gov/irs/income/amt/exemption/child/amount.yamlhas references only from 2019. The PR's fix now depends on its 2013-2018 values ($7,400 for 2015-2016, $7,500 for 2017). - The values are right. Rev. Proc. 2016-55 §3.11 (file page 14) gives "$7,500" for 2017. The 2015 and 2016 Exemption Worksheets, line 7, give "$7,400".
- Fix (optional): add those Rev. Procs. as references.
Verified correct
- Hand-checks (11 cases, about 40 expectations). Each is TX.
T/exemption/amt_exemption.yaml:203, 2017 joint, spouses 18 and 17, wages 29,000, interest 121,000.- Taxable income = 150,000 − 12,700 − 2 × 4,050 = 129,200. Rev. Proc. 2016-55 gives the $12,700 standard deduction (file page 15) and the $4,050 exemption (file page 18).
- AMTI = 129,200 + 8,100 + 12,700 = 150,000. That is below the $160,900 joint phase-out start, so the exemption is $84,500 (§3.10, file page 13). The Exception applies, so
amt_kiddie_tax_appliesis false. - Base = 65,500 and the tentative tax is 26% × 65,500 = 17,030.
- Regular tax = 10,452.50 + 25% × 53,300 = 23,777.50 (Table 1, file page 7), so AMT is 0.
- Old code: cap 29,000 + 7,500 = 36,500, base 129,200 − 36,500 = 92,700, tax 24,102, AMT 324.50.
T/income/amt_income_less_exemptions.yaml:108, 2017 single, age 17, interest 50,000.- Taxable income = 50,000 − 6,350 − 4,050 = 39,600. AMTI = 50,000.
- Exemption = min(54,300, 0 + 7,500) = 7,500 (earned income below the limit). The base is 42,500 and the tax 11,050.
- Old code: base 32,100.
- Same file, line 47, 2017, AMTI 200,000, earnings 10,000.
- Exemption. The phase-out is 25% × 79,300 = 19,825, leaving 34,475, and the cap is 17,500. So the exemption is 17,500, the base 182,500 and the old base 172,500.
T/exemption/amt_exemption.yaml:70(17,500) is unchanged.
- Same file, line 146, 2025 single, age 17, interest 200,000.
- Taxable income = 200,000 − 15,750 = 184,250. AMTI is 200,000 and the exemption 88,100 (no cap after 2017).
- The base is 111,900 and the tax 29,094.
T/exemption/amt_exemption.yaml:252, 2021 joint, wages 29,000.- Taxable income is 29,000 − 25,100 = 3,900, and AMTI is 29,000.
- The exemption is 114,600, so the base and AMT are 0.
- Same file, line 284 (2022). Taxable income is 29,000 − 25,900 = 3,100, the exemption 118,100, and the base 0.
- Same file, lines 134 and 170, joint with both spouses 18.
amt_kiddie_tax_appliesis false. The exemption is 137,000 in 2025 and 140,200 in 2026, unchanged from before. T/income/amt_income_less_exemptions.yaml:88, 2025 joint with both spouses 18, AMTI 100,000. The predicate is false and the base is 0.T/kiddie_tax/amt_kiddie_tax_applies.yaml:- Line 110 (2017, separate return, age 18): true. §1(g)(2)(C) excludes only joint returns.
- Line 118 (2017, joint, students aged 22 and 23): false. The old code gave true, because both are under 24.
- Line 18 (2022, joint, both 18): false.
- 2017 against 2018.
T/exemption/amt_exemption.yaml:86(2018, single, age 18, no earnings): 70,300 with no cap, becausein_effectis false from 2018.- The 2017 cap. For 2017 the cap uses the $7,500 amount.
- The indexed amount.
child/amount.yamlmatches the IRS:- 2015 and 2016: $7,400 (worksheet line 7, file page 10 of each year's instructions).
- 2017: $7,500 (Rev. Proc. 2016-55 §3.11).
- The 2015-2017 form.
- The exemption amounts and phase-out starts in
amount.yamlandphase_out/start.yamlmatch the line 29 charts. In 2017, for example, they are $54,300/$120,700, $84,500/$160,900 and $42,250/$80,450. - The 26% bracket ends at $187,800 in 2017, which matches line 31.
- The exemption amounts and phase-out starts in
- Callers at the head:
amt_kiddie_tax_appliesis read only byamt_exemption, and only whilechild.in_effectis true (before 2018).amt_income_less_exemptionsfeeds the federal AMT, the §911 variables andco_alternative_minimum_taxable_income. Those change only before 2018. The Colorado AMT rate starts in 2021.- California.
ca_amt_exemptionreads onlychild.amountand its own child test, so it is unaffected.
- References.
- The 2017 instructions. File page 10 holds the Exemption Worksheet (
amt_income_less_exemptions.py), and file page 11 holds the joint-return Exception (amt_kiddie_tax_applies.py). - Rev. Proc. 2016-55. The test comments cite pages 7, 15 and 18, which show the rate table, the standard deduction and the exemption.
- §56(b)(1)(D), cited in a test comment, is the standard-deduction and exemption disallowance.
- The 2017 instructions. File page 10 holds the Exemption Worksheet (
- Changelog.
changelog.d/amt-child-pre-2018.fixed.mdis a top-level fragment, andfixedis the right type. - Batch lessons:
- Source-conflict ratchet (Tie source-conflict markers to the register shared with Axiom #10287).
- In CI. The green run's tree contains Tie source-conflict markers to the register shared with Axiom #10287 and Count the FL and SD LIHEAP comments in the source-conflict ratchet baseline #10334.
test_conflict_sounding_comments_do_not_growpassed in the Rest (Python, shard-1) job. - Statically. I also ran
main'sCONFLICT_COMMENT_REover the comment tokens of the two scanned files the PR edits (amt_income_less_exemptions.pyandamt_kiddie_tax_applies.py) at the merge base, the head andmain. Each has 0 matches. - The baseline list. Neither file is in
KNOWN_UNMARKED, andmainhasn't touched either since the merge base. The ratchet passes on the merged tree.
- In CI. The green run's tree contains Tie source-conflict markers to the register shared with Axiom #10287 and Count the FL and SD LIHEAP comments in the source-conflict ratchet baseline #10334.
- NH Add New Hampshire state supplementation for 2026 #10156 (state-gated keys): not applicable. There is no state-gated variable.
- Integrate modeled state unemployment insurance into income flows #9558, Document disjoint health premium inputs and correct consumer treatment #10046 and OK Add Oklahoma state supplementation for 2026 #10165: not applicable. No income-source list or wage definition changes.
- Partner tests: untouched. The Household API Partners check passed.
- Source-conflict ratchet (Tie source-conflict markers to the register shared with Axiom #10287).
Axiom line assessment
Invalid: axiom: pending: hub files parity (S1).
- Recommended form:
axiom: us:statutes/26/59#section_59_j_kiddie_exemption_limit_applies encoded-correct; TheAxiomFoundation/rulespec-us#<n> queued. The queued issue is a new open,pe-parity-labelled, dispatch-ready issue for the pre-2018 §59(j)(1) cap, the §1(g)(2) applicability (including (C)) and the taxable excess. The required contents are listed under S1. Alternatively, cite an encoder PR asencoded. - Not
n/a. These are statutory provisions, and the PR changes 2013-2017 AMT results. encoded-correctcovers only the post-2017 switch. rulespec-usmain(5796861e58) encodes the switch asfalsefrom 2018-01-01, which matches the model. It has no pre-2018 version, and55.yamlcovers only 2026.
CI status
27 pass, 3 skipping, 0 pending, 0 failed. I re-checked gh pr checks 10308 at the end of this review, and the head is still e7b010e809.
- The green run. Run 39608011006 (
pull_request, created 2026-10-21 13:26 UTC) tested merge commit70ec14b2. That merges the head intofec98b87c8(Count the FL and SD LIHEAP comments in the source-conflict ratchet baseline #10334), so CI's tree contains the Tie source-conflict markers to the register shared with Axiom #10287 ratchet and the FL/SD LIHEAP baseline fix. The known main-caused ratchet failure therefore doesn't apply. - The skipped checks are the umbrella jobs of the superseded run 39507938034 (2026-10-20 22:25 UTC).
- Where the changed tests ran.
- Quick Feedback selected and passed:
amt_exemption.yaml(17),amt_income_less_exemptions.yaml(10),amt_kiddie_tax_applies.yaml(11) and the property test (1). - Full suites. The Baseline (irs) suite, the Rest Python
policygroup (which reran the property test), Microsimulation and Household API Partners all passed.
- Quick Feedback selected and passed:
- Locally: I ran no tests or model probes. CI is green at the current head. Every expectation and the S2 values were checked by hand from the code, the parameters and the IRS sources.
Branch status
- Position: 3 commits ahead of
main(328d1721e2) and 24 behind. The merge base isf4b1644230. - Merge: clean.
git merge-tree --write-tree PolicyEngine/main e7b010e809exits 0 (treed3157c9dcf).- Since the merge base,
mainhas touched no file in this PR and no AMT variable, parameter or test.
- Siblings (note only).
- Draft Leave state tax refunds and the section 68 reduction out of federal AMTI, and fix Colorado AMTI to match #10099 (same author) edits
amt_income.py,co_alternative_minimum_taxable_income.pyandamt_income.yaml. It has no file overlap, but it changes the pre-2018 AMTI that child filers now use (G3). - Take the 2020 charitable deduction for non-itemizers above the line #10186 and Phase out the Minnesota AMT exemption at 25% instead of the federal 2026 rate #10256 touch only Minnesota AMT files.
- Draft Leave state tax refunds and the section 68 reduction out of federal AMTI, and fix Colorado AMTI to match #10099 (same author) edits
0 critical, 3 should and 4 suggestions are open at this head.
Verdict: REQUEST_CHANGES
DTrim99
left a comment
There was a problem hiding this comment.
Both changes are correct. s.59(j) caps only the exemption, joint returns are excluded under s.1(g)(2)(C), s.59(j) stays off from 2018 (SECURE Act, and OBBBA s.70107 struck the 2026 end date), and the pre-2018 add-backs match Form 6251. Three should-address items: (1) the 'pending: hub files parity' axiom line is invalid (cite 59(j) encoded-correct, plus a queued issue for the pre-2018 cap and 1(g)(2)); (2) add cases for an itemizing 2017 child and a pair either side of the cap; (3) the Python property test restates the old formulas and locks in the old predicate, with no cost report. Four suggestions. Full report in the comment above.
WIP: Correct the pre-2018 AMT child exemption and income base identified in Yale/PSL unit U4. A child with $50,000 AMTI and a $7,500 exemption should have a $42,500 AMT base; a 2017 joint return by young spouses should receive the ordinary joint exemption.
Plan:
amt_exemption.amt_kiddie_tax_applies.Sources:
Validation:
qualified_dividend_netting.yamlwas stopped during initialization before the job wall;regular_tax_before_credits.yamlwas not started (19 cases remain). No test process remains running.axiom: us:statutes/26/59#section_59_j_kiddie_exemption_limit_applies encoded-correct for 2018 onward (false from 2018-01-01; companion tests us/statutes/26/59.test.yaml); TheAxiomFoundation/rulespec-us#1857 queued for TY2013-2017 (§59(j), §1(g)(2) including the joint-return exclusion, and the §55(b)(1)(A)(ii) AMTI taxable excess). It is blocked on three things: axiom-corpus ingestion of the TY2013-2017 statute text and the Form 6251 instructions (TheAxiomFoundation/axiom-corpus#915), a re-pin to a release that carries the 2013-2016 revenue procedures, and approval of the billed encoder run.