fix: prevent permalink collision via strict link resolution

Fixes critical data loss bug where creating similar entity names
(e.g., "Node C") would overwrite existing entities (e.g., "Node A.md")
due to fuzzy search incorrectly matching similar file paths.

Changes:
- Add strict=True to resolve_link() calls in entity_service.py
- Disables fuzzy search fallback during entity creation/update
- Prevents false positive matches on similar paths like
  "edge-cases/Node A.md" and "edge-cases/Node C.md"

Testing:
- Added comprehensive integration test reproducing the bug scenario
- Added MCP-level permalink collision tests
- All 55 entity service tests pass
- Manual testing confirms fix prevents file overwrite

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
phernandez
2025-10-04 14:45:37 -05:00
parent f3b1945e4c
commit 2a050edee4
3 changed files with 452 additions and 3 deletions
+4 -3
View File
@@ -146,10 +146,11 @@ class EntityService(BaseService[EntityModel]):
f"Creating or updating entity: {schema.file_path}, permalink: {schema.permalink}"
)
# Try to find existing entity using smart resolution
existing = await self.link_resolver.resolve_link(schema.file_path)
# Try to find existing entity using strict resolution (no fuzzy search)
# This prevents incorrectly matching similar file paths like "Node A.md" and "Node C.md"
existing = await self.link_resolver.resolve_link(schema.file_path, strict=True)
if not existing and schema.permalink:
existing = await self.link_resolver.resolve_link(schema.permalink)
existing = await self.link_resolver.resolve_link(schema.permalink, strict=True)
if existing:
logger.debug(f"Found existing entity: {existing.file_path}")