refactor: Trust Claude's seed picks, only add bridge nodes

Instead of expanding all callers/callees of seeds (which pulls in noise
from hub nodes like getSession), now:
1. Find direct edges between Claude's seeds
2. Only add non-seed nodes if they bridge 2+ isolated seeds
3. Cross-connection pass discovers hidden edges between result nodes
4. No more unrelated callers of hub nodes polluting the graph

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Colby McHenry
2026-03-22 16:48:55 -05:00
co-authored by Claude Opus 4.6
parent ba30c74461
commit c433e7d1a0
+45 -65
View File
@@ -310,10 +310,11 @@ ${symbolIndex}`;
const stems = keywords.map(kw => kw.length > 5 ? kw.slice(0, Math.max(4, Math.ceil(kw.length * 0.5))) : kw); const stems = keywords.map(kw => kw.length > 5 ? kw.slice(0, Math.max(4, Math.ceil(kw.length * 0.5))) : kw);
const uniqueStems = [...new Set(stems)]; const uniqueStems = [...new Set(stems)];
const isRelevant = (node: Node): boolean => { const _isRelevant = (node: Node): boolean => {
const haystack = `${node.name} ${node.filePath} ${node.qualifiedName}`.toLowerCase(); const haystack = `${node.name} ${node.filePath} ${node.qualifiedName}`.toLowerCase();
return uniqueStems.some(stem => haystack.includes(stem)); return uniqueStems.some(stem => haystack.includes(stem));
}; };
void _isRelevant; // Used by keyword fallback when Claude is unavailable
// Step 1: Find seed nodes // Step 1: Find seed nodes
const seedMap = new Map<string, Node>(); const seedMap = new Map<string, Node>();
@@ -370,78 +371,57 @@ ${symbolIndex}`;
if (!edgeSet.has(ek)) { edgeSet.add(ek); edgeList.push(edge); } if (!edgeSet.has(ek)) { edgeSet.add(ek); edgeList.push(edge); }
}; };
// Step 2: For each seed, get callers/callees (depth 1) // Step 2: Find edges between seeds (trust Claude's picks)
// Only keep neighbors that are relevant or connect to other seeds // Only add non-seed nodes if they bridge two seeds
// Fall back to top-3 non-relevant only if seed has NO relevant neighbors
for (const [seedId] of seedMap) { for (const [seedId] of seedMap) {
if (nodeMap.size >= maxNodes) break; // Check if this seed directly connects to another seed
const callers = this.cg.getCallers(seedId, 1);
const callees = this.cg.getCallees(seedId, 1); const callees = this.cg.getCallees(seedId, 1);
const neighbors = [...callers, ...callees]; const callers = this.cg.getCallers(seedId, 1);
for (const item of [...callees, ...callers]) {
const relevant: typeof neighbors = []; if (seedMap.has(item.node.id)) {
const irrelevant: typeof neighbors = []; addEdge(item.edge);
for (const item of neighbors) {
if (seedMap.has(item.node.id) || isRelevant(item.node)) {
relevant.push(item);
} else {
irrelevant.push(item);
}
}
// Always add relevant neighbors
for (const item of relevant) {
if (nodeMap.size >= maxNodes && !nodeMap.has(item.node.id)) continue;
nodeMap.set(item.node.id, item.node);
addEdge(item.edge);
}
// For seeds with no relevant neighbors, add top-3 callees
// so they're not completely floating
if (relevant.length === 0 && irrelevant.length > 0) {
for (const item of irrelevant.slice(0, 3)) {
if (nodeMap.size >= maxNodes) break;
// Only add if it connects to another node already in the graph
if (nodeMap.has(item.node.id)) {
addEdge(item.edge);
}
} }
} }
} }
// Step 3: Bridge pass — find shared callees between isolated seeds // Step 3: Bridge pass — for isolated seeds, find shared callees
// If two seeds both call the same function, add it as a bridge node // that connect them to other seeds or to each other
const isolatedSeeds = Array.from(seedMap.keys()).filter(id => { const connectedAfterDirect = new Set<string>();
return !edgeList.some(e => e.source === id || e.target === id); for (const e of edgeList) {
}); connectedAfterDirect.add(e.source);
connectedAfterDirect.add(e.target);
}
if (isolatedSeeds.length > 1) { const isolatedSeeds = Array.from(seedMap.keys()).filter(id => !connectedAfterDirect.has(id));
// Collect callees for each isolated seed
const seedCallees = new Map<string, { node: Node; seeds: string[] }>(); // Collect all callees/callers of isolated seeds to find bridges
for (const seedId of isolatedSeeds) { const bridgeCandidates = new Map<string, { node: Node; connectedSeeds: Set<string>; edges: Edge[] }>();
const callees = this.cg.getCallees(seedId, 1); for (const seedId of isolatedSeeds) {
for (const item of callees) { const callees = this.cg.getCallees(seedId, 1);
const existing = seedCallees.get(item.node.id); const callers = this.cg.getCallers(seedId, 1);
if (existing) { for (const item of [...callees, ...callers]) {
existing.seeds.push(seedId); const candidate = bridgeCandidates.get(item.node.id);
} else { if (candidate) {
seedCallees.set(item.node.id, { node: item.node, seeds: [seedId] }); candidate.connectedSeeds.add(seedId);
} candidate.edges.push(item.edge);
} else {
bridgeCandidates.set(item.node.id, {
node: item.node,
connectedSeeds: new Set([seedId]),
edges: [item.edge],
});
} }
} }
// Add bridge nodes that connect 2+ isolated seeds }
for (const [bridgeId, { node: bridgeNode, seeds }] of seedCallees) {
if (seeds.length >= 2 && nodeMap.size < maxNodes) { // Add bridges that connect 2+ seeds, or connect an isolated seed to a connected one
nodeMap.set(bridgeId, bridgeNode); for (const [bridgeId, { node: bridgeNode, connectedSeeds, edges }] of bridgeCandidates) {
// Add edges from each seed to the bridge const connectsToGraph = connectedAfterDirect.has(bridgeId) || seedMap.has(bridgeId);
for (const seedId of seeds) { const connectsMultiple = connectedSeeds.size >= 2;
const callees = this.cg.getCallees(seedId, 1);
for (const item of callees) { if ((connectsMultiple || connectsToGraph) && nodeMap.size < maxNodes) {
if (item.node.id === bridgeId) addEdge(item.edge); nodeMap.set(bridgeId, bridgeNode);
} for (const edge of edges) addEdge(edge);
}
}
} }
} }
@@ -456,7 +436,7 @@ ${symbolIndex}`;
} }
} }
// Step 5: Filter edges and remove isolated non-root nodes // Step 5: Filter and clean up
const finalEdges = edgeList.filter(e => nodeMap.has(e.source) && nodeMap.has(e.target)); const finalEdges = edgeList.filter(e => nodeMap.has(e.source) && nodeMap.has(e.target));
const connectedIds = new Set<string>(); const connectedIds = new Set<string>();