fix: prevent infinite loop during storage initialization (v6.0.1)

CRITICAL FIX for production blocker in v6.0.0:

Root Cause:
- BaseStorage.init() set isInitialized = true at the END of initialization
- If any code during init called ensureInitialized(), it triggered init() recursively
- This caused infinite loop on fresh workspace initialization

Fix:
- Set isInitialized = true at START of BaseStorage.init()
- Wrap in try/catch to reset flag on error
- Prevents recursive init() calls while maintaining error recovery

Impact:
- Fixes all 8 storage adapters (FileSystem, Memory, S3, R2, GCS, Azure, OPFS, Historical)
- Init now completes in ~1 second on fresh installation (was hanging)
- Workshop team can now use v6.0.0 features without infinite loop
- No new test failures (1178 tests passing)

Files:
- src/storage/baseStorage.ts: Move isInitialized = true to top of init()
- CHANGELOG.md: Document v6.0.1 hotfix

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
David Snelling 2025-11-20 08:38:40 -08:00
parent 42ae5be455
commit 4d300e8ed3
2 changed files with 45 additions and 11 deletions

View file

@ -2,6 +2,31 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [6.0.1](https://github.com/soulcraftlabs/brainy/compare/v6.0.0...v6.0.1) (2025-11-20)
### 🐛 Critical Bug Fixes
**Fixed infinite loop during storage initialization on fresh workspaces (v6.0.1)**
**Symptom:** FileSystemStorage (and all storage adapters) entered infinite loop on fresh installation, printing "📁 New installation: using depth 1 sharding..." message hundreds of thousands of times.
**Root Cause:** In v6.0.0, `BaseStorage.init()` sets `isInitialized = true` at the END of initialization (after creating GraphAdjacencyIndex). If any code path during initialization called `ensureInitialized()`, it would trigger `init()` recursively because the flag was still `false`.
**Fix:** Set `isInitialized = true` at the START of `BaseStorage.init()` (before any initialization work) to prevent recursive calls. Flag is reset to `false` on error to allow retries.
**Impact:**
- ✅ Fixes production blocker reported by Workshop team
- ✅ All 8 storage adapters fixed (FileSystem, Memory, S3, R2, GCS, Azure, OPFS, Historical)
- ✅ Init completes in ~1 second on fresh installation (was hanging indefinitely)
- ✅ No new test failures introduced (1178 tests passing)
**Files Changed:**
- `src/storage/baseStorage.ts:261-287` - Moved `isInitialized = true` to top of init() with try/catch
**Migration:** No code changes required - drop-in replacement for v6.0.0.
---
## [6.0.0](https://github.com/soulcraftlabs/brainy/compare/v5.12.0...v6.0.0) (2025-11-19)
## 🚀 v6.0.0 - ID-First Storage Architecture

View file

@ -259,22 +259,31 @@ export abstract class BaseStorage extends BaseStorageAdapter {
* IMPORTANT: If your adapter overrides init(), call await super.init() first!
*/
public async init(): Promise<void> {
// Load type statistics from storage (if they exist)
await this.loadTypeStatistics()
// v6.0.1: CRITICAL FIX - Set flag FIRST to prevent infinite recursion
// If any code path during initialization calls ensureInitialized(), it would
// trigger init() again. Setting the flag immediately breaks the recursion cycle.
this.isInitialized = true
// v6.0.0: Create GraphAdjacencyIndex (lazy-loaded, no rebuild)
// LSM-trees are initialized on first use via ensureInitialized()
// Index is populated incrementally as verbs are added via addVerb()
try {
prodLog.debug('[BaseStorage] Creating GraphAdjacencyIndex...')
this.graphIndex = new GraphAdjacencyIndex(this)
prodLog.debug(`[BaseStorage] GraphAdjacencyIndex instantiated (lazy-loaded), graphIndex=${!!this.graphIndex}`)
// Load type statistics from storage (if they exist)
await this.loadTypeStatistics()
// v6.0.0: Create GraphAdjacencyIndex (lazy-loaded, no rebuild)
// LSM-trees are initialized on first use via ensureInitialized()
// Index is populated incrementally as verbs are added via addVerb()
try {
prodLog.debug('[BaseStorage] Creating GraphAdjacencyIndex...')
this.graphIndex = new GraphAdjacencyIndex(this)
prodLog.debug(`[BaseStorage] GraphAdjacencyIndex instantiated (lazy-loaded), graphIndex=${!!this.graphIndex}`)
} catch (error) {
prodLog.error('[BaseStorage] Failed to create GraphAdjacencyIndex:', error)
throw error
}
} catch (error) {
prodLog.error('[BaseStorage] Failed to create GraphAdjacencyIndex:', error)
// Reset flag on failure to allow retry
this.isInitialized = false
throw error
}
this.isInitialized = true
}
/**