Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/distinct-tax-expenditure-reform-ids.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Assign distinct `reform_id` values to each national JCT tax expenditure target instead of reusing a single generic reform id for all of them.
19 changes: 12 additions & 7 deletions policyengine_us_data/db/etl_national_targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
etl_argparser,
)

TAX_EXPENDITURE_REFORM_ID = 1


def extract_national_targets(dataset: str = DEFAULT_DATASET):
"""
Expand Down Expand Up @@ -64,43 +62,49 @@ def extract_national_targets(dataset: str = DEFAULT_DATASET):
# These JCT values are tax expenditures, not baseline deduction totals.
# They must be matched against repeal-based income tax deltas in the
# unified calibration path.
tax_expenditure_targets = [
raw_tax_expenditure_targets = [
{
"reform_id": 1,
"variable": "salt_deduction",
"value": 21.247e9,
"source": "Joint Committee on Taxation",
"notes": "SALT deduction tax expenditure",
"year": HARDCODED_YEAR,
},
{
"reform_id": 2,
"variable": "medical_expense_deduction",
"value": 11.4e9,
"source": "Joint Committee on Taxation",
"notes": "Medical expense deduction tax expenditure",
"year": HARDCODED_YEAR,
},
{
"reform_id": 3,
"variable": "charitable_deduction",
"value": 65.301e9,
"source": "Joint Committee on Taxation",
"notes": "Charitable deduction tax expenditure",
"year": HARDCODED_YEAR,
},
{
"reform_id": 4,
"variable": "deductible_mortgage_interest",
"value": 24.8e9,
"source": "Joint Committee on Taxation",
"notes": "Mortgage interest deduction tax expenditure",
"year": HARDCODED_YEAR,
},
{
"reform_id": 5,
"variable": "qualified_business_income_deduction",
"value": 63.1e9,
"source": "Joint Committee on Taxation",
"notes": "QBI deduction tax expenditure",
"year": HARDCODED_YEAR,
},
]
tax_expenditure_targets = [{**target} for target in raw_tax_expenditure_targets]

direct_sum_targets = [
{
Expand Down Expand Up @@ -493,7 +497,7 @@ def load_national_targets(
with Session(engine) as session:
# Get the national stratum
us_stratum = (
session.query(Stratum).filter(Stratum.parent_stratum_id == None).first()
session.query(Stratum).filter(Stratum.parent_stratum_id.is_(None)).first()
)

if not us_stratum:
Expand Down Expand Up @@ -631,6 +635,7 @@ def load_national_targets(

for _, target_data in tax_expenditure_df.iterrows():
target_year = target_data["year"]
target_reform_id = int(target_data["reform_id"])

# Clean up incorrectly scoped baseline rows from older DBs.
if migrated_stratum_ids:
Expand All @@ -641,7 +646,7 @@ def load_national_targets(
Target.variable == target_data["variable"],
Target.period == target_year,
Target.reform_id == 0,
Target.active == True,
Target.active,
)
.all()
)
Expand All @@ -654,7 +659,7 @@ def load_national_targets(
Target.stratum_id == us_stratum.stratum_id,
Target.variable == target_data["variable"],
Target.period == target_year,
Target.reform_id == TAX_EXPENDITURE_REFORM_ID,
Target.reform_id == target_reform_id,
)
.first()
)
Expand All @@ -679,7 +684,7 @@ def load_national_targets(
stratum_id=us_stratum.stratum_id,
variable=target_data["variable"],
period=target_year,
reform_id=TAX_EXPENDITURE_REFORM_ID,
reform_id=target_reform_id,
value=target_data["value"],
active=True,
source="PolicyEngine",
Expand Down
23 changes: 23 additions & 0 deletions policyengine_us_data/tests/test_database_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,29 @@ def test_jct_mortgage_tax_expenditure_uses_mortgage_specific_variable(built_db):
]


def test_jct_tax_expenditure_targets_have_distinct_reform_ids(built_db):
"""Each JCT tax expenditure target should have its own reform id."""
conn = sqlite3.connect(str(built_db))
rows = conn.execute("""
SELECT t.variable, t.reform_id
FROM targets t
WHERE t.notes LIKE '%Modeled as repeal-based income tax expenditure target%'
AND t.notes LIKE '%Source: Joint Committee on Taxation%'
ORDER BY t.variable
""").fetchall()
conn.close()

expected = [
("charitable_deduction", 3),
("deductible_mortgage_interest", 4),
("medical_expense_deduction", 2),
("qualified_business_income_deduction", 5),
("salt_deduction", 1),
]

assert rows == expected


def test_state_income_tax_targets(built_db):
"""State income tax targets should cover all income-tax states."""
conn = sqlite3.connect(str(built_db))
Expand Down
Loading