From e57e9474986097f37e89a8dbfa868005368d645c Mon Sep 17 00:00:00 2001 From: David Snelling Date: Thu, 13 Nov 2025 17:09:37 -0800 Subject: [PATCH] fix: resolve excludeVFS architectural bug across all query paths (v5.7.13) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: v5.7.12 introduced execution order bug in metadata-only query path - Complex allOf structure captured empty filter before type was added - Type filter became orphaned outside allOf array - Empty filter returned [], intersection = 0 results - Result: brain.find({ type: 'person', excludeVFS: true }) returned 0 entities Additionally: v5.7.12 only fixed 1 of 3 query paths, creating inconsistent behavior Fix: Replace complex nested filter with simple consistent approach across ALL paths - Metadata-only queries (lines 1355-1381): Moved excludeVFS AFTER type filter - Empty queries (lines 1418-1424): Added isVFSEntity check for consistency - Vector + metadata (lines 1497-1502): Added isVFSEntity check for consistency Simple filter logic: filter.vfsType = { exists: false } // Exclude VFS files/folders filter.isVFSEntity = { ne: true } // Extra safety check This works because: - VFS infrastructure entities ALWAYS have vfsType: 'file' or 'directory' - Extracted entities (person/concept/etc) do NOT have vfsType (undefined) - No execution order dependencies - No complex nested structures Tested: All 3 query paths verified with comprehensive test - Empty query: ✅ Returns extracted entities, excludes VFS - Metadata-only + type: ✅ Returns 3 people (was returning 0!) - Vector search: ✅ Returns correct filtered results Impact: Workshop team can now use excludeVFS: true with type filters - brain.find({ type: NounType.Person, excludeVFS: true }) now works correctly - Returns extracted people WITHOUT VFS infrastructure files/folders - Includes entities with vfsPath metadata (import tracking) Files changed: src/brainy.ts (3 locations) --- src/brainy.ts | 58 ++++++++++++++++++--------------------------------- 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/src/brainy.ts b/src/brainy.ts index e990a069..fc22d55f 100644 --- a/src/brainy.ts +++ b/src/brainy.ts @@ -1352,42 +1352,6 @@ export class Brainy implements BrainyInterface { if (params.where) Object.assign(filter, params.where) if (params.service) filter.service = params.service - // v5.7.12: excludeVFS helper - ONLY exclude VFS infrastructure entities - // Bug fix: Previously excluded entities with ANY vfsType field - // Now ONLY excludes entities with isVFSEntity: true OR vfsType: 'file'/'directory' - // This allows extracted entities (concepts/people/etc) to be included even if they - // have vfsPath metadata showing where they were imported from - if (params.excludeVFS === true) { - // Build filter: EXCLUDE WHERE (isVFSEntity == true) OR (vfsType IN ['file', 'directory']) - // Implementation: INCLUDE WHERE (isVFSEntity missing/false) AND (vfsType missing/not file or directory) - const existingFilter = { ...filter } - filter = { - allOf: [ - existingFilter, - { - // Only include entities WITHOUT isVFSEntity: true - anyOf: [ - { isVFSEntity: { exists: false } }, - { isVFSEntity: { ne: true } } - ] - }, - { - // Only include entities WITHOUT vfsType: 'file' or 'directory' - // Since VFS files ALWAYS have vfsType set, we check it's missing OR not file/dir - anyOf: [ - { vfsType: { exists: false } }, - { - allOf: [ - { vfsType: { ne: 'file' } }, - { vfsType: { ne: 'directory' } } - ] - } - ] - } - ] - } - } - if (params.type) { const types = Array.isArray(params.type) ? params.type : [params.type] if (types.length === 1) { @@ -1402,6 +1366,20 @@ export class Brainy implements BrainyInterface { } } + // v5.7.13: excludeVFS helper - ONLY exclude VFS infrastructure entities + // Applied AFTER type filter to avoid execution order bugs + // Excludes entities where: + // - vfsType is 'file' or 'directory' (VFS files/folders) + // - isVFSEntity is true (explicitly marked as VFS) + // Includes extracted entities (person/concept/etc) even if they have vfsPath metadata + if (params.excludeVFS === true) { + // VFS infrastructure entities ALWAYS have vfsType set + // Extracted entities do NOT have vfsType (undefined) + filter.vfsType = { exists: false } + // Extra safety: exclude entities explicitly marked as VFS + filter.isVFSEntity = { ne: true } + } + // v4.5.4: Apply sorting if requested, otherwise just filter let filteredIds: string[] if (params.orderBy) { @@ -1437,10 +1415,12 @@ export class Brainy implements BrainyInterface { const limit = params.limit || 20 const offset = params.offset || 0 - // v4.7.0: excludeVFS helper + // v5.7.13: excludeVFS helper - exclude VFS infrastructure entities + // VFS files/folders have vfsType set, extracted entities do NOT let filter: any = {} if (params.excludeVFS === true) { filter.vfsType = { exists: false } + filter.isVFSEntity = { ne: true } } // Use metadata index if we need to filter @@ -1514,9 +1494,11 @@ export class Brainy implements BrainyInterface { if (params.where) Object.assign(filter, params.where) if (params.service) filter.service = params.service - // v4.7.0: excludeVFS helper for cleaner UX + // v5.7.13: excludeVFS helper - exclude VFS infrastructure entities + // VFS files/folders have vfsType set, extracted entities do NOT if (params.excludeVFS === true) { filter.vfsType = { exists: false } + filter.isVFSEntity = { ne: true } } if (params.type) {