@soulcraft/brainy 5.7.1 β†’ 5.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  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.
4
4
 
5
+ ### [5.7.3](https://github.com/soulcraftlabs/brainy/compare/v5.7.2...v5.7.3) (2025-11-12)
6
+
7
+
8
+ ### πŸ› Bug Fixes
9
+
10
+ * resolve REAL v5.7.x race condition - type cache layer (v5.7.3) ([ee17565](https://github.com/soulcraftlabs/brainy/commit/ee1756565ca01666e2aa3b31a80b62c6aa8046e8))
11
+
12
+ ### [5.7.2](https://github.com/soulcraftlabs/brainy/compare/v5.7.1...v5.7.2) (2025-11-12)
13
+
14
+
15
+ ### πŸ› Bug Fixes
16
+
17
+ * resolve v5.7.x race condition with write-through cache (v5.7.2) ([732d23b](https://github.com/soulcraftlabs/brainy/commit/732d23bd2afb4ac9559a9beb7835e0f623065ff2))
18
+
5
19
  ### [5.7.1](https://github.com/soulcraftlabs/brainy/compare/v5.7.0...v5.7.1) (2025-11-11)
6
20
 
7
21
  - fix: resolve v5.7.0 deadlock by restoring storage layer separation (v5.7.1) (eb9af45)
package/dist/brainy.js CHANGED
@@ -1613,6 +1613,21 @@ export class Brainy {
1613
1613
  lastBatchTime = Date.now();
1614
1614
  }
1615
1615
  }
1616
+ // v5.7.3: Ensure nounTypeCache is populated for all successful entities
1617
+ // This prevents cache misses that trigger expensive 42-type searches
1618
+ // when entities are immediately queried (e.g., during brain.relate())
1619
+ const cacheWarmingNeeded = result.successful.filter(id => !this.storage.nounTypeCache?.has(id));
1620
+ if (cacheWarmingNeeded.length > 0) {
1621
+ // Warm the cache by fetching metadata for entities not in cache
1622
+ await Promise.all(cacheWarmingNeeded.map(async (id) => {
1623
+ try {
1624
+ await this.storage.getNounMetadata(id);
1625
+ }
1626
+ catch (error) {
1627
+ // Ignore errors during cache warming (entity may be invalid)
1628
+ }
1629
+ }));
1630
+ }
1616
1631
  result.duration = Date.now() - startTime;
1617
1632
  return result;
1618
1633
  }
@@ -3079,7 +3094,15 @@ export class Brainy {
3079
3094
  // 3. Flush graph adjacency index (relationship cache)
3080
3095
  // Note: Graph structure is already persisted via storage.saveVerb() calls
3081
3096
  // This just flushes the in-memory cache for performance
3082
- this.graphIndex.flush()
3097
+ this.graphIndex.flush(),
3098
+ // 4. v5.7.3: Clear write-through cache after flush
3099
+ // Cache persists during batch operations for read-after-write consistency
3100
+ // Cleared here after all writes are guaranteed flushed to disk
3101
+ (async () => {
3102
+ if (this.storage && typeof this.storage.writeCache !== 'undefined') {
3103
+ this.storage.writeCache.clear();
3104
+ }
3105
+ })()
3083
3106
  ]);
3084
3107
  const elapsed = Date.now() - startTime;
3085
3108
  console.log(`βœ… All indexes flushed to disk in ${elapsed}ms`);
@@ -643,6 +643,10 @@ export class ImportCoordinator {
643
643
  if (addResult.failed.length > 0) {
644
644
  console.warn(`⚠️ ${addResult.failed.length} entities failed to create`);
645
645
  }
646
+ // v5.7.3: Ensure all writes are flushed before creating relationships
647
+ // Fixes "Source entity not found" error in v5.7.0/v5.7.1/v5.7.2
648
+ // Guarantees entities are fully persisted and queryable before brain.relate() is called
649
+ await this.brain.flush();
646
650
  // Create provenance links in batch
647
651
  if (documentEntityId && options.createProvenanceLinks !== false && entities.length > 0) {
648
652
  const provenanceParams = entities.map((entity, idx) => {
@@ -53,6 +53,7 @@ export declare abstract class BaseStorage extends BaseStorageAdapter {
53
53
  protected graphIndex?: GraphAdjacencyIndex;
54
54
  protected graphIndexPromise?: Promise<GraphAdjacencyIndex>;
55
55
  protected readOnly: boolean;
56
+ private writeCache;
56
57
  refManager?: RefManager;
57
58
  blobStorage?: BlobStorage;
58
59
  commitLog?: CommitLog;
@@ -74,6 +74,13 @@ export class BaseStorage extends BaseStorageAdapter {
74
74
  super(...arguments);
75
75
  this.isInitialized = false;
76
76
  this.readOnly = false;
77
+ // v5.7.2: Write-through cache for read-after-write consistency
78
+ // v5.7.3: Extended lifetime - persists until explicit flush() call
79
+ // Guarantees that immediately after writeObjectToBranch(), readWithInheritance() returns the data
80
+ // Cache key: resolved branchPath (includes branch scope for COW isolation)
81
+ // Cache lifetime: write start β†’ flush() call (provides safety net for batch operations)
82
+ // Memory footprint: Bounded by batch size (typically <1000 items during imports)
83
+ this.writeCache = new Map();
77
84
  this.currentBranch = 'main';
78
85
  this.cowEnabled = false;
79
86
  // Type-first indexing support (v5.4.0)
@@ -353,7 +360,14 @@ export class BaseStorage extends BaseStorageAdapter {
353
360
  */
354
361
  async writeObjectToBranch(path, data, branch) {
355
362
  const branchPath = this.resolveBranchPath(path, branch);
356
- return this.writeObjectToPath(branchPath, data);
363
+ // v5.7.2: Add to write cache BEFORE async write (guarantees read-after-write consistency)
364
+ // v5.7.3: Cache persists until flush() is called (extended lifetime for batch operations)
365
+ // This ensures readWithInheritance() returns data immediately, fixing "Source entity not found" bug
366
+ this.writeCache.set(branchPath, data);
367
+ // Write to storage (async)
368
+ await this.writeObjectToPath(branchPath, data);
369
+ // v5.7.3: Cache is NOT cleared here anymore - persists until flush()
370
+ // This provides a safety net for immediate queries after batch writes
357
371
  }
358
372
  /**
359
373
  * Read object with inheritance from parent branches (COW layer)
@@ -362,12 +376,24 @@ export class BaseStorage extends BaseStorageAdapter {
362
376
  */
363
377
  async readWithInheritance(path, branch) {
364
378
  if (!this.cowEnabled) {
365
- // COW disabled, direct read
379
+ // COW disabled: check write cache, then direct read
380
+ // v5.7.2: Check cache first for read-after-write consistency
381
+ const cachedData = this.writeCache.get(path);
382
+ if (cachedData !== undefined) {
383
+ return cachedData;
384
+ }
366
385
  return this.readObjectFromPath(path);
367
386
  }
368
387
  const targetBranch = branch || this.currentBranch || 'main';
369
- // Try current branch first
370
388
  const branchPath = this.resolveBranchPath(path, targetBranch);
389
+ // v5.7.2: Check write cache FIRST (synchronous, instant)
390
+ // This guarantees read-after-write consistency within the same process
391
+ // Fixes bug: brain.add() β†’ brain.relate() β†’ "Source entity not found"
392
+ const cachedData = this.writeCache.get(branchPath);
393
+ if (cachedData !== undefined) {
394
+ return cachedData;
395
+ }
396
+ // Try current branch first
371
397
  let data = await this.readObjectFromPath(branchPath);
372
398
  if (data !== null) {
373
399
  return data; // Found in current branch
@@ -411,6 +437,9 @@ export class BaseStorage extends BaseStorageAdapter {
411
437
  */
412
438
  async deleteObjectFromBranch(path, branch) {
413
439
  const branchPath = this.resolveBranchPath(path, branch);
440
+ // v5.7.2: Remove from write cache immediately (before async delete)
441
+ // Ensures subsequent reads don't return stale cached data
442
+ this.writeCache.delete(branchPath);
414
443
  return this.deleteObjectFromPath(branchPath);
415
444
  }
416
445
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soulcraft/brainy",
3
- "version": "5.7.1",
3
+ "version": "5.7.3",
4
4
  "description": "Universal Knowledge Protocolβ„’ - World's first Triple Intelligence database unifying vector, graph, and document search in one API. Stage 3 CANONICAL: 42 nouns Γ— 127 verbs covering 96-97% of all human knowledge.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",