fix: resolve excludeVFS architectural bug across all query paths (v5.7.13)

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)
This commit is contained in:
David Snelling 2025-11-13 17:09:37 -08:00
parent 3296c75edf
commit e57e947498

View file

@ -1352,42 +1352,6 @@ export class Brainy<T = any> implements BrainyInterface<T> {
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<T = any> implements BrainyInterface<T> {
}
}
// 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<T = any> implements BrainyInterface<T> {
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<T = any> implements BrainyInterface<T> {
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) {