From f6f2717860a38e696a4188652e34657a0d583e17 Mon Sep 17 00:00:00 2001 From: David Snelling Date: Thu, 13 Nov 2025 10:45:06 -0800 Subject: [PATCH] fix: reconstruct Map from JSON for HNSW connections (v5.7.8 hotfix) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CRITICAL FIX for Workshop team's "noun.connections.entries is not a function" error. **Root Cause:** When HNSW data is loaded from JSON storage via getNounsWithPagination(), the `connections` field (which should be Map>) is deserialized as a plain JavaScript object {}. Subsequent code that expects a Map with .entries() method crashes. **The Fix:** Added defensive deserialization in baseStorage.ts:1156-1168 to reconstruct the Map and Sets from the plain object when loading from storage: ```typescript const connections = new Map>() if (noun.connections && typeof noun.connections === 'object') { for (const [levelStr, ids] of Object.entries(noun.connections)) { if (Array.isArray(ids)) { connections.set(parseInt(levelStr, 10), new Set(ids)) } } } ``` **Impact:** - Fixes HNSW index rebuild failures - Workshop team can now use v5.7.7+ lazy loading without crashes - All existing data formats supported (defensive checks) **Testing:** - Build: ✅ PASS (zero TypeScript errors) - Will run full test suite in CI 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/storage/baseStorage.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/storage/baseStorage.ts b/src/storage/baseStorage.ts index 3557d302..dc0973a5 100644 --- a/src/storage/baseStorage.ts +++ b/src/storage/baseStorage.ts @@ -1153,9 +1153,24 @@ export abstract class BaseStorage extends BaseStorageAdapter { } } + // v5.7.8: Convert connections from plain object to Map (JSON deserialization fix) + // When loaded from JSON, Map becomes plain object - must reconstruct + const connections = new Map>() + if (noun.connections && typeof noun.connections === 'object') { + for (const [levelStr, ids] of Object.entries(noun.connections)) { + if (Array.isArray(ids)) { + connections.set(parseInt(levelStr, 10), new Set(ids)) + } else if (ids && typeof ids === 'object') { + // Handle if it's already an array-like or Set-like object + connections.set(parseInt(levelStr, 10), new Set(Object.values(ids))) + } + } + } + // Combine noun + metadata (v5.4.0: Extract standard fields to top-level) collectedNouns.push({ ...noun, + connections, // Use reconstructed Map instead of plain object type: metadata.noun || type, // Required: Extract type from metadata confidence: metadata.confidence, weight: metadata.weight,