@soulcraft/brainy 3.37.6 → 3.37.7
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.
|
@@ -146,6 +146,12 @@ export class GcsStorage extends BaseStorage {
|
|
|
146
146
|
});
|
|
147
147
|
// Initialize counts from storage
|
|
148
148
|
await this.initializeCounts();
|
|
149
|
+
// CRITICAL FIX (v3.37.7): Clear any stale cache entries from previous runs
|
|
150
|
+
// This prevents cache poisoning from causing silent failures on container restart
|
|
151
|
+
prodLog.info('🧹 Clearing cache from previous run to prevent cache poisoning');
|
|
152
|
+
this.nounCacheManager.clear();
|
|
153
|
+
this.verbCacheManager.clear();
|
|
154
|
+
prodLog.info('✅ Cache cleared - starting fresh');
|
|
149
155
|
this.isInitialized = true;
|
|
150
156
|
}
|
|
151
157
|
catch (error) {
|
|
@@ -380,12 +386,27 @@ export class GcsStorage extends BaseStorage {
|
|
|
380
386
|
*/
|
|
381
387
|
async getNode(id) {
|
|
382
388
|
await this.ensureInitialized();
|
|
383
|
-
// Check cache first
|
|
389
|
+
// Check cache first WITH LOGGING
|
|
384
390
|
const cached = this.nounCacheManager.get(id);
|
|
385
|
-
|
|
391
|
+
// DIAGNOSTIC LOGGING: Reveal cache poisoning
|
|
392
|
+
prodLog.info(`[getNode] 🔍 Cache check for ${id.substring(0, 8)}...:`, {
|
|
393
|
+
hasCached: cached !== undefined,
|
|
394
|
+
isNull: cached === null,
|
|
395
|
+
isObject: cached !== null && typeof cached === 'object',
|
|
396
|
+
type: typeof cached
|
|
397
|
+
});
|
|
398
|
+
// CRITICAL FIX: Only return cached value if it's valid (not null/undefined)
|
|
399
|
+
if (cached !== undefined && cached !== null) {
|
|
400
|
+
prodLog.info(`[getNode] ✅ Cache HIT - returning cached node for ${id.substring(0, 8)}...`);
|
|
386
401
|
this.logger.trace(`Cache hit for noun ${id}`);
|
|
387
402
|
return cached;
|
|
388
403
|
}
|
|
404
|
+
else if (cached === null) {
|
|
405
|
+
prodLog.warn(`[getNode] ⚠️ Cache contains NULL for ${id.substring(0, 8)}... - ignoring and loading from GCS`);
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
prodLog.info(`[getNode] ❌ Cache MISS - loading from GCS for ${id.substring(0, 8)}...`);
|
|
409
|
+
}
|
|
389
410
|
// Apply backpressure
|
|
390
411
|
const requestId = await this.applyBackpressure();
|
|
391
412
|
try {
|
|
@@ -420,8 +441,14 @@ export class GcsStorage extends BaseStorage {
|
|
|
420
441
|
level: data.level || 0
|
|
421
442
|
// NO metadata field - retrieved separately for scalability
|
|
422
443
|
};
|
|
423
|
-
//
|
|
424
|
-
|
|
444
|
+
// CRITICAL FIX: Only cache valid nodes (never cache null)
|
|
445
|
+
if (node && node.id && node.vector && Array.isArray(node.vector)) {
|
|
446
|
+
this.nounCacheManager.set(id, node);
|
|
447
|
+
prodLog.info(`[getNode] 💾 Cached node ${id.substring(0, 8)}... successfully`);
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
prodLog.warn(`[getNode] ⚠️ NOT caching invalid node for ${id.substring(0, 8)}...`);
|
|
451
|
+
}
|
|
425
452
|
this.logger.trace(`Successfully retrieved node ${id}`);
|
|
426
453
|
this.releaseBackpressure(true, requestId);
|
|
427
454
|
return node;
|
|
@@ -440,7 +467,8 @@ export class GcsStorage extends BaseStorage {
|
|
|
440
467
|
prodLog.error(`[getNode] Error object:`, JSON.stringify(error, null, 2));
|
|
441
468
|
// Check if this is a "not found" error
|
|
442
469
|
if (error.code === 404) {
|
|
443
|
-
prodLog.warn(`[getNode] Identified as 404 error - returning null`);
|
|
470
|
+
prodLog.warn(`[getNode] Identified as 404 error - returning null WITHOUT caching`);
|
|
471
|
+
// CRITICAL FIX: Do NOT cache null values
|
|
444
472
|
return null;
|
|
445
473
|
}
|
|
446
474
|
// Handle throttling
|
|
@@ -237,6 +237,16 @@ export class S3CompatibleStorage extends BaseStorage {
|
|
|
237
237
|
await this.cleanupLegacyIndexFolder();
|
|
238
238
|
// Initialize counts from storage
|
|
239
239
|
await this.initializeCounts();
|
|
240
|
+
// CRITICAL FIX (v3.37.7): Clear any stale cache entries from previous runs
|
|
241
|
+
// This prevents cache poisoning from causing silent failures on container restart
|
|
242
|
+
const nodeCacheSize = this.nodeCache?.size || 0;
|
|
243
|
+
if (nodeCacheSize > 0) {
|
|
244
|
+
prodLog.info(`🧹 Clearing ${nodeCacheSize} cached node entries from previous run`);
|
|
245
|
+
this.nodeCache.clear();
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
prodLog.info('🧹 Node cache is empty - starting fresh');
|
|
249
|
+
}
|
|
240
250
|
this.isInitialized = true;
|
|
241
251
|
this.logger.info(`Initialized ${this.serviceType} storage with bucket ${this.bucketName}`);
|
|
242
252
|
}
|
|
@@ -808,6 +818,27 @@ export class S3CompatibleStorage extends BaseStorage {
|
|
|
808
818
|
*/
|
|
809
819
|
async getNode(id) {
|
|
810
820
|
await this.ensureInitialized();
|
|
821
|
+
// Check cache first WITH LOGGING
|
|
822
|
+
const cached = this.nodeCache.get(id);
|
|
823
|
+
// DIAGNOSTIC LOGGING: Reveal cache poisoning
|
|
824
|
+
prodLog.info(`[getNode] 🔍 Cache check for ${id.substring(0, 8)}...:`, {
|
|
825
|
+
hasCached: cached !== undefined,
|
|
826
|
+
isNull: cached === null,
|
|
827
|
+
isObject: cached !== null && typeof cached === 'object',
|
|
828
|
+
type: typeof cached
|
|
829
|
+
});
|
|
830
|
+
// CRITICAL FIX: Only return cached value if it's valid (not null/undefined)
|
|
831
|
+
if (cached !== undefined && cached !== null) {
|
|
832
|
+
prodLog.info(`[getNode] ✅ Cache HIT - returning cached node for ${id.substring(0, 8)}...`);
|
|
833
|
+
this.logger.trace(`Cache hit for node ${id}`);
|
|
834
|
+
return cached;
|
|
835
|
+
}
|
|
836
|
+
else if (cached === null) {
|
|
837
|
+
prodLog.warn(`[getNode] ⚠️ Cache contains NULL for ${id.substring(0, 8)}... - ignoring and loading from S3`);
|
|
838
|
+
}
|
|
839
|
+
else {
|
|
840
|
+
prodLog.info(`[getNode] ❌ Cache MISS - loading from S3 for ${id.substring(0, 8)}...`);
|
|
841
|
+
}
|
|
811
842
|
try {
|
|
812
843
|
// Import the GetObjectCommand only when needed
|
|
813
844
|
const { GetObjectCommand } = await import('@aws-sdk/client-s3');
|
|
@@ -858,6 +889,14 @@ export class S3CompatibleStorage extends BaseStorage {
|
|
|
858
889
|
connections,
|
|
859
890
|
level: parsedNode.level || 0
|
|
860
891
|
};
|
|
892
|
+
// CRITICAL FIX: Only cache valid nodes (never cache null)
|
|
893
|
+
if (node && node.id && node.vector && Array.isArray(node.vector)) {
|
|
894
|
+
this.nodeCache.set(id, node);
|
|
895
|
+
prodLog.info(`[getNode] 💾 Cached node ${id.substring(0, 8)}... successfully`);
|
|
896
|
+
}
|
|
897
|
+
else {
|
|
898
|
+
prodLog.warn(`[getNode] ⚠️ NOT caching invalid node for ${id.substring(0, 8)}...`);
|
|
899
|
+
}
|
|
861
900
|
this.logger.trace(`Successfully retrieved node ${id}`);
|
|
862
901
|
return node;
|
|
863
902
|
}
|
|
@@ -876,7 +915,8 @@ export class S3CompatibleStorage extends BaseStorage {
|
|
|
876
915
|
prodLog.error(`[getNode] Error object:`, JSON.stringify(error, null, 2));
|
|
877
916
|
// Check if this is a "not found" error (S3 uses "NoSuchKey")
|
|
878
917
|
if (error?.name === 'NoSuchKey' || error?.Code === 'NoSuchKey' || error?.$metadata?.httpStatusCode === 404) {
|
|
879
|
-
prodLog.warn(`[getNode] Identified as 404/NoSuchKey error - returning null`);
|
|
918
|
+
prodLog.warn(`[getNode] Identified as 404/NoSuchKey error - returning null WITHOUT caching`);
|
|
919
|
+
// CRITICAL FIX: Do NOT cache null values
|
|
880
920
|
return null;
|
|
881
921
|
}
|
|
882
922
|
// Handle throttling
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soulcraft/brainy",
|
|
3
|
-
"version": "3.37.
|
|
3
|
+
"version": "3.37.7",
|
|
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",
|