Conversation
A fixed graph keeps its change set in a plain priority queue, which holds the same node twice, and innerUpdateChanged() never checks the node it polls. Two things put duplicates in there: the constructor queues every node without setting isChanged, so the first markChanged() queues it again; and the pass tracks which nodes it has queued rather than which ones it has updated, seeded with the first marked node only, so a node marked before the pass is queued again once a node ordered before it changes. Its suppliers then run twice. Track the updated nodes instead and skip a node that is polled twice. The nodes are polled in topological order, so everything an update can reach is polled after it and one update per node is always enough. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"Diamond" named the value/duration/endTime dependency shape, but only duration and endTime are graph nodes; value is a genuine variable, so it never becomes one. The actual graph is a single edge, not a diamond. Rename to what the domain demonstrates: duration and endTime both source from value directly, and endTime also sources from duration. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Benchmarking the previous commit surfaced a regression it introduced: the old code returned immediately when changeTracker was empty, before allocating visited. The new updated BitSet was allocated unconditionally, even on a pass with nothing to do, which the "dirty" flag in VariableSupport can trigger for a move that never touches this graph at all. Restore the early return. Confirmed on a chain of 20 shared-source shadow variables across 200 entities: no-op passes go from roughly 155-160ns back to roughly 100ns, matching the pre-fix baseline, while the real fix still cuts supplier calls from ~35 to exactly 20 per move on the same domain. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
fodzal
requested review from
Christopher-Chianelli and
triceo
as code owners
September 17, 2026 13:29
triceo
removed their request for review
September 17, 2026 13:32
fodzal
marked this pull request as draft
September 21, 2026 08:00
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue.
In a fixed variable reference graph, when two shadow variables share a source and one
also depends on the other, the shared source enqueues both directly, and updating the first
re-enqueues the second through their edge before dedup catches it. Its supplier then runs twice for
nothing:
valuemarksdurationandendTimedirectly;durationalso marksendTimevia theduration → endTimeedge.endTimeSupplierruns twice for the same pass.Fix. The dedup check happened at enqueue time (
visited, seeded from only the first queuednode) instead of at dequeue time. Track updated nodes and check when a node comes out of the
queue instead of when it goes in:
Benchmark. 200 entities, each a chain of 20 shadow ints all sourced from the same genuine
variable and each also depending on the previous link; every move marks all 20 directly and
re-marks 19 of them through the chain: