# KG Authorship Fix - Person Nodes & AUTHORED/MODIFIED Relationships

## Summary

Fixed the Knowledge Graph builder to properly create Person nodes and distinguish between AUTHORED (original author) and MODIFIED (subsequent contributors) relationships.

## Problem

Before the fix:
- **Persons**: 0
- **AUTHORED**: 0
- **MODIFIED**: 0

The authorship extraction code had several critical issues:
1. Only captured the MOST RECENT author per file (skipped all others)
2. No MODIFIED relationships were created
3. Limited to 500 commits (too few for proper attribution)
4. Missing `add_modified_relationship_sync` method

## Solution

### 1. Added `add_modified_relationship_sync` to `knowledge_graph.py`

Created synchronous method to create MODIFIED relationships, mirroring the existing `add_authored_relationship_sync` pattern.

**Location**: `src/mcp_vector_search/core/knowledge_graph.py` (after line 1900)

```python
def add_modified_relationship_sync(
    self,
    person_id: str,
    entity_id: str,
    timestamp: str,
    commit_sha: str,
    lines: int,
) -> None:
    """Add a MODIFIED relationship (synchronous)."""
    # Creates MODIFIED edge with timestamp, commit_sha, lines_changed
```

### 2. Fixed `_extract_authorship_sync` in `kg_builder.py`

Changed from single-author-per-file to multi-author collection with AUTHORED/MODIFIED distinction.

**Location**: `src/mcp_vector_search/core/kg_builder.py` (lines 3248-3433)

**Key changes**:
- Changed `file_author_map: dict[str, tuple]` → `file_authors_map: dict[str, list[tuple]]`
- Collect ALL authors per file (not just most recent)
- Sort authors chronologically (oldest first)
- De-duplicate authors (person may have multiple commits)
- First (oldest) author → AUTHORED relationship
- Subsequent authors → MODIFIED relationships
- Increased commit limit: 500 → 5000 for better coverage
- Increased timeout: 30s → 60s to handle larger history

**Algorithm**:
```python
# 1. Collect all authors per file from git log
file_authors_map[file_path].append((person_id, timestamp, commit_sha))

# 2. Sort chronologically (oldest first)
authors_sorted = sorted(authors, key=lambda x: x[1])

# 3. De-duplicate by person_id
unique_authors = [first occurrence of each person_id]

# 4. First author = AUTHORED, rest = MODIFIED
first_author → add_authored_relationship_sync()
for subsequent_author → add_modified_relationship_sync()
```

### 3. Fixed `_extract_authorship_fast` (async version)

Applied the same fix to the async version for consistency.

**Location**: `src/mcp_vector_search/core/kg_builder.py` (lines 3144-3246)

### 4. Updated `_extract_authorship_from_blame_detailed` docstring

Clarified that this slower git-blame version only extracts AUTHORED relationships.

## Results

After the fix:
```
Phase 4/4: Extracting git metadata
  ✓ 5 persons from git
  ✓ project: mcp-vector-search
  ✓ 1,620 authored, 740 modified
  ✓ 107,634 part_of
```

**Statistics**:
- **Persons**: 5 (5 unique contributors)
- **AUTHORED**: 1,620 (original authorship)
- **MODIFIED**: 740 (subsequent modifications)
- **Total authorship relationships**: 2,360

## Technical Details

### Person Node Structure
```python
@dataclass
class Person:
    id: str                  # person:<email_hash>
    name: str                # Display name from git
    email_hash: str          # SHA256 of email (privacy)
    commits_count: int = 0   # Total commits
    first_commit: str | None # ISO timestamp
    last_commit: str | None  # ISO timestamp
```

### Relationship Properties

**AUTHORED** (Person → CodeEntity):
- `timestamp`: ISO timestamp of original authorship
- `commit_sha`: Git commit SHA
- `lines_authored`: Number of lines (currently 0)

**MODIFIED** (Person → CodeEntity):
- `timestamp`: ISO timestamp of modification
- `commit_sha`: Git commit SHA
- `lines_changed`: Number of lines (currently 0)

### Git Log Command
```bash
git log --format=%H|%an|%ae|%aI --name-only -n 5000
```

**Format**: `commit_sha|author_name|author_email|timestamp`

**Output example**:
```
abc123|John Doe|john@example.com|2025-01-15T10:30:00Z

src/core/kg_builder.py
src/core/knowledge_graph.py
```

## Files Modified

1. **src/mcp_vector_search/core/knowledge_graph.py**
   - Added `add_modified_relationship_sync` method

2. **src/mcp_vector_search/core/kg_builder.py**
   - Fixed `_extract_authorship_sync` (synchronous)
   - Fixed `_extract_authorship_fast` (async)
   - Updated `_extract_authorship_from_blame_detailed` docstring

## Testing

### Rebuild KG
```bash
uv run mcp-vector-search kg build --force
```

### Verify Statistics
```bash
uv run mcp-vector-search kg stats
```

Expected output:
- Persons > 0
- AUTHORED > 0
- MODIFIED > 0

## Performance

- **Build time**: ~35.6s total
- **Git metadata extraction**: 26.4s (Phase 4)
- **Commit limit**: 5000 commits (adjustable)
- **Timeout**: 60s (increased from 30s)

## Future Improvements

1. **Line-level attribution**: Currently `lines_authored` and `lines_changed` are set to 0
   - Could use `git blame` for accurate line counts
   - Trade-off: significantly slower (per-file blame vs single log command)

2. **Configurable commit limit**: Allow users to adjust via CLI flag
   - Small repos: `--commits 1000`
   - Large repos: `--commits 10000` or `--all`

3. **Incremental updates**: Only process new commits since last build
   - Track last processed commit SHA
   - Use `git log <last_sha>..HEAD`

4. **Author name resolution**: Handle email changes and author name variations
   - Map multiple emails to same person
   - Use `.mailmap` for canonical names

## LOC Delta

**Lines Added**: ~140 lines
- `add_modified_relationship_sync`: 30 lines
- `_extract_authorship_sync` expansion: 60 lines
- `_extract_authorship_fast` expansion: 50 lines

**Lines Removed**: ~80 lines
- Old single-author logic: 80 lines

**Net Change**: +60 lines (functionality increase justified by feature completion)

## Conclusion

The KG now properly tracks:
- ✅ Person nodes (unique contributors)
- ✅ AUTHORED relationships (original file authors)
- ✅ MODIFIED relationships (subsequent contributors)

This enables queries like:
- "Who authored this file?"
- "Who has modified this component?"
- "What files has this person worked on?"
- "Show contributors to this module"

The fix ensures complete authorship attribution across the codebase.
