Skip to content

US reforms silently fail when applied via p.update() after Microsimulation construction #232

@anth-volk

Description

@anth-volk

Summary

Reforms applied to US simulations via p.update() after Microsimulation construction have no effect on calculations. The parameter values are modified, but the tax calculations return baseline results, causing silent failures.

Root Cause

The US country package (policyengine-us) uses a shared singleton TaxBenefitSystem:

# policyengine_us/system.py
system = CountryTaxBenefitSystem()  # Module-level singleton

class Microsimulation(CoreMicrosimulation):
    default_tax_benefit_system_instance = system  # All sims share this

When p.update() is called after construction:

  1. The parameter value is modified on the shared TaxBenefitSystem ✓
  2. But calculations are cached at the simulation level with the old values
  3. The updated parameter is never used in calculations ✗

Expected vs Actual

Metric Expected Actual
Parameter value Changed ✓ Changed ✓
Tax calculation Different Unchanged

Workaround

Pass the reform at Microsimulation construction time:

reform_dict = {
    "gov.irs.deductions.standard.amount.SINGLE": {
        "2024-01-01": 29200
    }
}
microsim = Microsimulation(reform=reform_dict)  # Works correctly

Comparison with UK

The UK package (policyengine-uk >= 2.72.3) was refactored in July 2025 to give each simulation its own TaxBenefitSystem instance, so p.update() works correctly there.

Package Architecture p.update() Works?
policyengine-uk Separate TBS per simulation ✅ Yes
policyengine-us Shared singleton TBS ❌ No

Impact

Any code using policyengine.py simulation_modifier pattern (which calls p.update()) for US simulations will silently return baseline results regardless of the reform.

Suggested Fix

Either:

  1. In policyengine.py: Convert parameter values to reform dict and pass at construction (implemented in this repo)
  2. In policyengine-us: Refactor to match UK architecture (separate TBS per simulation)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions