Summary
After Simulation.subsample() on a reform simulation, the rebuilt baseline branch carries the reform policy, and the saved baseline tax-benefit system is stranded under a stray branches["tax_benefit_system"] dict key. Anything that reads the baseline branch after subsampling (e.g. labor-supply behavioral responses, which compare against simulation.get_branch("baseline")) silently compares reform against reform.
Where
simulation.py, end of subsample() — master L1854–1858:
# Ensure the baseline branch has the new data.
if "baseline" in self.branches:
baseline_tax_benefit_system = self.branches["baseline"].tax_benefit_system
self.branches["baseline"] = self.clone()
self.branches["tax_benefit_system"] = baseline_tax_benefit_system
self.clone() clones the reform simulation (including a clone of its reformed system), and the last line assigns the saved baseline system into the branches dict under a string key instead of restoring it onto the rebuilt branch (self.branches["baseline"].tax_benefit_system = ...). The rebuilt branch also never gets branch_name = "baseline" / parent_branch set the way get_branch would set them.
Executed repro (country template)
from policyengine_core.country_template import Microsimulation
REFORM_RATE = 0.42
INSTANT = "2022-01-01"
simulation = Microsimulation(reform={"taxes.income_tax_rate": {INSTANT: REFORM_RATE}})
baseline_system_before = simulation.branches["baseline"].tax_benefit_system
# IDs are ETERNITY inputs while weights are annual, so pass the weight period.
simulation.subsample(n=1, seed="phase-d", time_period="2022")
baseline_system_after = simulation.branches["baseline"].tax_benefit_system
print(list(simulation.branches))
print(baseline_system_after.parameters.taxes.income_tax_rate(INSTANT))
print("tax_benefit_system" in simulation.branches)
print(simulation.branches["tax_benefit_system"] is baseline_system_before)
Output (master):
['baseline', 'tax_benefit_system']
0.42 # baseline branch now carries the reform rate; true baseline is 0.15
True # stray dict key exists
True # ...and holds the original baseline system
Expected
After subsampling, branches["baseline"] should hold the subsampled populations with the original baseline tax-benefit system (rate 0.15 here), and no "tax_benefit_system" key should appear in branches.
Context
🤖 Generated with Claude Code
Summary
After
Simulation.subsample()on a reform simulation, the rebuiltbaselinebranch carries the reform policy, and the saved baseline tax-benefit system is stranded under a straybranches["tax_benefit_system"]dict key. Anything that reads the baseline branch after subsampling (e.g. labor-supply behavioral responses, which compare againstsimulation.get_branch("baseline")) silently compares reform against reform.Where
simulation.py, end ofsubsample()— master L1854–1858:self.clone()clones the reform simulation (including a clone of its reformed system), and the last line assigns the saved baseline system into thebranchesdict under a string key instead of restoring it onto the rebuilt branch (self.branches["baseline"].tax_benefit_system = ...). The rebuilt branch also never getsbranch_name = "baseline"/parent_branchset the wayget_branchwould set them.Executed repro (country template)
Output (master):
Expected
After subsampling,
branches["baseline"]should hold the subsampled populations with the original baseline tax-benefit system (rate 0.15 here), and no"tax_benefit_system"key should appear inbranches.Context
subsample()calls neither delete API).🤖 Generated with Claude Code