Skip to content
This repository was archived by the owner on Jun 14, 2026. It is now read-only.

Commit 7e22bb9

Browse files
committed
Map SOI retirement contribution targets
1 parent 343830a commit 7e22bb9

3 files changed

Lines changed: 132 additions & 2 deletions

File tree

src/microplex_us/targets/arch.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,18 @@
396396
"tip_income_taxpayers",
397397
"COUNT",
398398
),
399+
"irs_soi.form_w2_401k_elective_deferrals": (
400+
"traditional_401k_contributions",
401+
"AMOUNT",
402+
),
403+
"irs_soi.form_w2_designated_roth_401k_contributions": (
404+
"roth_401k_contributions",
405+
"AMOUNT",
406+
),
407+
"irs_soi.payments_to_keogh_plan": (
408+
"self_employed_pension_contribution_ald",
409+
"AMOUNT",
410+
),
399411
"census_decennial.resident_population": ("population", "COUNT"),
400412
"census_decennial.occupied_housing_units": ("household_count", "COUNT"),
401413
"census_pep.resident_population": ("population", "COUNT"),
@@ -630,7 +642,9 @@
630642
"short_term_capital_gains": EntityType.PERSON,
631643
"proprietors_income_amount": EntityType.PERSON,
632644
"rental_income": EntityType.PERSON,
645+
"roth_401k_contributions": EntityType.PERSON,
633646
"self_employment_income": EntityType.PERSON,
647+
"self_employed_pension_contribution_ald": EntityType.TAX_UNIT,
634648
"salt_refund_income": EntityType.PERSON,
635649
"state_income_tax": EntityType.TAX_UNIT,
636650
"taxable_ira_distributions": EntityType.PERSON,
@@ -639,6 +653,7 @@
639653
"taxable_pension_income": EntityType.PERSON,
640654
"taxable_social_security": EntityType.PERSON,
641655
"tip_income": EntityType.PERSON,
656+
"traditional_401k_contributions": EntityType.PERSON,
642657
"unemployment_compensation": EntityType.PERSON,
643658
"medicaid": EntityType.PERSON,
644659
"social_security": EntityType.PERSON,
@@ -763,8 +778,13 @@
763778
"tanf_family_count": "TANF family count",
764779
"tanf_recipient_count": "TANF recipient count",
765780
"tip_income": "Tip income",
781+
"traditional_401k_contributions": "Traditional 401(k) contributions",
766782
"traditional_ira_contributions": "Traditional IRA contributions",
783+
"roth_401k_contributions": "Roth 401(k) contributions",
767784
"roth_ira_contributions": "Roth IRA contributions",
785+
"self_employed_pension_contribution_ald": (
786+
"Self-employed pension contribution ALD"
787+
),
768788
}
769789

770790
ARCH_AGI_BRACKET_LABELS = {
@@ -791,11 +811,16 @@
791811
"interest_deduction": "interest_paid_deduction_amount",
792812
"net_capital_gains": "net_capital_gains_amount",
793813
"real_estate_taxes": "real_estate_taxes_amount",
814+
"roth_401k_contributions": "roth_401k_contributions",
815+
"self_employed_pension_contribution_ald": (
816+
"self_employed_pension_contribution_ald"
817+
),
794818
"total_self_employment_income": "schedule_c_income_amount",
795819
"taxable_ira_distributions": "taxable_ira_distributions_amount",
796820
"taxable_pension_income": "taxable_pension_income_amount",
797821
"taxable_social_security": "taxable_social_security_amount",
798822
"tip_income": "tip_income",
823+
"traditional_401k_contributions": "traditional_401k_contributions",
799824
"unemployment_compensation": "unemployment_compensation_amount",
800825
}
801826

@@ -898,6 +923,8 @@
898923
"population": "Census Population Estimates Program Vintage 2024 age-sex files",
899924
"real_estate_taxes": "IRS SOI itemized deduction tables or ACS state files",
900925
"roth_ira_contributions": "IRS SOI IRA contribution tables",
926+
"roth_401k_contributions": "IRS SOI Form W-2 Statistics Table 4.B",
927+
"self_employed_pension_contribution_ald": "IRS SOI Publication 1304 Table 1.4",
901928
"state_individual_income_tax_collections": (
902929
"Census State Tax Collections item T40"
903930
),
@@ -919,6 +946,7 @@
919946
"tanf_recipient_count": "ACF TANF Caseload Data",
920947
"tip_income": "IRS SOI Form W-2 Statistics",
921948
"traditional_ira_contributions": "IRS SOI IRA contribution tables",
949+
"traditional_401k_contributions": "IRS SOI Form W-2 Statistics Table 4.B",
922950
"taxable_ira_distributions": "IRS SOI IRA accumulation/distribution tables",
923951
"taxable_pension_income": "IRS SOI Publication 1304 Table 1.4",
924952
"taxable_social_security": "IRS SOI Publication 1304 Table 1.4",

