@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.
- package/dist/storage/adapters/fileSystemStorage.js +6 -2
- package/dist/storage/adapters/gcsStorage.js +54 -3
- package/dist/storage/adapters/memoryStorage.js +13 -1
- package/dist/storage/adapters/opfsStorage.js +27 -4
- package/dist/storage/adapters/s3CompatibleStorage.js +26 -1
- package/package.json +1 -1
|
@@ -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:
|
|
1358
|
-
totalEdges:
|
|
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
|
-
|
|
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
|
-
|
|
1192
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
1216
|
-
|
|
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
|
|
1221
|
-
|
|
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
|
-
|
|
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
|
+
"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",
|