From 401443a4b005f1ea847eed87cc7529eb25eab61a Mon Sep 17 00:00:00 2001 From: David Snelling Date: Tue, 28 Oct 2025 14:30:31 -0700 Subject: [PATCH] fix: per-sheet column detection in Excel importer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CRITICAL FIX for Entity_* placeholder names in multi-sheet Excel imports Root Cause: - Column detection ran globally on first row of all combined sheets - Different sheets have different column structures (Term vs Name, etc.) - Concepts sheet: [Term, Definition] → detected 'Term' column ✅ - Characters sheet: [Name, Description] → looked for 'Term' column ❌ - Result: Characters/Places/Other fell back to Entity_* placeholders Fix: - Group rows by sheet (_sheet field) - Detect columns per-sheet, not globally - Each sheet now uses its own column mapping - Characters/Places sheets now correctly find 'Name' column Impact: - Concepts: Still work (no change) - Characters/Places/Other: NOW USE ACTUAL NAMES! 🎉 Also removed debug logging from v4.8.5 (performance overhead) Fixes: Workshop File Explorer showing Entity_* instead of real names Ref: BRAINY_V4.8.4_VFS_UNDEFINED_NAMES_BUG.md --- src/brainy.ts | 15 --------------- src/importers/SmartExcelImporter.ts | 25 +++++++++++++++++++++++-- src/vfs/PathResolver.ts | 13 ------------- src/vfs/VirtualFileSystem.ts | 21 +-------------------- 4 files changed, 24 insertions(+), 50 deletions(-) diff --git a/src/brainy.ts b/src/brainy.ts index 9dc4e25f..f0a9512f 100644 --- a/src/brainy.ts +++ b/src/brainy.ts @@ -573,14 +573,6 @@ export class Brainy implements BrainyInterface { // v4.8.0: Storage adapters ALREADY extract standard fields to top-level! // Just read from top-level fields of HNSWNounWithMetadata - console.log(`[DEBUG convertNounToEntity] Converting noun ${noun.id}:`, { - nounMetadataKeys: noun.metadata ? Object.keys(noun.metadata) : [], - nounType: noun.type, - hasName: !!noun.metadata?.name, - hasPath: !!noun.metadata?.path, - hasVfsType: !!noun.metadata?.vfsType - }) - // v4.8.0: Clean structure with standard fields at top-level const entity: Entity = { id: noun.id, @@ -600,13 +592,6 @@ export class Brainy implements BrainyInterface { metadata: noun.metadata as T } - console.log(`[DEBUG convertNounToEntity] Converted entity metadata:`, { - entityMetadataKeys: entity.metadata ? Object.keys(entity.metadata as any) : [], - metadata_name: (entity.metadata as any)?.name, - metadata_path: (entity.metadata as any)?.path, - metadata_vfsType: (entity.metadata as any)?.vfsType - }) - return entity } diff --git a/src/importers/SmartExcelImporter.ts b/src/importers/SmartExcelImporter.ts index 08f5591d..17107eab 100644 --- a/src/importers/SmartExcelImporter.ts +++ b/src/importers/SmartExcelImporter.ts @@ -227,8 +227,25 @@ export class SmartExcelImporter { return this.emptyResult(startTime) } - // Detect column names - const columns = this.detectColumns(rows[0], opts) + // CRITICAL FIX (v4.8.6): Detect columns per-sheet, not globally + // Different sheets may have different column structures (Term vs Name, etc.) + // Group rows by sheet and detect columns for each sheet separately + const rowsBySheet = new Map() + for (const row of rows) { + const sheet = row._sheet || 'default' + if (!rowsBySheet.has(sheet)) { + rowsBySheet.set(sheet, []) + } + rowsBySheet.get(sheet)!.push(row) + } + + // Detect columns for each sheet + const columnsBySheet = new Map>() + for (const [sheet, sheetRows] of rowsBySheet) { + if (sheetRows.length > 0) { + columnsBySheet.set(sheet, this.detectColumns(sheetRows[0], opts)) + } + } // Process each row with BATCHED PARALLEL PROCESSING (v3.38.0) const extractedRows: ExtractedRow[] = [] @@ -252,6 +269,10 @@ export class SmartExcelImporter { chunk.map(async (row, chunkIndex) => { const i = chunkStart + chunkIndex + // CRITICAL FIX (v4.8.6): Use sheet-specific column mapping + const sheet = row._sheet || 'default' + const columns = columnsBySheet.get(sheet) || this.detectColumns(row, opts) + // Extract data from row const term = this.getColumnValue(row, columns.term) || `Entity_${i}` const definition = this.getColumnValue(row, columns.definition) || '' diff --git a/src/vfs/PathResolver.ts b/src/vfs/PathResolver.ts index 5749610c..c683dbb2 100644 --- a/src/vfs/PathResolver.ts +++ b/src/vfs/PathResolver.ts @@ -230,7 +230,6 @@ export class PathResolver { from: dirId, type: VerbType.Contains }) - console.log(`[DEBUG PathResolver] getChildren(${dirId}): Found ${relations.length} Contains relations`) const validChildren: VFSEntity[]= [] const childNames = new Set() @@ -238,24 +237,12 @@ export class PathResolver { // Fetch all child entities via relationships for (const relation of relations) { const entity = await this.brain.get(relation.to) - console.log(`[DEBUG PathResolver] Retrieved entity ${relation.to}:`, { - exists: !!entity, - type: entity?.type, - hasMetadata: !!entity?.metadata, - metadataKeys: entity?.metadata ? Object.keys(entity.metadata) : [], - metadata_vfsType: entity?.metadata?.vfsType, - metadata_name: entity?.metadata?.name - }) - if (entity && entity.metadata?.vfsType && entity.metadata?.name) { validChildren.push(entity as VFSEntity) childNames.add(entity.metadata.name) - } else { - console.log(`[DEBUG PathResolver] ❌ FILTERED OUT entity ${relation.to} - missing vfsType or name`) } } - console.log(`[DEBUG PathResolver] Returning ${validChildren.length} valid children (filtered from ${relations.length})`) // Update cache this.parentCache.set(dirId, childNames) return validChildren diff --git a/src/vfs/VirtualFileSystem.ts b/src/vfs/VirtualFileSystem.ts index 2479bf5c..ef7e8ff4 100644 --- a/src/vfs/VirtualFileSystem.ts +++ b/src/vfs/VirtualFileSystem.ts @@ -846,20 +846,6 @@ export class VirtualFileSystem implements IVirtualFileSystem { // Get children let children = await this.pathResolver.getChildren(entityId) - console.log(`[DEBUG VFS] readdir(${path}): Found ${children.length} children`) - - // Debug first child - if (children.length > 0) { - const firstChild = children[0] - console.log(`[DEBUG VFS] First child structure:`, { - id: firstChild.id, - type: firstChild.type, - metadataKeys: Object.keys(firstChild.metadata || {}), - metadata_name: firstChild.metadata?.name, - metadata_path: firstChild.metadata?.path, - metadata_vfsType: firstChild.metadata?.vfsType - }) - } // Apply filters if (options?.filter) { @@ -884,17 +870,12 @@ export class VirtualFileSystem implements IVirtualFileSystem { // Return appropriate format if (options?.withFileTypes) { - const result = children.map(child => ({ + return children.map(child => ({ name: child.metadata.name, path: child.metadata.path, type: child.metadata.vfsType, entityId: child.id } as VFSDirent)) - console.log(`[DEBUG VFS] Returning ${result.length} VFSDirent items`) - if (result.length > 0) { - console.log(`[DEBUG VFS] First VFSDirent:`, result[0]) - } - return result } return children.map(child => child.metadata.name)