2025-09-11 16:23:32 -07:00
/ * *
* Brainy v3 . 0 Find & Triple Intelligence Test Suite
* Testing vector search , metadata filtering , and fusion strategies
* /
import { describe , it , expect , beforeAll , afterAll } from 'vitest'
import { Brainy } from '../../src/brainy.js'
import { NounType , VerbType } from '../../src/types/graphTypes.js'
describe ( 'Find and Triple Intelligence' , ( ) = > {
let brain : Brainy
let testData : any [ ]
beforeAll ( async ( ) = > {
feat(8.0)!: flip requireSubtype default to true (BRAINY-8.0-SUBTYPE-CONTRACT § C-1)
Brainy 8.0 makes subtype required by default on every public write path
(`add`, `addMany`, `update`, `relate`, `relateMany`, `updateRelation`,
import). Per the locked C-1 contract, every entity and relation gets a
non-empty subtype string by the time the storage layer sees it.
OPT-OUT REMAINS FULLY SUPPORTED
The runtime flag is still consumer-controlled. Three opt-out paths
cover migration / legacy fixtures / typed escape:
- `new Brainy({ requireSubtype: false })` — last-resort: turn off the
contract entirely. Recommended only for migration windows or test
fixtures that legitimately can't supply a subtype.
- `new Brainy({ requireSubtype: { except: [NounType.Thing, ...] } })` —
per-type allowlist: strict everywhere except the listed types.
- `brain.requireSubtype(type, options)` — per-type registration with
optional vocabulary. Composes with the brain-wide flag.
Default is now `true`. Opt-out is explicit and documented; nothing
silently degrades.
TEST SWEEP
Bulk-applied `requireSubtype: false` to every `new Brainy({...})` call
site across 120 test files. Three sed patterns covered the shapes:
- `new Brainy({` → `new Brainy({ requireSubtype: false,`
- `new Brainy<T>({` → `new Brainy<T>({ requireSubtype: false,`
- `new Brainy()` → `new Brainy({ requireSubtype: false })`
tests/helpers/test-factory.ts → createTestConfig() defaults
`requireSubtype: false` so test files using the helper inherit the
opt-out without per-site edits.
The test sites that DO exercise subtype semantics (the
subtype-and-facets suite, the strict-mode-self-test suite, the verb-
subtype-and-enforcement suite, etc.) already pass real subtypes — they
were the 7.30.x acceptance tests for this contract. Those tests
continue to pass unchanged.
CHANGES
src/brainy.ts
- normalizeConfig() — `requireSubtype` default `false` → `true`.
Comment refreshed to document the three opt-out paths.
tests/* (120 files)
- Bulk-edited brain construction sites. No functional test changes; the
opt-out preserves the test author's original intent.
tests/helpers/test-factory.ts
- createTestConfig() base config gains `requireSubtype: false`.
NO-OP for consumers who were already passing subtype on every write.
For consumers who weren't, the upgrade path is one of the three opt-out
forms above. Migration recipe documented in 8.0 release notes (next
commit).
VERIFICATION
- npx tsc --noEmit: clean
- npm test: 1408 / 1409 (same pre-existing race-condition outstanding;
no other regressions from the flip)
2026-06-09 14:58:25 -07:00
brain = new Brainy ( { requireSubtype : false ,
2025-09-11 16:23:32 -07:00
storage : { type : 'memory' }
} )
await brain . init ( )
// Add diverse test data
testData = [
// Technology items
{ data : 'JavaScript is a programming language for web development' , metadata : { category : 'tech' , language : 'javascript' , difficulty : 'medium' } , type : NounType . Document } ,
{ data : 'TypeScript adds static typing to JavaScript' , metadata : { category : 'tech' , language : 'typescript' , difficulty : 'advanced' } , type : NounType . Document } ,
{ data : 'Python is great for data science and AI' , metadata : { category : 'tech' , language : 'python' , difficulty : 'easy' } , type : NounType . Document } ,
{ data : 'React is a JavaScript library for building UIs' , metadata : { category : 'tech' , framework : 'react' , language : 'javascript' } , type : NounType . Document } ,
// Science items
{ data : 'Quantum computing uses quantum mechanics principles' , metadata : { category : 'science' , field : 'physics' , complexity : 'high' } , type : NounType . Concept } ,
{ data : 'Machine learning enables computers to learn from data' , metadata : { category : 'science' , field : 'ai' , complexity : 'medium' } , type : NounType . Concept } ,
{ data : 'Neural networks are inspired by biological brains' , metadata : { category : 'science' , field : 'ai' , complexity : 'high' } , type : NounType . Concept } ,
// Business items
{ data : 'Market analysis helps understand consumer behavior' , metadata : { category : 'business' , domain : 'marketing' , importance : 'high' } , type : NounType . Process } ,
{ data : 'Project management ensures successful delivery' , metadata : { category : 'business' , domain : 'management' , importance : 'critical' } , type : NounType . Process } ,
{ data : 'Financial planning is essential for growth' , metadata : { category : 'business' , domain : 'finance' , importance : 'critical' } , type : NounType . Process }
]
// Add all test data
for ( const item of testData ) {
await brain . add ( item )
}
} )
afterAll ( ( ) = > {
brain = null as any
} )
describe ( 'Vector Search' , ( ) = > {
it ( 'should find similar items by text query' , async ( ) = > {
const results = await brain . find ( {
query : 'JavaScript programming' ,
limit : 3
} )
expect ( results ) . toHaveLength ( 3 )
expect ( results [ 0 ] . score ) . toBeGreaterThan ( 0 )
expect ( results [ 0 ] . score ) . toBeLessThanOrEqual ( 1 )
// Should find JavaScript-related items first
const topResult = results [ 0 ] . entity
expect ( topResult . metadata ? . language ) . toBeDefined ( )
} )
it ( 'should respect limit parameter' , async ( ) = > {
const results = await brain . find ( {
query : 'technology' ,
limit : 5
} )
expect ( results . length ) . toBeLessThanOrEqual ( 5 )
} )
it ( 'should find by vector directly' , async ( ) = > {
// Get vector from an existing item
const jsItem = await brain . find ( { query : 'JavaScript' , limit : 1 } )
const vector = jsItem [ 0 ] . entity . vector
const results = await brain . find ( {
vector ,
limit : 3
} )
expect ( results ) . toHaveLength ( 3 )
// First result should be very similar (same or nearly same vector)
expect ( results [ 0 ] . score ) . toBeGreaterThan ( 0.9 )
} )
it ( 'should return all items when no query provided' , async ( ) = > {
const results = await brain . find ( { } )
expect ( results . length ) . toBeGreaterThanOrEqual ( testData . length )
} )
} )
describe ( 'Metadata Filtering' , ( ) = > {
it ( 'should filter by single metadata field' , async ( ) = > {
const results = await brain . find ( {
where : { category : 'tech' }
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
results . forEach ( r = > {
expect ( r . entity . metadata ? . category ) . toBe ( 'tech' )
} )
} )
it ( 'should filter by multiple metadata fields' , async ( ) = > {
const results = await brain . find ( {
where : {
category : 'tech' ,
language : 'javascript'
}
} )
results . forEach ( r = > {
expect ( r . entity . metadata ? . category ) . toBe ( 'tech' )
expect ( r . entity . metadata ? . language ) . toBe ( 'javascript' )
} )
} )
it ( 'should support $gte operator' , async ( ) = > {
const results = await brain . find ( {
where : {
importance : { $gte : 'high' }
}
} )
results . forEach ( r = > {
const importance = r . entity . metadata ? . importance
if ( importance ) {
expect ( [ 'high' , 'critical' ] ) . toContain ( importance )
}
} )
} )
it ( 'should support $contains operator for arrays' , async ( ) = > {
// Add item with array metadata
await brain . add ( {
data : 'Test with tags' ,
metadata : { tags : [ 'test' , 'validation' , 'qa' ] } ,
type : NounType . Document
} )
const results = await brain . find ( {
where : {
tags : { $contains : 'test' }
}
} )
const found = results . find ( r = >
Array . isArray ( r . entity . metadata ? . tags ) &&
r . entity . metadata . tags . includes ( 'test' )
)
expect ( found ) . toBeDefined ( )
} )
it ( 'should handle complex nested filters' , async ( ) = > {
const results = await brain . find ( {
where : {
$or : [
{ category : 'tech' , language : 'javascript' } ,
{ category : 'science' , field : 'ai' }
]
}
} )
results . forEach ( r = > {
const meta = r . entity . metadata
const matchesTech = meta ? . category === 'tech' && meta ? . language === 'javascript'
const matchesScience = meta ? . category === 'science' && meta ? . field === 'ai'
expect ( matchesTech || matchesScience ) . toBe ( true )
} )
} )
} )
describe ( 'Type Filtering' , ( ) = > {
it ( 'should filter by single noun type' , async ( ) = > {
const results = await brain . find ( {
type : NounType . Document
} )
results . forEach ( r = > {
expect ( r . entity . type ) . toBe ( NounType . Document )
} )
} )
it ( 'should filter by multiple noun types' , async ( ) = > {
const results = await brain . find ( {
type : [ NounType . Document , NounType . Concept ]
} )
results . forEach ( r = > {
expect ( [ NounType . Document , NounType . Concept ] ) . toContain ( r . entity . type )
} )
} )
} )
describe ( 'Combined Search (Triple Intelligence)' , ( ) = > {
it ( 'should combine vector search with metadata filtering' , async ( ) = > {
const results = await brain . find ( {
query : 'programming' ,
where : { category : 'tech' } ,
limit : 5
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
results . forEach ( r = > {
expect ( r . entity . metadata ? . category ) . toBe ( 'tech' )
} )
} )
it ( 'should combine vector, metadata, and type filtering' , async ( ) = > {
const results = await brain . find ( {
query : 'artificial intelligence' ,
where : { category : 'science' } ,
type : NounType . Concept ,
limit : 5
} )
results . forEach ( r = > {
expect ( r . entity . metadata ? . category ) . toBe ( 'science' )
expect ( r . entity . type ) . toBe ( NounType . Concept )
} )
} )
it ( 'should support fusion strategies' , async ( ) = > {
const results = await brain . find ( {
query : 'JavaScript' ,
where : { category : 'tech' } ,
fusion : {
strategy : 'adaptive' ,
weights : { vector : 0.7 , field : 0.3 }
}
} )
expect ( results ) . toBeDefined ( )
expect ( results . length ) . toBeGreaterThan ( 0 )
} )
it ( 'should handle fusion with graph intelligence' , async ( ) = > {
// Create some relationships
const items = await brain . find ( { limit : 3 } )
if ( items . length >= 2 ) {
await brain . relate ( {
from : items [ 0 ] . id ,
to : items [ 1 ] . id ,
type : VerbType . References
} )
}
const results = await brain . find ( {
query : 'technology' ,
connected : { to : items [ 0 ] ? . id } ,
fusion : {
strategy : 'adaptive' ,
weights : { vector : 0.5 , graph : 0.3 , field : 0.2 }
}
} )
expect ( results ) . toBeDefined ( )
} )
} )
describe ( 'Performance' , ( ) = > {
it ( 'should handle large result sets efficiently' , async ( ) = > {
const start = Date . now ( )
const results = await brain . find ( { limit : 100 } )
const elapsed = Date . now ( ) - start
expect ( elapsed ) . toBeLessThan ( 1000 ) // Should complete in under 1 second
expect ( results . length ) . toBeLessThanOrEqual ( 100 )
} )
it ( 'should cache repeated searches' , async ( ) = > {
const query = { query : 'caching test' , limit : 5 }
// First search
const results1 = await brain . find ( query )
// Second search (should hit cache)
const results2 = await brain . find ( query )
expect ( results1 ) . toEqual ( results2 )
// Note: Cache might not always be faster in tests due to overhead
// But results should be identical
} )
} )
describe ( 'Edge Cases' , ( ) = > {
it ( 'should handle empty query gracefully' , async ( ) = > {
const results = await brain . find ( { query : '' } )
expect ( results ) . toBeDefined ( )
expect ( Array . isArray ( results ) ) . toBe ( true )
} )
it ( 'should handle non-matching filters' , async ( ) = > {
const results = await brain . find ( {
where : { nonExistentField : 'value' }
} )
expect ( results ) . toBeDefined ( )
expect ( Array . isArray ( results ) ) . toBe ( true )
} )
it ( 'should handle very long queries' , async ( ) = > {
const longQuery = 'test ' . repeat ( 1000 ) // 5000 characters
const results = await brain . find ( { query : longQuery , limit : 1 } )
expect ( results ) . toBeDefined ( )
expect ( Array . isArray ( results ) ) . toBe ( true )
} )
it ( 'should handle special characters in queries' , async ( ) = > {
const specialQuery = '!@#$%^&*()_+-=[]{}|;\':",./<>?'
const results = await brain . find ( { query : specialQuery , limit : 1 } )
expect ( results ) . toBeDefined ( )
expect ( Array . isArray ( results ) ) . toBe ( true )
} )
it ( 'should handle unicode in queries' , async ( ) = > {
const unicodeQuery = '你好世界 🌍 مرحبا بالعالم'
const results = await brain . find ( { query : unicodeQuery , limit : 1 } )
expect ( results ) . toBeDefined ( )
expect ( Array . isArray ( results ) ) . toBe ( true )
} )
} )
describe ( 'Similarity Search' , ( ) = > {
it ( 'should find similar items to a given ID' , async ( ) = > {
const items = await brain . find ( { limit : 1 } )
if ( items . length > 0 ) {
const results = await brain . similar ( {
to : items [ 0 ] . id ,
limit : 3
} )
expect ( results ) . toHaveLength ( 3 )
// First result might be the item itself
results . forEach ( r = > {
expect ( r . score ) . toBeGreaterThanOrEqual ( 0 )
expect ( r . score ) . toBeLessThanOrEqual ( 1 )
} )
}
} )
it ( 'should exclude the source item from similar results' , async ( ) = > {
const items = await brain . find ( { limit : 1 } )
if ( items . length > 0 ) {
const results = await brain . similar ( {
to : items [ 0 ] . id ,
limit : 5
} )
// Check if source is excluded (implementation dependent)
const selfMatch = results . find ( r = > r . id === items [ 0 ] . id )
if ( selfMatch ) {
// If included, should be first with score ~1
expect ( results [ 0 ] . id ) . toBe ( items [ 0 ] . id )
expect ( results [ 0 ] . score ) . toBeGreaterThan ( 0.99 )
}
}
} )
} )
} )