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:
- The parameter value is modified on the shared TaxBenefitSystem ✓
- But calculations are cached at the simulation level with the old values
- 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:
- In policyengine.py: Convert parameter values to reform dict and pass at construction (implemented in this repo)
- In policyengine-us: Refactor to match UK architecture (separate TBS per simulation)
Summary
Reforms applied to US simulations via
p.update()afterMicrosimulationconstruction 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 singletonTaxBenefitSystem:When
p.update()is called after construction:Expected vs Actual
Workaround
Pass the reform at
Microsimulationconstruction time:Comparison with UK
The UK package (
policyengine-uk >= 2.72.3) was refactored in July 2025 to give each simulation its ownTaxBenefitSysteminstance, sop.update()works correctly there.Impact
Any code using
policyengine.pysimulation_modifier pattern (which callsp.update()) for US simulations will silently return baseline results regardless of the reform.Suggested Fix
Either: