Problem
The daemon's mergeGraph in internal/files/daemon.go remaps old→new UUIDs for File and Function nodes when a file is re-processed incrementally. But it does not remap Type or Class nodes. When the API returns new UUIDs for these node types, existing relationships from unchanged files still point at the old IDs, creating dangling edges.
Repro
- Full generate on Next.js (~12,000 nodes)
- Incremental update for 3 files including
packages/next/src/shared/lib/constants.ts
- Merge the incremental result into the baseline
- Check for dangling edges:
DANGLING: type=imports, endNode c100dae7:51fd:fce5:81c8:9976494ceb39
Missing node was: labels=['Type'], filePath=constants.ts, name=CompilerNameValues
A Type node (CompilerNameValues) from constants.ts got a new UUID in the incremental response. An imports relationship from an unchanged file still references the old UUID. The merge kept the old relationship but didn't remap the endpoint.
Root cause
daemon.go lines ~380-410 build the old→new remap only for File and Function nodes:
if n.HasLabel("File") {
if newID, ok := incFileByPath[fp]; ok && newID != n.ID {
oldToNew[n.ID] = newID
}
} else if n.HasLabel("Function") {
// ...remap by filePath:name...
}
Type and Class nodes are not remapped.
Fix
Extend the remap to cover Type and Class nodes using the same filePath:name key pattern:
} else if n.HasLabel("Type") || n.HasLabel("Class") {
name := n.Prop("name")
key := fp + ":" + name
if newID, ok := incTypeByKey[key]; ok && newID != n.ID {
oldToNew[n.ID] = newID
}
}
This requires building incTypeByKey and incClassByKey maps from the incremental response, same as incFnByKey.
Impact
Low — affects relationships pointing at Type/Class nodes in changed files. Most relationships point at File or Function nodes which are already remapped. Found 1 dangling edge in a 27,000-relationship graph (0.004%). But it's a correctness issue that will compound with more incremental updates.
Pre-existing in both the CLI (internal/files/daemon.go) and graph-fusion (internal/daemon/daemon.go).
Problem
The daemon's
mergeGraphininternal/files/daemon.goremaps old→new UUIDs forFileandFunctionnodes when a file is re-processed incrementally. But it does not remapTypeorClassnodes. When the API returns new UUIDs for these node types, existing relationships from unchanged files still point at the old IDs, creating dangling edges.Repro
packages/next/src/shared/lib/constants.tsA
Typenode (CompilerNameValues) fromconstants.tsgot a new UUID in the incremental response. Animportsrelationship from an unchanged file still references the old UUID. The merge kept the old relationship but didn't remap the endpoint.Root cause
daemon.golines ~380-410 build theold→newremap only forFileandFunctionnodes:TypeandClassnodes are not remapped.Fix
Extend the remap to cover
TypeandClassnodes using the samefilePath:namekey pattern:This requires building
incTypeByKeyandincClassByKeymaps from the incremental response, same asincFnByKey.Impact
Low — affects relationships pointing at Type/Class nodes in changed files. Most relationships point at File or Function nodes which are already remapped. Found 1 dangling edge in a 27,000-relationship graph (0.004%). But it's a correctness issue that will compound with more incremental updates.
Pre-existing in both the CLI (
internal/files/daemon.go) and graph-fusion (internal/daemon/daemon.go).