Skip to content

Point a cached ID at the node that actually wrote it - #85

Merged
revarbat merged 1 commit into
mainfrom
fix-cached-id-attribution
Aug 10, 2026
Merged

Point a cached ID at the node that actually wrote it#85
revarbat merged 1 commit into
mainfrom
fix-cached-id-attribution

Conversation

@revarbat

Copy link
Copy Markdown
Member

Follow-up to #84. Selecting either of two identical cylinders highlighted the same line in the editor.

#84 gave cached bodies fresh originalIDs, but each fresh ID inherited the node of whichever call site was generated first — so the viewport separated the two cylinders while the editor pointed both at line 1.

Which node a fresh ID carries now depends on what the old one stood for:

  • the reused node itself — two pieces of source wrote the same shape, so this copy belongs to the node reusing it
  • something deeper inside it — the cube and sphere in a module called twice keep their own nodes, since both calls really do come from that one module body. Re-pointing those at the call site was my first attempt and collapses every part of a call onto one line: the same defect, one level down.

Telling those apart needs the node whose generation filled the entry, recorded per cache key for the render's duration (cleared with idToNode, whose pointers share its lifetime).

Second bug, also from #84

Across renders the old IDs predate the current idToNode, so nothing was written for them — geometry served from an earlier evaluate carried no source node at all. A re-render of an unchanged file is all cache hits, which left nothing in the viewport pickable.

Verified

Attribution now matches an uncached render exactly:

no cache cached
two cylinders [1, 2] [1, 2]
module called twice [2, 3, 2, 3] [2, 3, 2, 3]
three identical spheres [1, 2, 3] [1, 2, 3]
reused difference() [1, 1, 1, 1] [1, 1, 1, 1]

805/805 C++ tests pass. Each new assertion was negative-controlled — always-call-site, always-old-node, never-serve-from-cache, and #84's exact code each fail their own test and no others.

Known ceiling

Two subtrees identical down to their transforms still share one attribution: only the inner node is a cache hit, and the producer check keeps the first copy's descendants. They occupy the same space, so there is nothing to select apart.

🤖 Generated with Claude Code

0.27.0 gave cached bodies fresh originalIDs so two identical shapes
stopped being one thing to select, but each fresh ID inherited the node
of whichever call site was generated first. The viewport then separated
the two cylinders while the editor highlighted one line for either.

Which node a fresh ID should carry depends on what the old one stood
for. An ID standing for the reused node itself belongs to the node
reusing it -- two pieces of source wrote the same shape. An ID standing
for something deeper inside, the cube and sphere within a module called
twice, keeps its own node: both calls really do come from the one body
that spells those parts out, and re-pointing them at the call site
collapses every part of a call onto a single line -- the same defect,
one level down. Telling the two apart needs the node whose generation
filled the entry, so record it per cache key for the render's duration.

Also fixes a second case 0.27.0 had backwards: across renders the old
IDs predate this render's idToNode, so nothing was written for them at
all and geometry served from an earlier evaluate carried no source node.
A re-render of an unchanged file is all cache hits, which left nothing
in the viewport pickable.

Attribution now matches an uncached render exactly for identical
primitives at different call sites, reused modules, and reused
differences. CacheHitSkipsRegeneratingTheSubtree was asserting the empty
idToNode the second bug produced; it now reads the skip through the
child's own bodies, which is what it meant all along.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@revarbat
revarbat merged commit c501d68 into main Aug 10, 2026
3 checks passed
@revarbat
revarbat deleted the fix-cached-id-attribution branch August 10, 2026 03:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant