Repository navigation
Cap the educator expense deduction per eligible educator (26 U.S.C. 62(a)(2)(D)) - #9833
Conversation
YAML cases at, below and above the cap for 2021 ($250), 2022 and 2025 ($300) and 2026 ($350); joint returns with one and two educators; a dependent's expenses. A Hypothesis property checks the bound, a numpy differential, monotonicity and the AGI identity. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…)(2)(D)) gov.irs.ald.deductions listed the raw educator_expense input, so the federal deduction was uncapped. Add gov.irs.ald.educator_expense.cap with each year's IRS value ($250 for 2002-2021, $300 for 2022-2025, $350 for 2026 per Rev. Proc. 2025-32 sec. 4.12), uprated after 2026 to the nearest $50 as 62(d)(3) rounds. educator_expense_ald_person caps each person's own expenses; educator_expense_ald adds the head's and spouse's amounts and replaces the raw input in the ALD list. A dependent's own capped amount feeds dependent_taxable_ss_magi and the dependent's Medicaid AGI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… AGI Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A member flagged as a tax unit dependent has their income left off the filer's return by irs_gross_income, which masks on is_tax_unit_dependent; mask their deduction the same way (tax_unit_non_dep_sum, as #9801 does for the other person-level deductions). Make the dependent test case's roles explicit. 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 #9833 +/- ##
===========================================
- Coverage 100.00% 96.11% -3.89%
===========================================
Files 4 6 +2
Lines 76 103 +27
Branches 2 5 +3
===========================================
+ Hits 76 99 +23
- Misses 0 2 +2
- Partials 0 2 +2
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:
|
… 62(d)(3)) Core's metadata uprating chained from the rounded 2026 value ($350), which put the projected cap at $400 in 2030-2031. 62(d)(3) indexes the $250 amount with a 2014 base year and rounds the increase to the nearest $50, so on the repo's CPI the cap stays $350 through 2031 and reaches $400 in 2032. extend_educator_expense_cap computes each year after the last published value from the statute, with get_irs_cola(parameters, year, 2014), as the dependent standard deduction extension does. The published 2002-2026 values stay explicit and take precedence. Tests: the 62(d)(3) computation reproduces every published cap from 2016 to 2026; projected years 2027-2100 equal it, are multiples of $50 and never fall; a synthetic index pins nearest rounding in both directions; and a 2030 YAML case expects $350. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…9-111) Pub. L. 119-111, division B, section 1, adds early childhood educators to the 62(d)(1) eligible educator definition for expenses paid or incurred in taxable years beginning after 2025. The model has no educator-status input and takes any positive educator_expense as an eligible educator's, so the input's documentation now gives the effective-year split, and both groups share the same cap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#9801 (keep dependents' above-the-line deductions off the filer's AGI) has landed, so this PR lands second. - medicaid_adjusted_gross_income_person: main now maps each tax-unit deduction to its person-level amount and attributes it with person_share_of_tax_unit_amount. educator_expense_ald joins that map as educator_expense_ald_person. The helper keeps a dependent's own amount and gives the head and spouse their own amounts whenever those sum to the tax-unit amount, which educator_expense_ald always does unless it is an input or a reform changes it. - test_dependent_above_the_line_deductions_invariants.py: PERSON_DEDUCTIONS builds the reference deduction sum from educator_expense_ald_person, the capped amount, instead of the raw educator_expense. Its 2020 draws reach $300, above 2020's $250 cap. DEPENDENT_DEDUCTION_INPUTS keeps the raw input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…icaid split test_dependent_above_the_line_deductions_invariants.py now lists educator_expense_ald among its AGGREGATES, so the harness checks that a dependent's educator expenses never change the filer's educator_expense_ald and that it equals the numpy sum of the head's and spouse's educator_expense_ald_person. A Medicaid AGI case supplies educator_expense_ald directly, at 250 against own amounts of 300 and 200, so person_share_of_tax_unit_amount scales the head's and spouse's shares to 150 and 100 while the dependent keeps their own 300. Without the educator entry in the Medicaid map this case and the existing one both fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
US + core hub merge audit, us#9833 at
|
Impact update (hub, after merge): the real microsim against this PR's own baseThis PR was merged with its 2024 and 2026 figures measured against main from before #9801, and the 2030 run still missing. These are the runs that measure it against the PR's actual merge base, post-#9801 main Setup:
What these figures reflect:
The 2030 branch run completed every output (log ends Evidence: |
Summary
gov.irs.ald.deductionslisted the raweducator_expenseinput, and nothing underparameters/gov/irsorvariables/gov/irscapped it. Every dollar a filer entered came off AGI. Under 26 U.S.C. 62(a)(2)(D) each eligible educator deducts at most $250, indexed from 2016 under 62(d)(3): $300 for 2022 through 2025 and $350 for 2026. On a joint return each spouse is capped separately.This PR adds the cap parameter and a capped deduction,
educator_expense_ald, and puts it in the ALD list in place of the raw input. After 2026 the cap is projected from the statutory $250 base, as 62(d)(3) computes it.The law
26 U.S.C. 62(a)(2)(D) (OLRC, via the pinned Axiom corpus row
us/statute/26/62, as of Online@119-100):62(d)(1)(A):
Pub. L. 119-111, division B, §1 (approved September 18, 2026; 140 Stat. 1049) amends 62(d)(1), and the amendments "shall apply to expenses paid or incurred in taxable years beginning after December 31, 2025." It strikes "a kindergarten through grade 12 teacher" and inserts "an early childhood or kindergarten through grade 12 teacher". For early childhood education, "school" now means
The 900-hour test, the dollar amount and its indexing are unchanged, so both groups have the same cap.
62(d)(3):
The cap applies per educator, not per return. The Form 1040 instructions for Schedule 1, line 11 (2022, p. 87) say:
The 2016 through 2021 instructions say the same with $500 and $250. Pub. L. 107-147 §406 added the deduction for taxable years beginning after 2001. A series of extensions carried it year by year, and Pub. L. 114-113 §104 made it permanent and added (d)(3) (US Code amendment notes, govinfo USCODE-2023).
Parameter values
gov.irs.ald.educator_expense.cap, per eligible educator. Each value was read from the cited PDF; page numbers are PDF pages.Projection. 62(d)(3) increases the $250 amount itself, not the last published cap, and rounds the increase to the nearest multiple of $50. After 2026,
extend_educator_expense_capinparameters/uprating_extensions.pycomputes each year that way: $250 plus $250 ×get_irs_cola(parameters, year, 2014), with the increase rounded to the nearest $50.get_irs_colais the repo's 1(f)(3) cost-of-living adjustment, and 2014 is the base year 62(d)(3) substitutes for 2016. This is howextend_dependent_standard_deduction_parametersalready projects the 63(c)(5) limits from their statutory bases. The published values for 2002–2026 stay in the YAML and take precedence. On the repo's CPI series the same computation reproduces every published cap from 2016 to 2026. It is also the formula rulespec-us encodes ineligible_educator_expense_cap_after_inflation_adjustment: base + floor(base × COLA / 50 + ½) × 50.The increase is $120.06 in 2031 and $127.32 in 2032, within $5 of the $125 rounding point, so a CPI forecast update can move that step by a year.
What changes
gov.irs.ald.educator_expense.cap, with the values above.extend_educator_expense_capinparameters/uprating_extensions.pywrites the caps for 2027 on, as described under Projection.set_all_uprating_parameterscalls it after the Chained CPI-U extension, as it calls the dependent standard deduction extension.cap.yamlkeepsuprating: gov.irs.upratingwithnearest$50 rounding to describe the index; the computed values supersede it, as they do for the dependent standard deduction.educator_expense_ald_person(Person) = min(max(0,educator_expense), cap). This is each person's own amount, as on their own return; a dependent's is computed too.educator_expense_ald(TaxUnit) = the sum ofeducator_expense_ald_personover the head and spouse. It usestax_unit_non_dep_sum, the sameis_tax_unit_dependentmaskirs_gross_incomeuses, so a dependent's deduction leaves the filer's return exactly when their income does.gov.irs.ald.deductions:educator_expense→educator_expense_aldin all four periods.dependent_taxable_ss_magi: mapseducator_expense_aldtoeducator_expense_ald_person, the dependent's own capped amount. It was the raw input.medicaid_adjusted_gross_income_person: mapseducator_expense_aldtoeducator_expense_ald_personinTAX_UNIT_AGI_ALDS_WITH_PERSON_LEVEL_EQUIVALENTS, beside the self-employment and alimony deductions. Keep dependents' above-the-line deductions off the filer's AGI #9801 made that a map and attributes each entry withperson_share_of_tax_unit_amount. A dependent keeps their own capped amount, and the head and spouse each get their own whenever those sum toeducator_expense_ald, which they always do unless it is an input or a reform changes it; then the two shares are scaled to it. On main, the head's and spouse's raw expenses are pooled and split 50/50 on a joint return, and a dependent's raw expenses reduce their own Medicaid AGI uncapped.educator_expenseinput: its documentation now says what it is (an eligible educator's unreimbursed qualified expenses, entered in full) and cites 62(a)(2)(D), (d)(1) and Pub. L. 119-111. It says kindergarten through grade 12 educators qualify in every year and early childhood educators from 2026, and that the model takes any positive amount as an eligible educator's, so an early childhood educator's expenses belong only in 2026 and later.educator_expense_ald_personsays the same.Readers of the ALD list, checked
These take the capped tax-unit amount with no edit:
above_the_line_deductions(addsthe list);taxable_ss_magiandtaxable_uc_agi(addover the list);ma_part_b_agi, which takes the list less Massachusetts' disallowed items;adjusted_gross_income_personandstudent_loan_interest_ald_magi, which split non-person ALDs between head and spouse as before;mo_adjusted_gross_income(the remainder after the self-employment ALDs).tools/default_uprating.pykeeps uprating the raw input.tests/core/test_ald_determinism.pyuseseducator_expenseonly as a synthetic name in a made-up list, so it is unchanged.State treatments
ma_part_b_agi, so it now takes the capped amount, which is what line 11 holds.oh_educator_expense_deduction_person(ORC 5747.01(A)(31), expenses above the federal amount) andva_educator_expenses(Va. Code 58.1-322.03, expenses not claimed federally) are separate inputs. Ohio's deduction list does not include the federal item, and neither state readseducator_expense.Interaction with #9801
#9801 (keep dependents' above-the-line deductions off the filer's AGI) merged first, as
1f9d85aafc. It sums person-level ALDs over non-dependents and puts a dependent's person-level deductions on the dependent's own Medicaid AGI. This branch merges main (b372bf24b0, thence79d1ed5efor #9609 and #9722), so this PR lands second:educator_expense_aldis tax-unit level and already leaves dependents out, so Keep dependents' above-the-line deductions off the filer's AGI #9801'stax_unit_non_dep_addtakes it as is.person_share_of_tax_unit_amount. This branch had addededucator_expense_ald_personto the old list. The resolution keeps Keep dependents' above-the-line deductions off the filer's AGI #9801's map and adds"educator_expense_ald": "educator_expense_ald_person"to it (described under What changes). Both Medicaid educator cases fail without that entry: with it removed, the dependent's AGI is 5,000 instead of 4,700, because the dependent's own capped amount is never subtracted (evidence/r2/finish-yaml-medicaid-educator-without-map-entry.txt).dependent_taxable_ss_magithrougheducator_expense_ald_person; that file merged without a conflict. Keep dependents' above-the-line deductions off the filer's AGI #9801's Case 3 (a dependent's $300 of 2025 educator expenses reduces the dependent's Medicaid AGI to 4,100) passes on this head.PERSON_DEDUCTIONSbuilt the reference ALD sum from the raweducator_expense, and its 2020 draws go up to $300, above 2020's $250 cap. This branch changes that entry toeducator_expense_ald_personand keeps the raw input inDEPENDENT_DEDUCTION_INPUTS. On this head, with the entry still raw, both 2020 tests fail (test_dependent_deductions_stay_off_the_filers_return_2020andtest_seeded_population[2020]). With the edit, all 9 tests in the file pass.educator_expense_aldto that test'sAGGREGATES. The harness then checks that dependents' educator expenses never change it, and that it equals the numpy sum of the head's and spouse'seducator_expense_ald_person.Invariants
These hold for every input. The Hypothesis test checks them on drawn batches (2021, 2022, 2025, 2026) and on a seeded population of 200 tax units:
educator_expense_ald≤ cap × (number of head and spouse with expenses) ≤ 2 × cap. It is also never more than the head's and spouse's expenses.educator_expense_ald= Σ over head and spouse of min(expenses, cap), computed in numpy with the caps taken from the Rev. Procs., not from the model.educator_expense_ald_person= min(expenses, cap) for everyone, dependents included.educator_expense_aldand never raises AGI.educator_expense_ald.get_irs_cola(year, 2014)rounded to the nearest $50, and is a multiple of $50. The values incap.yaml(2002–2026) are what the parameter returns for those years.test_uprating_extensions.pychecks both on the model's parameters, and checks on the repo's CPI path that the cap never falls from one year to the next. A unit test with a made-up CPI series checks the extension's rounding in both directions and that it keeps an encoded year.Tests
Run by the build and the hub, one process at a time, with the worktree's own
.venv(CPython 3.13, policyengine-core 3.32.15):4613f8c792)f25432710e)educator_expense_ald.yaml(13 cases)test_educator_expense_cap_invariants.py(Hypothesis)Other folders on this branch: the ALD folder 92 passed; social security 24; Medicaid income 67; OH 163, VA 214, MA 116 and MO 235.
tests/code_healthpassed 136. Intest_ald_determinism.py, 8 tests passed and one hit a subprocess timeout under host load; it passed when the hub re-ran it alone (64 s).Round 2, on this head (
ce79d1ed5e, main merged in). Each line below is one process, run in sequence with CPython 3.13.9 and policyengine-core 3.32.15. Logs are inevidence/r2/finish-*.txt.educator_expense_ald.yaml, including the 2030 projected-cap casetest_educator_expense_cap_invariants.pytest_uprating_extensions.py, including the 4 projection teststest_dependent_above_the_line_deductions_invariants.pyPERSON_DEDUCTIONSedittests/code_health, one process per filetest_reference_urls.py) were rerun: 97 passedtests/test_programs_registry.py(#9722)ruff format --check .andruff check .(ruff 0.15.5, fromuv.lock)Round 2's projection, fail-before. At
f25432710e, the 2030 YAML case fails witheducator_expense_ald_personat 400 rather than 350. The statutory projection test also fails, first at 2030 with 400 rather than 350 (evidence/r2/fix-r1-before-*.txt).The merged tree's cap matches round 2's pre-merge values in every year compared, 2002–2040 plus 2050, 2075, 2100 and 2150 (
evidence/r2/finish-cap-values-merged.json).Microsimulation impact: current figures (hub, after merge): the real microsim against this PR's own base
This PR was merged with its 2024 and 2026 figures measured against main from before #9801, and the 2030 run still missing. These are the runs that measure it against the PR's actual merge base, post-#9801 main
bab1a47c60, compared with the merged headce79d1ed5e.Setup:
populace_us_2024.h5@populace-us-2024-spm-20260909.lockrun.sh,run.py,compare.py), one run per side, matched record by record.What these figures reflect:
educator_expense_alditself isn't compared, because the base build doesn't produce that array under the same name. The deduction change shows up inabove_the_line_deductions.The 2030 branch run completed every output (log ends
DONE educap-p 2030). Its wrapper reported rc 145 because the run was paused during a host hold, so the comparison was run separately on the saved arrays.Evidence:
~/reviews/us-hub/educator-cap/evidence/r2/hub_compare_{2026,2030}.json.Microsimulation impact (as originally merged)
Default dataset (
populace_us_2024.h5@populace-us-2024-spm-20260909), policyengine-core 3.32.15, through the hub runner. Each figure compares two real runs on the same records: main and this branch, one run each.2030, against current main
2030 is the first year round 2's projection changes the cap: $350, where round 1 had $400. Main is
bab1a47c60and this branch isce79d1ed5e.Not run in this round. Both runs waited on the hub runner from 06:06 to 08:07 EDT and never got the shared heavy lock: about a dozen other runs were queued and the host load average was above 100. The job withdrew them before either started, so no 2030 figure is reported here.
evidence/r2/finish_impact_2030.shruns the pair (mainbab1a47c60againstce79d1ed5e) and the record-by-record comparison when the lock allows. Until then, the projected-year change is the parameter itself: the cap is $350 in 2030 under this branch, where round 1 had $400, and the YAML case "2030, the projected cap is still $350" pins it for a single filer.2024 and 2026, round 1, against main before #9801
Round 2 changes only the projected caps, from 2027 on. Every value from 2002 to 2026 is the same at
f25432710eand at this head (both trees'capparameter compared year by year), so round 2 does not move these results and they were not rerun.They compare
f25432710ewith main at4613f8c792, before #9801 merged. That main deducted a tax unit dependent's raw educator expenses on the filer's return. In the data, dependents' expenses come to $22.1M (weighted) in 2024 and $24.9M in 2026, from 145 records. Removing them from the filer's return is part of these changes. Current main already does that, through #9801, so against current main the changes would be smaller. No run against current main was made in this round.educator_expenseitself is unchanged: $0.92bn in 2024 and $1.04bn in 2026.above_the_line_deductionsadjusted_gross_incomeincome_taxstate_income_taxAGI rises slightly more than deductions fall, because AGI feeds other parts of the calculation, such as the taxable share of Social Security.
Not in this PR
educator_expenseis taken to belong to an eligible educator, as before. Kindergarten through grade 12 and early childhood educators have the same cap, so the formula needs no split. For 2025 and earlier it would also deduct an early childhood educator's expenses if they were entered; the input's documentation says to enter them only from 2026.Round 2
The independent review of
f25432710erequested changes. This round answers it:636b0be64e; see Projection.educator_expenseandeducator_expense_ald_person(f38732ad3e). No formula change: the model has no educator-status input, and both groups have the same cap. RuleSpec's eligible-educator rule still has only the kindergarten through grade 12 version, so the amendment is queued as rulespec-us#1497.PERSON_DEDUCTIONSedit in Keep dependents' above-the-line deductions off the filer's AGI #9801's test (b372bf24b0). It adds a Medicaid case for a suppliededucator_expense_aldand theAGGREGATESentry (7f13ef6cd3), then merges Fix fused reference URLs repo-wide and correct Arkansas DFA page anchors #9609 and Fix LIHEAP program registry entries and add a registry integrity test #9722 (ce79d1ed5e). See Interaction with Keep dependents' above-the-line deductions off the filer's AGI #9801.axiom: us:statutes/26/62#eligible_educator_expenses_allowable_above_the_line encoded-correct | TheAxiomFoundation/rulespec-us#1497 queued (Pub. L. 119-111 early childhood educators, TY2026 on; blocked on the pinned corpus, whose §62 text predates the amendment). rulespec-us
us/statutes/26/62.yamlencodes the per-educator min(expenses − 62(d)(2) coordination amount, cap), the 900-hour definition, and the 62(d)(3) cap formula with rounding to the nearest $50. The companion testeligible_educator_expense_deduction_applies_cap_and_coordination(us/statutes/26/62.test.yaml) exercises it: $400 of expenses less $60 coordination, capped at $300 for a COLA of 0.2. The cost-of-living adjustment is an input there, so the Rev. Proc. year values are not RuleSpec atoms; the published 2026 figure is $350 (Rev. Proc. 2025-32 §4.12).🤖 Generated with Claude Code