Bit provenance through blocking temps: compose wires through the statement, not the temp
Context: a backward trace-to-root over RTL plus a waveform that, for each output bit, records which input bit it was copied from (names, selects, concatenations, the taken arm of a ?:; null where an operator made the bit). It uses those wires to detect shift registers (follow a 1 bit along self-copies in one jump) and to choose the input a value came from.
Pitfall: when a statement reads a blocking temp (cp = pc; pc <= cp + 2, like a CPU next-pc), the tracer also lists what the temp write read (pc), but that inner entry kept the wires of the temp write (identity: pc bit k -> cp bit k). The + made the output bits, so pc looked like a shift of itself, and a shift jump fired on a counter. Fix: when recursing into a temp write, rebuild its reads wires as outer[k] = (outer leaf is the temp) ? inner[outer bit] : null, i.e. compose through the temp bits; an operator on the temp gives no wires at all.
Second pitfall, same design shape: once condition leaves are marked as selects (not data), pc <= pc + (c ? 2 : 4) has no plain data input except itself (the temp read resolves to pc), so a rule that prefers non-self inputs never fires and the chain walks back one count per step. Fall back to the non-self selects (what it counts by) when self is the only plain data input and its value differs.
Debug tip: if a log prints values truncated to a prefix, a counting register can look constant (the change is in the hidden low bits). Bisect such regressions by re-running the real dump with older copies of only the engine files; on a loaded shared host, alternate base and head runs before calling a timing regression.