PolicyEngine / PolicyEngine/policyengine-core
FullTracer records no parameter reads for yearly formulas: the at-instant node is cached before the tracing recast
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 22
- Forks
- 30
- Avg merge
- 14h 33m
- Merged PRs (30d)
- 7
Description
Summary
With simulation.trace = True, TraceNode.parameters is empty for almost every yearly-period formula. Monthly formulas (SNAP) are recorded, which hides the problem. Verified on policyengine-core 3.30.2 with policyengine-us 1.808.0.
Cause
Simulation._run_formula (simulation.py:1099) soft-recasts tax_benefit_system.parameters to tracing only when a formula runs:
if self.trace and not isinstance(self.tax_benefit_system.parameters, TracingParameterNodeAtInstant):
self.tax_benefit_system.parameters.trace = True
...
But ParameterNode._get_at_instant (parameter_node.py:216) caches the ParameterNodeAtInstant per instant, and the yearly instant is first requested before any formula runs (defined_for and adds/subtracts evaluation, uprating), while parameters.trace is still False. The cached node is therefore a plain ParameterNodeAtInstant, and every later parameters(period).gov.* read for that instant bypasses TracingParameterNodeAtInstant. Monthly instants are created after the recast, so they trace correctly.
Reproduce
from policyengine_us import Simulation
sim = Simulation(situation={...household with a child, employment income...})
sim.trace = True
sim.calculate("ctc_child_individual_maximum", 2026)
node = next(t for t in sim.tracer.trees if t.name == "ctc_child_individual_maximum")
print([p.name for p in node.parameters]) # [] — expected gov.irs.credits.ctc.amount.base
print(type(sim.tax_benefit_system.parameters("2026-01-01")).__name__) # ParameterNodeAtInstant, not Tracing…
Workaround
Before any calculation:
root = sim.tax_benefit_system.parameters
root.trace, root.tracer, root.branch_name = True, sim.tracer, sim.branch_name
# recursively clear ParameterNode._at_instant_cache on every node
Proposed fix
Do the recast in the Simulation.trace setter (simulation.py:523) rather than lazily in _run_formula, and clear the at-instant caches on the parameter tree when tracing is switched on (and off). _run_formula can keep its check as a safety net.
Context
Found while building a traced parameter → variable dependency map for validation matching in policyengine-app-v2 (PolicyEngine/policyengine-app-v2#1180). Related: #542 covers the second gap (scale/bracket reads never recorded).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the Simulation.trace setter and _run_formula in simulation.py, then inspect ParameterNode._get_at_instant and its cache in parameter_node.py. Reproduce the yearly formula case with tracing enabled and verify that cached parameter nodes are recast and caches are cleared when tracing changes, so TraceNode.parameters records the expected parameter reads.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100