# Investigation Report: Node Expansion Not Working

## Summary
User reports that directory/file nodes show expand/collapse icons ("+"/"-") but clicking them doesn't expand/collapse the hierarchy.

## Code Analysis

### 1. Click Handler Attachment ✓ CORRECT
**Location**: `/Users/masa/Projects/mcp-vector-search/src/mcp_vector_search/visualization/index.html:481`

```javascript
.on("click", handleNodeClick)
```

The click handler IS correctly attached to each node group (`<g>` element).

### 2. Pointer Events ✓ CORRECT
**Locations**: Lines 123, 130, 542

All text elements (labels, icons, expand indicators) have `pointer-events: none`, which correctly allows clicks to pass through to the parent `<g>` element where the handler is attached.

### 3. hasChildren() Function ✓ CORRECT
**Location**: Line 586-590

```javascript
function hasChildren(node) {
    return allLinks.some(l => (l.source.id || l.source) === node.id);
}
```

This correctly checks if a node is a parent (source) in any link. The `(l.source.id || l.source)` pattern handles both:
- **Before D3 mutation**: `l.source` is a string (e.g., "dir_abc")
- **After D3 mutation**: `l.source` is an object with `.id` property

### 4. handleNodeClick() Function ✓ LOGIC CORRECT
**Location**: Line 593-624

The logic flow is correct:
1. Show content pane (always)
2. Check if node has children
3. If yes, toggle collapse/expand state
4. Call `renderGraph()` to update visualization

### 5. expandNode() Function ✓ LOGIC CORRECT
**Location**: Line 626-654

Correctly:
1. Removes node from `collapsedNodes`
2. Finds children by filtering `allLinks` for links where source matches node ID
3. Adds each child to `visibleNodes`
4. Adds each child to `collapsedNodes` (children start collapsed)

### 6. Data Structure ✓ VERIFIED
**File**: `/Users/masa/Projects/mcp-vector-search/chunk-graph.json`

```
Total nodes: 7015
Total links: 7006
Directory nodes: 26
Root directories: 5 (docs, examples, scripts, src, tests)
```

Sample link structure:
```json
{
  "source": "dir_9f40c524",
  "target": "dir_504f9a81",
  "type": "dir_hierarchy"
}
```

Example: `docs` directory has 22 child links, confirming hierarchy is correctly structured.

## Debugging Added

I've added comprehensive console logging to help diagnose the issue:

### Initial State Logging (Line 445-450)
Logs on page load:
- Total nodes and links
- Root nodes identified
- Initial visible and collapsed node sets

### Click Handler Logging (Line 594-623)
Logs on every node click:
- Node name, type, and ID
- Whether node has children
- Whether node is collapsed
- Which action is taken (expand/collapse)

### hasChildren() Logging (Line 587-590)
Logs every time it's called:
- Node name
- Result (true/false)
- Number of links checked

### expandNode() Logging (Line 627-653)
Logs during expansion:
- Node being expanded
- Number of child links found
- Number of child nodes found
- Each child being added to visibleNodes
- Final visibleNodes size

### renderGraph() Logging (Line 456-467)
Logs on every render:
- Size of visibleNodes and collapsedNodes sets
- Number of nodes being rendered
- Number of links being rendered

## Testing Instructions

1. **Open the visualization**:
   ```bash
   cd /Users/masa/Projects/mcp-vector-search/src/mcp_vector_search/visualization
   open index.html
   ```

2. **Open Browser DevTools**:
   - Press F12 or Cmd+Option+I (Mac)
   - Go to the Console tab

3. **Check Initial State**:
   - You should see "=== INITIAL STATE ===" logged
   - Verify root nodes are identified correctly
   - Should show 5-9 root nodes

4. **Click a Directory Node**:
   - Click on "docs", "src", or another directory node
   - Watch console for "=== NODE CLICKED ===" messages
   - Check what happens:

### Expected Behavior:
```
=== NODE CLICKED ===
Node: docs Type: directory ID: dir_9f40c524
hasChildren(docs): true Checking 7006 links for node ID: dir_9f40c524
Node has children: true
Node is collapsed: true
Expanding node...
expandNode(docs): Removing from collapsedNodes
  Found 22 child links for node dir_9f40c524
  Found 22 child nodes: [_archive, analysis, architecture, ...]
    Adding child to visibleNodes: _archive (dir_504f9a81)
    Adding child to visibleNodes: analysis (dir_abc123)
    ...
  visibleNodes now has 27 items
=== renderGraph() called ===
visibleNodes.size: 27
Rendering 27 visible nodes
Rendering XX visible links
```

### Possible Issues to Look For:

#### Issue A: hasChildren() Returns False
**Symptom**: Console shows `Node has children: false`
**Cause**: Links not properly structured or node ID mismatch
**Check**:
- Are node IDs consistent between nodes and links?
- Are links properly loaded?

#### Issue B: No Children Found
**Symptom**: Console shows `Found 0 child links`
**Cause**: Link source/target ID mismatch or D3 mutation issue
**Check**:
- What is the format of `l.source` (string or object)?
- Does `l.source` or `l.source.id` match the node ID?

#### Issue C: Children Added But Not Rendered
**Symptom**: Console shows children added to visibleNodes, but renderGraph() shows same count
**Cause**: visibleNodes not being updated correctly
**Check**:
- Does `visibleNodes.size` increase after expansion?
- Are the new nodes actually being rendered?

#### Issue D: Click Handler Not Firing
**Symptom**: No "=== NODE CLICKED ===" in console
**Cause**: Event handler not attached or being blocked
**Check**:
- Are there any JavaScript errors on page load?
- Try clicking different parts of the node (center, edge, icon area)

## Potential Root Causes

Based on the code analysis, here are the most likely issues:

### 1. D3 Link Mutation Issue (MOST LIKELY)
**Problem**: D3's `forceLink()` mutates link objects, replacing string IDs with object references.

When `visibleLinks` is created by filtering `allLinks`, it creates a new array but **shares the same link objects**. When D3 mutates `visibleLinks`, it also mutates `allLinks`.

**Impact**: After first render, all links in `allLinks` have object references instead of strings. The `hasChildren()` function should still work due to the `(l.source.id || l.source)` pattern, but there could be edge cases.

**Test**: Check console to see if `hasChildren()` is returning the correct value after clicking.

### 2. Event Propagation Issue
**Problem**: Click events might be consumed by drag handler or other events.

**Test**: Check if "=== NODE CLICKED ===" appears in console when clicking.

### 3. Render Not Updating Visual State
**Problem**: Even if expansion logic works, the visual update might fail.

**Test**: Check if `renderGraph()` logs show increasing node counts after expansion.

## Next Steps

1. **Run the visualization with debugging**
2. **Open browser console**
3. **Click a directory node**
4. **Copy all console output**
5. **Analyze which of the above issues is occurring**

## Files Modified

- `/Users/masa/Projects/mcp-vector-search/src/mcp_vector_search/visualization/index.html`
  - Added comprehensive console.log() debugging throughout
  - No logic changes - only added logging

## Conclusion

The code logic appears correct. The issue is likely:

1. **D3 link mutation** causing unexpected behavior in `hasChildren()` or `expandNode()`
2. **Event handling** issue preventing clicks from being registered
3. **Visual update** issue where expansion logic works but rendering doesn't update

The added debugging will help pinpoint the exact issue. Please run the visualization and check the browser console output when clicking nodes.
