@soulcraft/brainy 3.37.3 → 3.37.5

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.
@@ -1349,13 +1349,17 @@ export class FileSystemStorage extends BaseStorage {
1349
1349
  mergeStatistics(storageStats, localStats) {
1350
1350
  // Handle null cases
1351
1351
  if (!storageStats && !localStats) {
1352
+ // CRITICAL FIX (v3.37.4): Statistics files don't exist yet (first init)
1353
+ // Return minimal stats with counts instead of zeros
1354
+ // This prevents HNSW from seeing entityCount=0 during index rebuild
1352
1355
  return {
1353
1356
  nounCount: {},
1354
1357
  verbCount: {},
1355
1358
  metadataCount: {},
1356
1359
  hnswIndexSize: 0,
1357
- totalNodes: 0,
1358
- totalEdges: 0,
1360
+ totalNodes: this.totalNounCount,
1361
+ totalEdges: this.totalVerbCount,
1362
+ totalMetadata: 0,
1359
1363
  lastUpdated: new Date().toISOString()
1360
1364
  };
1361
1365
  }
@@ -392,6 +392,8 @@ export class GcsStorage extends BaseStorage {
392
392
  this.logger.trace(`Getting node ${id}`);
393
393
  // Get the GCS key with UUID-based sharding
394
394
  const key = this.getNounKey(id);
395
+ // DIAGNOSTIC LOGGING: Show exact path being accessed
396
+ this.logger.trace(`Computed GCS key: ${key}`);
395
397
  // Download from GCS
396
398
  const file = this.bucket.file(key);
397
399
  const [contents] = await file.download();
@@ -421,7 +423,12 @@ export class GcsStorage extends BaseStorage {
421
423
  this.releaseBackpressure(false, requestId);
422
424
  // Check if this is a "not found" error
423
425
  if (error.code === 404) {
424
- this.logger.trace(`Node not found: ${id}`);
426
+ // DIAGNOSTIC LOGGING: Upgrade 404 errors to WARN level with full details
427
+ const key = this.getNounKey(id);
428
+ prodLog.warn(`[getNode] ❌ 404 NOT FOUND: File does not exist at GCS path: ${key}`);
429
+ prodLog.warn(`[getNode] UUID: ${id}`);
430
+ prodLog.warn(`[getNode] Bucket: ${this.bucketName}`);
431
+ prodLog.warn(`[getNode] This suggests a path mismatch or the file was not written correctly`);
425
432
  return null;
426
433
  }
427
434
  // Handle throttling
@@ -785,6 +792,13 @@ export class GcsStorage extends BaseStorage {
785
792
  await this.ensureInitialized(); // CRITICAL: Must initialize before using this.bucket
786
793
  const limit = options.limit || 100;
787
794
  const useCache = options.useCache !== false;
795
+ // DIAGNOSTIC LOGGING: Track pagination performance
796
+ prodLog.info(`[getNodesWithPagination] Starting pagination: limit=${limit}, cursor=${options.cursor || 'none'}`);
797
+ const startTime = Date.now();
798
+ let shardsChecked = 0;
799
+ let filesFound = 0;
800
+ let nodesLoaded = 0;
801
+ let nodesFailed = 0;
788
802
  try {
789
803
  const nodes = [];
790
804
  // Parse cursor (format: "shardIndex:gcsPageToken")
@@ -799,6 +813,7 @@ export class GcsStorage extends BaseStorage {
799
813
  for (let shardIndex = startShardIndex; shardIndex < TOTAL_SHARDS; shardIndex++) {
800
814
  const shardId = getShardIdByIndex(shardIndex);
801
815
  const shardPrefix = `${this.nounPrefix}${shardId}/`;
816
+ shardsChecked++;
802
817
  // List objects in this shard
803
818
  // Cap maxResults to GCS API limit to prevent "Invalid unsigned integer" errors
804
819
  const requestedPageSize = limit - nodes.length;
@@ -808,6 +823,12 @@ export class GcsStorage extends BaseStorage {
808
823
  maxResults: cappedPageSize,
809
824
  pageToken: shardIndex === startShardIndex ? gcsPageToken : undefined
810
825
  });
826
+ // DIAGNOSTIC LOGGING: Show files found per shard (only log non-empty shards)
827
+ if (files && files.length > 0) {
828
+ filesFound += files.length;
829
+ prodLog.info(`[Shard ${shardId}] Found ${files.length} files in "${shardPrefix}"`);
830
+ prodLog.info(`[Shard ${shardId}] Sample file names: ${files.slice(0, 3).map((f) => f.name).join(', ')}`);
831
+ }
811
832
  // Extract node IDs from file names
812
833
  if (files && files.length > 0) {
813
834
  const nodeIds = files
@@ -824,11 +845,21 @@ export class GcsStorage extends BaseStorage {
824
845
  return name;
825
846
  })
826
847
  .filter((id) => id && id.length > 0);
848
+ // DIAGNOSTIC LOGGING: Show extracted UUIDs
849
+ prodLog.info(`[Shard ${shardId}] Extracted ${nodeIds.length} UUIDs: ${nodeIds.slice(0, 3).join(', ')}...`);
827
850
  // Load nodes
828
851
  for (const id of nodeIds) {
852
+ // DIAGNOSTIC LOGGING: Show each getNode() attempt
853
+ prodLog.info(`[Shard ${shardId}] Calling getNode("${id}")...`);
829
854
  const node = await this.getNode(id);
830
855
  if (node) {
831
856
  nodes.push(node);
857
+ nodesLoaded++;
858
+ prodLog.info(`[Shard ${shardId}] ✅ Successfully loaded node ${id}`);
859
+ }
860
+ else {
861
+ nodesFailed++;
862
+ prodLog.warn(`[Shard ${shardId}] ❌ getNode("${id}") returned null!`);
832
863
  }
833
864
  if (nodes.length >= limit) {
834
865
  break;
@@ -861,6 +892,14 @@ export class GcsStorage extends BaseStorage {
861
892
  // Continue to next shard
862
893
  }
863
894
  // No more shards or nodes
895
+ // DIAGNOSTIC LOGGING: Final summary
896
+ const elapsedTime = Date.now() - startTime;
897
+ prodLog.info(`[getNodesWithPagination] COMPLETED in ${elapsedTime}ms:`);
898
+ prodLog.info(` - Shards checked: ${shardsChecked}/${TOTAL_SHARDS}`);
899
+ prodLog.info(` - Files found: ${filesFound}`);
900
+ prodLog.info(` - Nodes loaded: ${nodesLoaded}`);
901
+ prodLog.info(` - Nodes failed: ${nodesFailed}`);
902
+ prodLog.info(` - Success rate: ${filesFound > 0 ? ((nodesLoaded / filesFound) * 100).toFixed(1) : 'N/A'}%`);
864
903
  return {
865
904
  nodes,
866
905
  totalCount: this.totalNounCount,
@@ -1188,8 +1227,20 @@ export class GcsStorage extends BaseStorage {
1188
1227
  }
1189
1228
  catch (error) {
1190
1229
  if (error.code === 404) {
1191
- this.logger.trace('Statistics not found (creating new)');
1192
- return null;
1230
+ // CRITICAL FIX (v3.37.4): Statistics file doesn't exist yet (first restart)
1231
+ // Return minimal stats with counts instead of null
1232
+ // This prevents HNSW from seeing entityCount=0 during index rebuild
1233
+ this.logger.trace('Statistics file not found - returning minimal stats with counts');
1234
+ return {
1235
+ nounCount: {},
1236
+ verbCount: {},
1237
+ metadataCount: {},
1238
+ hnswIndexSize: 0,
1239
+ totalNodes: this.totalNounCount,
1240
+ totalEdges: this.totalVerbCount,
1241
+ totalMetadata: 0,
1242
+ lastUpdated: new Date().toISOString()
1243
+ };
1193
1244
  }
1194
1245
  this.logger.error('Failed to get statistics:', error);
1195
1246
  return null;
@@ -551,7 +551,19 @@ export class MemoryStorage extends BaseStorage {
551
551
  */
552
552
  async getStatisticsData() {
553
553
  if (!this.statistics) {
554
- return null;
554
+ // CRITICAL FIX (v3.37.4): Statistics don't exist yet (first init)
555
+ // Return minimal stats with counts instead of null
556
+ // This prevents HNSW from seeing entityCount=0 during index rebuild
557
+ return {
558
+ nounCount: {},
559
+ verbCount: {},
560
+ metadataCount: {},
561
+ hnswIndexSize: 0,
562
+ totalNodes: this.totalNounCount,
563
+ totalEdges: this.totalVerbCount,
564
+ totalMetadata: 0,
565
+ lastUpdated: new Date().toISOString()
566
+ };
555
567
  }
556
568
  // Return a deep copy to avoid reference issues
557
569
  return {
@@ -1212,13 +1212,36 @@ export class OPFSStorage extends BaseStorage {
1212
1212
  }
1213
1213
  }
1214
1214
  catch (error) {
1215
- // If the legacy file doesn't exist either, return null
1216
- return null;
1215
+ // CRITICAL FIX (v3.37.4): No statistics files exist (first init)
1216
+ // Return minimal stats with counts instead of null
1217
+ // This prevents HNSW from seeing entityCount=0 during index rebuild
1218
+ return {
1219
+ nounCount: {},
1220
+ verbCount: {},
1221
+ metadataCount: {},
1222
+ hnswIndexSize: 0,
1223
+ totalNodes: this.totalNounCount,
1224
+ totalEdges: this.totalVerbCount,
1225
+ totalMetadata: 0,
1226
+ lastUpdated: new Date().toISOString()
1227
+ };
1217
1228
  }
1218
1229
  }
1219
1230
  }
1220
- // If we get here and statistics is null, return default statistics
1221
- return this.statistics ? this.statistics : null;
1231
+ // If we get here and statistics is null, return minimal stats with counts
1232
+ if (!this.statistics) {
1233
+ return {
1234
+ nounCount: {},
1235
+ verbCount: {},
1236
+ metadataCount: {},
1237
+ hnswIndexSize: 0,
1238
+ totalNodes: this.totalNounCount,
1239
+ totalEdges: this.totalVerbCount,
1240
+ totalMetadata: 0,
1241
+ lastUpdated: new Date().toISOString()
1242
+ };
1243
+ }
1244
+ return this.statistics;
1222
1245
  }
1223
1246
  catch (error) {
1224
1247
  console.error('Failed to get statistics data:', error);
@@ -2198,6 +2198,19 @@ export class S3CompatibleStorage extends BaseStorage {
2198
2198
  totalEdges: this.totalVerbCount
2199
2199
  };
2200
2200
  }
2201
+ // If we get here and statistics is null, return minimal stats with counts
2202
+ if (!statistics) {
2203
+ return {
2204
+ nounCount: {},
2205
+ verbCount: {},
2206
+ metadataCount: {},
2207
+ hnswIndexSize: 0,
2208
+ totalNodes: this.totalNounCount,
2209
+ totalEdges: this.totalVerbCount,
2210
+ totalMetadata: 0,
2211
+ lastUpdated: new Date().toISOString()
2212
+ };
2213
+ }
2201
2214
  // Successfully loaded statistics from storage
2202
2215
  return statistics;
2203
2216
  }
@@ -2212,7 +2225,19 @@ export class S3CompatibleStorage extends BaseStorage {
2212
2225
  totalEdges: this.totalVerbCount
2213
2226
  };
2214
2227
  }
2215
- return null;
2228
+ // CRITICAL FIX (v3.37.4): Statistics file doesn't exist yet (first restart)
2229
+ // Return minimal stats with counts instead of null
2230
+ // This prevents HNSW from seeing entityCount=0 during index rebuild
2231
+ return {
2232
+ nounCount: {},
2233
+ verbCount: {},
2234
+ metadataCount: {},
2235
+ hnswIndexSize: 0,
2236
+ totalNodes: this.totalNounCount,
2237
+ totalEdges: this.totalVerbCount,
2238
+ totalMetadata: 0,
2239
+ lastUpdated: new Date().toISOString()
2240
+ };
2216
2241
  }
2217
2242
  }
2218
2243
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soulcraft/brainy",
3
- "version": "3.37.3",
3
+ "version": "3.37.5",
4
4
  "description": "Universal Knowledge Protocol™ - World's first Triple Intelligence database unifying vector, graph, and document search in one API. 31 nouns × 40 verbs for infinite expressiveness.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",