brainy/tests/unit
David Snelling ff86e88e53 fix: add mutex locks to FileSystemStorage for HNSW concurrency (CRITICAL)
PRODUCTION BLOCKER: Workshop team reported data corruption at 450+ entities
during bulk imports (1400 files) with 1000+ concurrent operations.

## Root Cause

FileSystemStorage lacked mutex locks for HNSW operations, causing
read-modify-write race conditions at production scale. Memory and OPFS
adapters already had mutex locks (v4.9.2), but FileSystemStorage only
had atomic rename which prevents torn writes but NOT lost updates.

## The Race Condition

Without mutex, concurrent operations on same entity:
1. Thread A reads file (connections: [1,2,3])
2. Thread B reads file (connections: [1,2,3])
3. Thread A adds connection 4, writes [1,2,3,4]
4. Thread B adds connection 5, writes [1,2,3,5] ← Connection 4 LOST

Result: Corrupted HNSW graph, lost connections, undefined entity IDs

## Why Previous Fixes Failed

v4.9.2: Added atomic rename (prevents torn writes, NOT lost updates)
v4.10.0: Made problem worse by increasing concurrency without mutex

## The Fix

Added mutex locks to FileSystemStorage matching Memory/OPFS (v4.9.2):
- fileSystemStorage.ts:90 - Added hnswLocks Map
- fileSystemStorage.ts:2609-2626 - Mutex wraps saveHNSWData()
- fileSystemStorage.ts:2719-2731 - Mutex wraps saveHNSWSystem()

Mutex serializes concurrent operations PER ENTITY while maintaining
atomic rename for crash safety.

## Workshop Bug Symptoms (Now Fixed)

1. Entity IDs undefined (300+ errors) - Fixed by preventing data loss
2. JSON truncation at 8KB (position 8192) - Fixed by serializing writes
3. Field index lock contention (100+ indexes) - Fixed by preventing corruption cascade
4. Corruption starts at ~450 entities - Fixed by handling hub node contention

## Test Coverage

Added 3 production-scale tests (hnswConcurrency.test.ts:533-688):
- 1000 concurrent saveHNSWData() on shared hub node (Workshop scenario)
- 500 entity corruption threshold test (crosses 450-entity limit)
- 100 concurrent system updates (entry point changes)

Test results: 16/16 passing
- 1000 concurrent ops: 177ms, 0 errors
- 500 entities: 0 undefined IDs, 0 corrupted data, 0 truncation
- All production-scale scenarios pass

## Evidence

Workshop bug report: brain-cloud/apps/workshop/BRAINY_V4.9.2_HNSW_CONCURRENCY_BUG_REPORT.md
Test Gap: Previous tests used 20 concurrent ops vs 1000 in production (50× difference)
Fix Pattern: Matches memoryStorage.ts:828 and opfsStorage.ts:2033 mutex implementation

## Breaking Changes

None - fully backward compatible

## Migration

No migration needed. Existing data compatible. For corrupted v4.9.2 data,
recommend clean slate re-import for guaranteed consistency.
2025-10-29 16:48:07 -07:00
..
augmentations feat: add distributed architecture with sharding and coordination 2025-09-22 15:45:35 -07:00
brainy fix: resolve import hang and index rebuild data loss bugs 2025-10-14 13:06:32 -07:00
import feat: implement progressive flush intervals for streaming imports 2025-10-22 17:36:27 -07:00
neural fix: v4.8.1 critical bug fixes for update() and clustering 2025-10-27 17:01:37 -07:00
storage fix: add mutex locks to FileSystemStorage for HNSW concurrency (CRITICAL) 2025-10-29 16:48:07 -07:00
types feat(types): Phase 0 - Type System Foundation for billion-scale optimization 2025-10-15 12:26:25 -07:00
utils feat(metadata): Phase 1b - TypeFirstMetadataIndex with fixed-size type tracking 2025-10-15 13:52:21 -07:00
brainy-core.unit.test.ts feat: Brainy 3.0 - Production-ready Triple Intelligence database 2025-09-11 16:23:32 -07:00
create-entities-default.test.ts fix: createEntities defaults to true, enable AI features by default 2025-10-23 16:54:40 -07:00
fieldTypeInference.test.ts feat: production-ready value-based temporal field detection 2025-10-16 13:58:57 -07:00
type-filtering.unit.test.ts fix: createEntities defaults to true, enable AI features by default 2025-10-23 16:54:40 -07:00
type-matching.unit.test.ts test: adjust type-matching tests for real embeddings (v3.33.0) 2025-10-09 18:32:14 -07:00
workshop-vfs-diagnostic.test.ts feat: brain.find() excludes VFS by default (Option 3C) 2025-10-24 11:42:47 -07:00