Skip to content

Add federal vs. state budgetary impact to economic_impact_analysis #289

@MaxGhenis

Description

@MaxGhenis

Context

PolicyEngine/policyengine-us#8076 added Person-level variables federal_benefit_cost / state_benefit_cost that split benefit expenditures between levels of government (currently covers Medicaid FMAP and CHIP eFMAP; will extend to SNAP OBBBA FY2028 state match, etc.).

Today economic_impact_analysis() in src/policyengine/tax_benefit_models/us/analysis.py returns per-program stats and aggregate impacts, but doesn't partition benefit spending by federal vs. state. Every consumer — policyengine-api's compare.py::budgetary_impact (PolicyEngine/policyengine-api#3481), analysis notebooks (PolicyEngine/analysis-notebooks#131), ad-hoc scripts — needs the same arithmetic, so the logic belongs here, not duplicated in each caller.

Proposal

Extend PolicyReformAnalysis to expose:

  • federal_budgetary_impact: federal tax revenue change (income_tax + payroll_tax) minus federal benefit spending change (federal_benefit_cost)
  • state_budgetary_impact: state tax revenue change (state_income_tax) minus state benefit spending change (state_benefit_cost)
  • total_budgetary_impact: existing sum, unchanged

Implementation: add two ChangeAggregate(variable="federal_benefit_cost", type=ChangeAggregateType.SUM) / state_benefit_cost calls alongside the existing per-program aggregates, and expose the federal/state splits as top-level fields on the analysis object.

Also tag ProgramStatistics entries with a level_of_government field ("federal", "state", or "shared") so consumers can filter per-program rows. For shared programs like Medicaid/CHIP, also populate federal_change / state_change using the new variables.

Why here vs. API

  • Thin arithmetic on microsim sums — no Flask-specific state
  • Analysis notebooks and ad-hoc Python scripts (not just the app) need this split
  • policyengine-api#3481 becomes a pass-through wiring change once this lands

Example

from policyengine.tax_benefit_models.us import economic_impact_analysis

analysis = economic_impact_analysis(baseline_sim, reform_sim)
print(f"Federal cost: ${analysis.federal_budgetary_impact / 1e9:+.1f}B")
print(f"State cost:   ${analysis.state_budgetary_impact / 1e9:+.1f}B")
print(f"Total:        ${analysis.total_budgetary_impact / 1e9:+.1f}B")

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions