Completes #1789. Two residual leaks into committed graph.json:
(a) Out-of-root reference targets (a .csproj ProjectReference, .sln
project, or bash `source` pointing outside the scan root) kept an
absolute source_file and an absolute-derived id, because the
relativization post-passes only handled paths under root and silently
left out-of-root ones absolute. They now get a portable walk-up
relative source_file and an `ext_`-namespaced id (basename fallback
for far-outside or cross-drive targets), with edge endpoints remapped.
(b) A symbol whose name normalizes to nothing (minified `$`, a JSONC
`"//"` key) collapsed _make_id(stem, name) to the bare absolute file
stem, leaking the path and colliding with the file node. Guard at the
three mint sites (json_config keys, engine function names) to skip
these no-signal symbols.
Adds regression tests: an out-of-root ProjectReference stays portable
(no scan-path in any id/source_file/edge), and a minified `$` is dropped
while the real function survives.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>