tests/targets/test_arch.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3449,6 +3449,52 @@ def test_arch_target_gap_queue_points_energy_subsidy_households_to_liheap(
34493449
assert row.gap_category == "ready_primary_loader"
34503450

34513451

3452+
def test_arch_target_gap_queue_points_retirement_contributions_to_soi(
3453+
tmp_path,
3454+
):
3455+
db_path = tmp_path / "arch_targets.db"
3456+
_create_arch_targets_db(db_path)
3457+
3458+
provider = ArchSQLiteTargetProvider(db_path)
3459+
report = summarize_arch_target_gap_queue(
3460+
provider,
3461+
period=2024,
3462+
profile_name="custom",
3463+
target_cells=(
3464+
PolicyEngineUSTargetCell(
3465+
"traditional_401k_contributions",
3466+
geo_level="national",
3467+
),
3468+
PolicyEngineUSTargetCell("roth_401k_contributions", geo_level="national"),
3469+
PolicyEngineUSTargetCell(
3470+
"self_employed_pension_contribution_ald",
3471+
geo_level="national",
3472+
),
3473+
),
3474+
)
3475+
3476+
rows_by_variable = {row.variable: row for row in report.rows}
3477+
traditional = rows_by_variable["traditional_401k_contributions"]
3478+
roth = rows_by_variable["roth_401k_contributions"]
3479+
self_employed = rows_by_variable["self_employed_pension_contribution_ald"]
3480+
3481+
assert {row.expected_source for row in report.rows} == {"IRS_SOI"}
3482+
assert traditional.expected_source_table == "IRS SOI Form W-2 Statistics Table 4.B"
3483+
assert traditional.expected_arch_variable == "traditional_401k_contributions"
3484+
assert traditional.expected_entity == "person"
3485+
assert roth.expected_source_table == "IRS SOI Form W-2 Statistics Table 4.B"
3486+
assert roth.expected_arch_variable == "roth_401k_contributions"
3487+
assert roth.expected_entity == "person"
3488+
assert self_employed.expected_source_table == (
3489+
"IRS SOI Publication 1304 Table 1.4"
3490+
)
3491+
assert self_employed.expected_arch_variable == (
3492+
"self_employed_pension_contribution_ald"
3493+
)
3494+
assert self_employed.expected_entity == "tax_unit"
3495+
assert {row.gap_category for row in report.rows} == {"ready_primary_loader"}
3496+
3497+
34523498
def test_arch_target_gap_queue_points_agi_person_counts_to_soi_table_2(tmp_path):
34533499
db_path = tmp_path / "arch_targets.db"
34543500
_create_arch_targets_db(db_path)

tests/targets/test_arch_facts.py

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,36 @@ def test_arch_consumer_fact_jsonl_provider_maps_us_admin_source_families(
13431343
value=526,
13441344
unit="usd",
13451345
),
1346+
_consumer_fact(
1347+
"w2-traditional-401k",
1348+
concept="irs_soi.form_w2_401k_elective_deferrals",
1349+
domain="form_w2_items",
1350+
source_name="irs_soi",
1351+
source_table="Form W-2 Statistics Table 4.B",
1352+
period={"type": "tax_year", "value": 2024},
1353+
value=277_859_181_000,
1354+
unit="usd",
1355+
),
1356+
_consumer_fact(
1357+
"w2-roth-401k",
1358+
concept="irs_soi.form_w2_designated_roth_401k_contributions",
1359+
domain="form_w2_items",
1360+
source_name="irs_soi",
1361+
source_table="Form W-2 Statistics Table 4.B",
1362+
period={"type": "tax_year", "value": 2024},
1363+
value=32_302_509_000,
1364+
unit="usd",
1365+
),
1366+
_consumer_fact(
1367+
"soi-keogh",
1368+
concept="irs_soi.payments_to_keogh_plan",
1369+
domain="all_individual_income_tax_returns",
1370+
source_name="irs_soi",
1371+
source_table="Publication 1304 Table 1.4",
1372+
period={"type": "tax_year", "value": 2024},
1373+
value=30_130_848_000,
1374+
unit="usd",
1375+
),
13461376
]
13471377
consumer_jsonl.write_text(
13481378
"\n".join(json.dumps(row, sort_keys=True) for row in rows) + "\n"
@@ -1398,11 +1428,26 @@ def test_arch_consumer_fact_jsonl_provider_maps_us_admin_source_families(
13981428
"geo_level": "national",
13991429
"domain_variable": "age",
14001430
},
1431+
{
1432+
"variable": "traditional_401k_contributions",
1433+
"geo_level": "national",
1434+
"domain_variable": None,
1435+
},
1436+
{
1437+
"variable": "roth_401k_contributions",
1438+
"geo_level": "national",
1439+
"domain_variable": None,
1440+
},
1441+
{
1442+
"variable": "self_employed_pension_contribution_ald",
1443+
"geo_level": "national",
1444+
"domain_variable": None,
1445+
},
14011446
),
14021447
)
14031448

1404-
assert report.target_cell_count == 12
1405-
assert report.covered_cell_count == 12
1449+
assert report.target_cell_count == 15
1450+
assert report.covered_cell_count == 15
14061451

14071452
target_set = provider.load_target_set(TargetQuery(period=2024))
14081453
targets_by_arch_variable = {
@@ -1442,6 +1487,17 @@ def test_arch_consumer_fact_jsonl_provider_maps_us_admin_source_families(
14421487
== "social_security_retirement"
14431488
)
14441489
assert targets_by_arch_variable["ssi_payments"].measure == "ssi"
1490+
traditional_401k = targets_by_arch_variable["traditional_401k_contributions"]
1491+
assert traditional_401k.measure == "traditional_401k_contributions"
1492+
assert traditional_401k.entity.value == "person"
1493+
roth_401k = targets_by_arch_variable["roth_401k_contributions"]
1494+
assert roth_401k.measure == "roth_401k_contributions"
1495+
assert roth_401k.entity.value == "person"
1496+
self_employed_pension = targets_by_arch_variable[
1497+
"self_employed_pension_contribution_ald"
1498+
]
1499+
assert self_employed_pension.measure == "self_employed_pension_contribution_ald"
1500+
assert self_employed_pension.entity.value == "tax_unit"
14451501
assert "aca_average_monthly_aptc" not in targets_by_arch_variable
14461502

14471503

0 commit comments

Comments
 (0)