Follow-up to #1899 (thanks for fixing node id / source_file relativization in 0.9.13-0.9.15). On 0.9.28 the same absolute-path-derived slug still leaks, but now into edge endpoints (links[].source / links[].target) instead of node ids.
What happens
A links entry's source/target is a machine-specific slug: the absolute scan path, lowercased with every run of non-alphanumerics collapsed to _, plus a trailing _cs/_py. For example users_alice_code_myrepo_src_pkg_thing_cs instead of the node id it should reference (thing). The node itself has the correct relativized id. Only the edge carries the slug.
Root cause (best guess)
#1899 relativized the node ids, but the id references already written into links endpoints aren't updated in the same pass, so edges keep the pre-relativization slug and point at a string that no longer matches any node's id.
Evidence: most of these slug endpoints do correspond to a real node once you slugify that node's source_file the same way and match. The node exists with a clean id, the edge just references its stale slug. A minority resolve to no node at all (references to files outside the scan root) and are genuine orphans.
Why it matters
The slug is derived from the absolute scan path, so the same source tree built on two different machines (or two different checkout paths) produces a different graph.json. The links differ even though the node id sets are byte-for-byte identical. This breaks build reproducibility and cross-machine caching. We commit graphs to git, so every rebuild shows a spurious diff, but the underlying non-determinism is general.
Scale
About 2,442 such endpoints in a real 79k-node / 232k-link C# graph. Across two machines the node id sets were identical and only the link endpoints differed.
Expected / suggested fix
Apply the #1899 relativization to links source/target as well. Either:
- update edge endpoints when the referenced node's id is relativized, or
- normalize endpoints at serialization time: resolve the path-derived slug back to the canonical node id (match by the node's slugified
source_file), and drop the edge if it resolves to no node.
Repro
Build a graph where a file is referenced from outside the scan root (for example a <ProjectReference Include="..\Core\Core.csproj" /> when only WebApi/ is scanned), then inspect links for source/target values that begin with a path-derived slug (<abs-path-slug>_...) rather than a bare node id.
Follow-up to #1899 (thanks for fixing node
id/source_filerelativization in 0.9.13-0.9.15). On 0.9.28 the same absolute-path-derived slug still leaks, but now into edge endpoints (links[].source/links[].target) instead of node ids.What happens
A
linksentry'ssource/targetis a machine-specific slug: the absolute scan path, lowercased with every run of non-alphanumerics collapsed to_, plus a trailing_cs/_py. For exampleusers_alice_code_myrepo_src_pkg_thing_csinstead of the node id it should reference (thing). The node itself has the correct relativized id. Only the edge carries the slug.Root cause (best guess)
#1899 relativized the node ids, but the id references already written into
linksendpoints aren't updated in the same pass, so edges keep the pre-relativization slug and point at a string that no longer matches any node's id.Evidence: most of these slug endpoints do correspond to a real node once you slugify that node's
source_filethe same way and match. The node exists with a clean id, the edge just references its stale slug. A minority resolve to no node at all (references to files outside the scan root) and are genuine orphans.Why it matters
The slug is derived from the absolute scan path, so the same source tree built on two different machines (or two different checkout paths) produces a different
graph.json. Thelinksdiffer even though the node id sets are byte-for-byte identical. This breaks build reproducibility and cross-machine caching. We commit graphs to git, so every rebuild shows a spurious diff, but the underlying non-determinism is general.Scale
About 2,442 such endpoints in a real 79k-node / 232k-link C# graph. Across two machines the node id sets were identical and only the link endpoints differed.
Expected / suggested fix
Apply the #1899 relativization to
linkssource/targetas well. Either:source_file), and drop the edge if it resolves to no node.Repro
Build a graph where a file is referenced from outside the scan root (for example a
<ProjectReference Include="..\Core\Core.csproj" />when onlyWebApi/is scanned), then inspectlinksforsource/targetvalues that begin with a path-derived slug (<abs-path-slug>_...) rather than a bare node id.