Surfaced while closing the node-id leak class (#2231/#2243). Distinct vector, own issue.
Problem. The per-file AST cache stores extracted nodes/edges keyed by content + relative path (namespaced by extractor version). When the same corpus is reached under a different absolute root (a clone, a moved checkout, a second mount) and the cache is carried along, a warm cache hit replays nodes/edges whose ids were minted from the ORIGINAL absolute root. The id-remap / final-canonicalization passes in extract() cannot fix these, because those ids no longer match any current-path form (the current run never sees the original root), so a stale machine-slug id can survive into graph.json on a cache hit.
This is separate from #2231/#2243 (which fix producers on a cold run) and from #2199 (stat-index portability, already fixed) — it's the AST result cache replaying pre-canonicalization ids.
Fix direction. Canonicalize node ids / edge endpoints when replaying a cached entry (re-anchor any id/endpoint minted from the entry's stored absolute source_file to the current root), or store cache entries already canonicalized (root-relative ids) so a replay is portable by construction. Mirror the manifest.json / stat-index.json portability approach (#2199).
Test. Extract a corpus under root A (populate cache), copy the tree + graphify-out to root B, extract under B with the warm cache, assert no node id / edge endpoint contains the root-A slug and ids match a cold B extraction.
Surfaced while closing the node-id leak class (#2231/#2243). Distinct vector, own issue.
Problem. The per-file AST cache stores extracted nodes/edges keyed by content + relative path (namespaced by extractor version). When the same corpus is reached under a different absolute root (a clone, a moved checkout, a second mount) and the cache is carried along, a warm cache hit replays nodes/edges whose ids were minted from the ORIGINAL absolute root. The id-remap / final-canonicalization passes in extract() cannot fix these, because those ids no longer match any current-path form (the current run never sees the original root), so a stale machine-slug id can survive into graph.json on a cache hit.
This is separate from #2231/#2243 (which fix producers on a cold run) and from #2199 (stat-index portability, already fixed) — it's the AST result cache replaying pre-canonicalization ids.
Fix direction. Canonicalize node ids / edge endpoints when replaying a cached entry (re-anchor any id/endpoint minted from the entry's stored absolute source_file to the current root), or store cache entries already canonicalized (root-relative ids) so a replay is portable by construction. Mirror the manifest.json / stat-index.json portability approach (#2199).
Test. Extract a corpus under root A (populate cache), copy the tree + graphify-out to root B, extract under B with the warm cache, assert no node id / edge endpoint contains the root-A slug and ids match a cold B extraction.