Skip to content

Gathering Exact Graph Freeze Timing

src/joint_graph/exact/gathering.py must mirror the live src/environments/gridworlds/gathering/env.py step order exactly, or the joint-graph artifacts drift away from replay buffers and OM training fails.

Regression fixed on 2026-04-22

The exact gathering_successors(...) helper used to remove apples for any agent that was "not newly frozen" at the end of the step. That was subtly wrong for agents that started the step frozen:

  • the live env collects apples before decrementing freeze timers
  • a frozen-at-start agent therefore cannot collect on that turn
  • the next observation may show that agent active again while an apple is still present underneath it

The exact builder was deleting those apples one step too early, so legal_joint_graph.pkl and derived env_transition_graph.pkl were missing a small set of valid Gathering observations. This surfaced in OM preparation as dataset states from wm/D.pkl that could not be found in the graph.

Correct collection rule

During exact successor generation, an agent may collect an apple only if both of these are true:

  • it was not frozen at the start of the step
  • it was not newly tagged into a frozen state during the step

That matches the runtime env's "collect, then decrement timers" ordering.

Cache invalidation

notebooks/utils/dynamics.py now writes a legal_joint_graph.metadata.pkl sidecar next to legal_joint_graph.pkl. The metadata records:

  • env module/name
  • expected public-state width
  • exact builder identity and source hash
  • seed and builder kwargs used to construct the graph

If the sidecar is missing or mismatched, the legal graph is rebuilt instead of being silently reused. This is important whenever exact-graph semantics change without changing the public-state width.