diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bceb5f4..abf599d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,38 @@ 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. +## [5.6.1](https://github.com/soulcraftlabs/brainy/compare/v5.6.0...v5.6.1) (2025-11-11) + +### ๐Ÿ› Bug Fixes + +* **storage**: Fix `clear()` not deleting COW version control data ([#workshop-bug-report](https://github.com/soulcraftlabs/brainy/issues)) + - Fixed all storage adapters to properly delete `_cow/` directory on clear() + - Fixed in-memory entity counters not being reset after clear() + - Prevents COW reinitialization after clear() by setting `cowEnabled = false` + - **Impact**: Resolves storage persistence bug (103MB โ†’ 0 bytes after clear) + - **Affected adapters**: FileSystemStorage, OPFSStorage, S3CompatibleStorage (GCSStorage, R2Storage, AzureBlobStorage already correct) + +### ๐Ÿ“ Technical Details + +* **Root causes identified**: + 1. `_cow/` directory contents deleted but directory not removed + 2. In-memory counters (`totalNounCount`, `totalVerbCount`) not reset + 3. COW could auto-reinitialize on next operation +* **Fixes applied**: + - FileSystemStorage: Use `fs.rm()` to delete entire `_cow/` directory + - OPFSStorage: Use `removeEntry('_cow', {recursive: true})` + - Cloud adapters: Already use `deleteObjectsWithPrefix('_cow/')` + - All adapters: Reset `totalNounCount = 0` and `totalVerbCount = 0` + - BaseStorage: Added guard in `initializeCOW()` to prevent reinitialization when `cowEnabled === false` + +## [5.6.0](https://github.com/soulcraftlabs/brainy/compare/v5.5.0...v5.6.0) (2025-11-11) + +### ๐Ÿ› Bug Fixes + +* **relations**: Fix `getRelations()` returning empty array for fresh instances + - Resolved initialization race condition in relationship loading + - Fresh Brain instances now correctly load persisted relationships + ## [5.5.0](https://github.com/soulcraftlabs/brainy/compare/v5.4.0...v5.5.0) (2025-11-06) ### ๐ŸŽฏ Stage 3 CANONICAL Taxonomy - Complete Coverage diff --git a/src/storage/adapters/azureBlobStorage.ts b/src/storage/adapters/azureBlobStorage.ts index a52d2302..06a73a60 100644 --- a/src/storage/adapters/azureBlobStorage.ts +++ b/src/storage/adapters/azureBlobStorage.ts @@ -1136,6 +1136,8 @@ export class AzureBlobStorage extends BaseStorage { this.logger.info('๐Ÿงน Clearing all data from Azure container...') // Delete all blobs in container + // v5.6.1: listBlobsFlat() returns ALL blobs including _cow/ prefix + // This correctly deletes COW version control data (commits, trees, blobs, refs) for await (const blob of this.containerClient!.listBlobsFlat()) { if (blob.name) { const blockBlobClient = this.containerClient!.getBlockBlobClient(blob.name) @@ -1143,6 +1145,14 @@ export class AzureBlobStorage extends BaseStorage { } } + // CRITICAL: Reset COW state to prevent automatic reinitialization + // When COW data is cleared, we must also clear the COW managers + // Otherwise initializeCOW() will auto-recreate initial commit on next operation + this.refManager = undefined + this.blobStorage = undefined + this.commitLog = undefined + this.cowEnabled = false + // Clear caches this.nounCacheManager.clear() this.verbCacheManager.clear() diff --git a/src/storage/adapters/fileSystemStorage.ts b/src/storage/adapters/fileSystemStorage.ts index d764c898..fbc5c61f 100644 --- a/src/storage/adapters/fileSystemStorage.ts +++ b/src/storage/adapters/fileSystemStorage.ts @@ -1021,10 +1021,32 @@ export class FileSystemStorage extends BaseStorage { if (await this.directoryExists(this.indexDir)) { await removeDirectoryContents(this.indexDir) } - + + // v5.6.1: Remove COW (copy-on-write) version control data + // This directory stores all git-like versioning data (commits, trees, blobs, refs) + // Must be deleted to fully clear all data including version history + const cowDir = path.join(this.rootDir, '_cow') + if (await this.directoryExists(cowDir)) { + // Delete the entire _cow/ directory (not just contents) + await fs.promises.rm(cowDir, { recursive: true, force: true }) + + // CRITICAL: Reset COW state to prevent automatic reinitialization + // When COW data is cleared, we must also clear the COW managers + // Otherwise initializeCOW() will auto-recreate initial commit on next operation + this.refManager = undefined + this.blobStorage = undefined + this.commitLog = undefined + this.cowEnabled = false + } + // Clear the statistics cache this.statisticsCache = null this.statisticsModified = false + + // v5.6.1: Reset entity counters (inherited from BaseStorageAdapter) + // These in-memory counters must be reset to 0 after clearing all data + ;(this as any).totalNounCount = 0 + ;(this as any).totalVerbCount = 0 } /** diff --git a/src/storage/adapters/gcsStorage.ts b/src/storage/adapters/gcsStorage.ts index 0390f73f..3179f280 100644 --- a/src/storage/adapters/gcsStorage.ts +++ b/src/storage/adapters/gcsStorage.ts @@ -1002,6 +1002,19 @@ export class GcsStorage extends BaseStorage { await deleteObjectsWithPrefix(this.verbMetadataPrefix) await deleteObjectsWithPrefix(this.systemPrefix) + // v5.6.1: Clear COW (copy-on-write) version control data + // This includes all git-like versioning data (commits, trees, blobs, refs) + // Must be deleted to fully clear all data including version history + await deleteObjectsWithPrefix('_cow/') + + // CRITICAL: Reset COW state to prevent automatic reinitialization + // When COW data is cleared, we must also clear the COW managers + // Otherwise initializeCOW() will auto-recreate initial commit on next operation + this.refManager = undefined + this.blobStorage = undefined + this.commitLog = undefined + this.cowEnabled = false + // Clear caches this.nounCacheManager.clear() this.verbCacheManager.clear() diff --git a/src/storage/adapters/opfsStorage.ts b/src/storage/adapters/opfsStorage.ts index ab99448f..2d054f46 100644 --- a/src/storage/adapters/opfsStorage.ts +++ b/src/storage/adapters/opfsStorage.ts @@ -481,9 +481,35 @@ export class OPFSStorage extends BaseStorage { // Remove all files in the index directory await removeDirectoryContents(this.indexDir!) + // v5.6.1: Remove COW (copy-on-write) version control data + // This directory stores all git-like versioning data (commits, trees, blobs, refs) + // Must be deleted to fully clear all data including version history + try { + // Delete the entire _cow/ directory (not just contents) + await this.rootDir!.removeEntry('_cow', { recursive: true }) + + // CRITICAL: Reset COW state to prevent automatic reinitialization + // When COW data is cleared, we must also clear the COW managers + // Otherwise initializeCOW() will auto-recreate initial commit on next operation + this.refManager = undefined + this.blobStorage = undefined + this.commitLog = undefined + this.cowEnabled = false + } catch (error: any) { + // Ignore if _cow directory doesn't exist (not all instances use COW) + if (error.name !== 'NotFoundError') { + throw error + } + } + // Clear the statistics cache this.statisticsCache = null this.statisticsModified = false + + // v5.6.1: Reset entity counters (inherited from BaseStorageAdapter) + // These in-memory counters must be reset to 0 after clearing all data + ;(this as any).totalNounCount = 0 + ;(this as any).totalVerbCount = 0 } catch (error) { console.error('Error clearing storage:', error) throw error diff --git a/src/storage/adapters/r2Storage.ts b/src/storage/adapters/r2Storage.ts index bda247bc..572fcbf7 100644 --- a/src/storage/adapters/r2Storage.ts +++ b/src/storage/adapters/r2Storage.ts @@ -1032,8 +1032,10 @@ export class R2Storage extends BaseStorage { prodLog.info('๐Ÿงน R2: Clearing all data from bucket...') - // Clear all prefixes - for (const prefix of [this.nounPrefix, this.verbPrefix, this.metadataPrefix, this.verbMetadataPrefix, this.systemPrefix]) { + // Clear all prefixes (v5.6.1: includes _cow/ for version control data) + // _cow/ stores all git-like versioning data (commits, trees, blobs, refs) + // Must be deleted to fully clear all data including version history + for (const prefix of [this.nounPrefix, this.verbPrefix, this.metadataPrefix, this.verbMetadataPrefix, this.systemPrefix, '_cow/']) { const objects = await this.listObjectsUnderPath(prefix) for (const key of objects) { @@ -1041,6 +1043,14 @@ export class R2Storage extends BaseStorage { } } + // CRITICAL: Reset COW state to prevent automatic reinitialization + // When COW data is cleared, we must also clear the COW managers + // Otherwise initializeCOW() will auto-recreate initial commit on next operation + this.refManager = undefined + this.blobStorage = undefined + this.commitLog = undefined + this.cowEnabled = false + this.nounCacheManager.clear() this.verbCacheManager.clear() diff --git a/src/storage/adapters/s3CompatibleStorage.ts b/src/storage/adapters/s3CompatibleStorage.ts index 656bf44f..f1d6f747 100644 --- a/src/storage/adapters/s3CompatibleStorage.ts +++ b/src/storage/adapters/s3CompatibleStorage.ts @@ -2123,10 +2123,28 @@ export class S3CompatibleStorage extends BaseStorage { // Delete all objects in the index directory await deleteObjectsWithPrefix(this.indexPrefix) - + + // v5.6.1: Delete COW (copy-on-write) version control data + // This includes all git-like versioning data (commits, trees, blobs, refs) + // Must be deleted to fully clear all data including version history + await deleteObjectsWithPrefix('_cow/') + + // CRITICAL: Reset COW state to prevent automatic reinitialization + // When COW data is cleared, we must also clear the COW managers + // Otherwise initializeCOW() will auto-recreate initial commit on next operation + this.refManager = undefined + this.blobStorage = undefined + this.commitLog = undefined + this.cowEnabled = false + // Clear the statistics cache this.statisticsCache = null this.statisticsModified = false + + // v5.6.1: Reset entity counters (inherited from BaseStorageAdapter) + // These in-memory counters must be reset to 0 after clearing all data + ;(this as any).totalNounCount = 0 + ;(this as any).totalVerbCount = 0 } catch (error) { prodLog.error('Failed to clear storage:', error) throw new Error(`Failed to clear storage: ${error}`) diff --git a/src/storage/baseStorage.ts b/src/storage/baseStorage.ts index 8d2faf82..24a1021d 100644 --- a/src/storage/baseStorage.ts +++ b/src/storage/baseStorage.ts @@ -289,6 +289,12 @@ export abstract class BaseStorage extends BaseStorageAdapter { branch?: string enableCompression?: boolean }): Promise { + // v5.6.1: If COW was explicitly disabled (e.g., via clear()), don't reinitialize + // This prevents automatic recreation of COW data after clear() operations + if (this.cowEnabled === false) { + return + } + // Check if RefManager already initialized (full COW setup complete) if (this.refManager) { return