PolicyEngine / PolicyEngine/policyengine-core

FullTracer records no parameter reads for yearly formulas: the at-instant node is cached before the tracing recast

Open
#541 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.