brainy/src/storage
David Snelling c15892ef04 fix(architecture): singleton GraphAdjacencyIndex via storage.getGraphIndex() (v6.3.0)
BREAKING: This is a critical architectural fix for the VFS tree corruption bug
reported by Soulcraft Workshop team. The fix addresses the root cause: dual
ownership of GraphAdjacencyIndex causing verbIdSet to be out of sync.

## Root Cause Analysis

The bug was caused by TWO separate GraphAdjacencyIndex instances:
1. Storage.graphIndex (created in BaseStorage.init())
2. Brainy.graphIndex (created in Brainy.init())

When verbs were saved, both instances were updated. But if Storage's graphIndex
was recreated (via ensureInitialized()), the new instance had an empty verbIdSet.
Queries filtered through this empty verbIdSet returned nothing - making data
appear lost even though it existed in the LSM-trees.

## Fix Summary

1. **GraphAdjacencyIndex Singleton Pattern**
   - Removed direct creation from BaseStorage.init()
   - Brainy now uses `storage.getGraphIndex()` instead of creating its own
   - getGraphIndex() has proper singleton pattern with concurrent access protection
   - Added `invalidateGraphIndex()` for branch switches

2. **Auto-rebuild verbIdSet Defense**
   - Added check in ensureInitialized(): if LSM-trees have data but verbIdSet
     is empty, automatically populate verbIdSet from storage
   - This is a safety net for edge cases

3. **Removed Double-Add Bug**
   - Removed graphIndex.addVerb() from saveVerb_internal()
   - Graph index updates now happen ONLY via AddToGraphIndexOperation in
     Brainy.relate() transaction system
   - This prevents duplicate counting in relationshipCountsByType

4. **PathResolver Cache Invalidation**
   - Added invalidateAllCaches() method to PathResolver and SemanticPathResolver
   - checkout() now clears VFS caches before recreating VFS for new branch

## Files Changed

- src/storage/baseStorage.ts: Removed graphIndex creation from init(), added
  invalidateGraphIndex(), removed addVerb from saveVerb_internal()
- src/brainy.ts: Use storage.getGraphIndex() in init/fork/checkout
- src/graph/graphAdjacencyIndex.ts: Auto-rebuild verbIdSet in ensureInitialized()
- src/vfs/PathResolver.ts: Added invalidateAllCaches()
- src/vfs/semantic/SemanticPathResolver.ts: Added invalidateAllCaches()

## Testing

All VFS tests pass (7/7), including:
- mkdir() should not corrupt VFS index
- Delete and recreate folder cycles
- Contains relationship queries

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 12:55:23 -08:00
..
adapters perf(storage): simplify cloud adapters to always-on write buffering 2025-12-02 13:43:04 -08:00
cow perf: eliminate N+1 patterns across all APIs for 10-20x faster cloud storage 2025-11-20 15:18:26 -08:00
backwardCompatibility.ts fix(storage): clean directory architecture - FileSystemStorage uses entities/nouns/hnsw and entities/verbs/hnsw 2025-10-27 12:23:00 -07:00
baseStorage.ts fix(architecture): singleton GraphAdjacencyIndex via storage.getGraphIndex() (v6.3.0) 2025-12-04 12:55:23 -08:00
cacheManager.ts feat: add node: protocol to all Node.js built-in imports for bundler compatibility 2025-09-17 14:20:21 -07:00
enhancedCacheManager.ts 🧠 Brainy 2.0.0 - Zero-Configuration AI Database with Triple Intelligence™ 2025-08-26 12:32:21 -07:00
enhancedClearOperations.ts feat: add node: protocol to all Node.js built-in imports for bundler compatibility 2025-09-17 14:20:21 -07:00
readOnlyOptimizations.ts feat: add distributed architecture with sharding and coordination 2025-09-22 15:45:35 -07:00
sharding.ts fix: implement unified UUID-based sharding for metadata across all storage adapters 2025-10-08 13:26:35 -07:00
storageFactory.ts fix: resolve HNSW race condition and verb weight extraction (v5.4.0) 2025-11-05 17:05:07 -08:00