2025-09-11 16:23:32 -07:00
/ * *
* Comprehensive Integration Tests for Unified Find ( ) Method
* Testing vector + graph + fields search with Triple Intelligence
*
* This test suite validates the complete unified search functionality ,
* including fusion strategies , performance optimization , and edge cases .
* /
import { describe , it , expect , beforeAll , afterAll , beforeEach } from 'vitest'
import { Brainy } from '../../src/brainy'
import { NounType , VerbType } from '../../src/types/graphTypes'
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
// 8.0 id normalization: the test factory seeds natural-key ids ('alice', …).
// The engine maps each to a stable UUID (v5) and preserves the original under
// _originalId, so entity.id is the canonical UUID and lookups round-trip by key.
import { v5 } from '../../src/universal/uuid'
2025-09-11 16:23:32 -07:00
import {
createTestEntity ,
createTestRelation ,
createSocialNetworkTestData ,
createKnowledgeGraphTestData ,
generateTestId ,
generateTestVector ,
measureExecutionTime ,
TestCleanup
} from '../helpers/test-factory'
describe ( 'Unified Find() Integration Tests' , ( ) = > {
let brain : Brainy
let cleanup : TestCleanup
let testEntities : any [ ] = [ ]
let testRelations : any [ ] = [ ]
beforeAll ( async ( ) = > {
// Initialize Brainy with memory storage for fast tests
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' } ,
model : { type : 'fast' } ,
index : {
m : 16 ,
efConstruction : 100 ,
efSearch : 50
}
} )
await brain . init ( )
cleanup = new TestCleanup ( )
} )
afterAll ( async ( ) = > {
await cleanup . cleanup ( )
brain = null as any
} )
beforeEach ( async ( ) = > {
// Clean up any existing test data
await cleanup . cleanup ( )
// Create fresh test data for each test
const socialData = createSocialNetworkTestData ( )
const knowledgeData = createKnowledgeGraphTestData ( )
testEntities = [ . . . socialData . entities , . . . knowledgeData . entities ]
testRelations = [ . . . socialData . relations , . . . knowledgeData . relations ]
// Add entities to Brainy
for ( const entity of testEntities ) {
await brain . add ( {
id : entity.id ,
data : entity.metadata.name || 'Test entity' ,
type : entity . type ,
metadata : entity.metadata ,
service : entity.service
} )
}
// Add relationships
for ( const relation of testRelations ) {
await brain . relate ( {
from : relation . from ,
to : relation.to ,
type : relation . type ,
weight : relation.weight ,
metadata : relation.metadata
} )
}
} )
describe ( '1. Unified Search Scenarios' , ( ) = > {
describe ( 'Vector-only Queries' , ( ) = > {
it ( 'should perform vector search by text query' , async ( ) = > {
const results = await brain . find ( {
query : 'Alice person social network' ,
limit : 5
} )
expect ( results ) . toHaveLength ( 5 )
expect ( results [ 0 ] . score ) . toBeGreaterThan ( 0 )
expect ( results [ 0 ] . score ) . toBeLessThanOrEqual ( 1 )
// Should find Alice-related entities
const aliceResult = results . find ( ( r : any ) = > r . entity . metadata ? . name === 'Alice' )
expect ( aliceResult ) . toBeDefined ( )
} )
it ( 'should perform vector search by direct vector' , async ( ) = > {
2026-06-17 13:11:41 -07:00
// get() is metadata-only by default (vector === []); request the vector explicitly.
const aliceEntity = await brain . get ( 'alice' , { includeVectors : true } )
2025-09-11 16:23:32 -07:00
expect ( aliceEntity ) . toBeDefined ( )
2026-06-17 13:11:41 -07:00
expect ( aliceEntity ! . vector ) . toHaveLength ( 384 )
2025-09-11 16:23:32 -07:00
const results = await brain . find ( {
vector : aliceEntity ! . vector ,
limit : 3
} )
expect ( results ) . toHaveLength ( 3 )
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
// First result should be Alice herself with high similarity (her id is
// the canonical v5 mapping of the natural key 'alice').
expect ( results [ 0 ] . entity . id ) . toBe ( v5 ( 'alice' ) )
2025-09-11 16:23:32 -07:00
expect ( results [ 0 ] . score ) . toBeGreaterThan ( 0.95 )
} )
it ( 'should handle empty vector search results' , async ( ) = > {
const results = await brain . find ( {
vector : generateTestVector ( ) ,
limit : 5
} )
expect ( Array . isArray ( results ) ) . toBe ( true )
expect ( results . length ) . toBeLessThanOrEqual ( 5 )
} )
} )
describe ( 'Graph-only Queries' , ( ) = > {
it ( 'should find connected entities (outbound)' , async ( ) = > {
const results = await brain . find ( {
connected : {
from : 'alice' ,
direction : 'out'
} ,
limit : 10
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
// Should find Bob and Charlie (Alice's friends)
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
const bobResult = results . find ( ( r : any ) = > r . entity . id === v5 ( 'bob' ) )
const charlieResult = results . find ( ( r : any ) = > r . entity . id === v5 ( 'charlie' ) )
2025-09-11 16:23:32 -07:00
expect ( bobResult || charlieResult ) . toBeDefined ( )
} )
it ( 'should find connected entities (inbound)' , async ( ) = > {
const results = await brain . find ( {
connected : {
from : 'bob' ,
direction : 'in'
} ,
limit : 10
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
// Should find Alice (who is friends with Bob)
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
const aliceResult = results . find ( ( r : any ) = > r . entity . id === v5 ( 'alice' ) )
2025-09-11 16:23:32 -07:00
expect ( aliceResult ) . toBeDefined ( )
} )
it ( 'should find connected entities (bidirectional)' , async ( ) = > {
const results = await brain . find ( {
connected : {
from : 'alice' ,
direction : 'both'
} ,
limit : 10
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
// Should find both Bob and Charlie
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
const bobResult = results . find ( ( r : any ) = > r . entity . id === v5 ( 'bob' ) )
const charlieResult = results . find ( ( r : any ) = > r . entity . id === v5 ( 'charlie' ) )
2025-09-11 16:23:32 -07:00
expect ( bobResult ) . toBeDefined ( )
expect ( charlieResult ) . toBeDefined ( )
} )
it ( 'should filter graph results by entity type' , async ( ) = > {
2026-06-17 13:11:41 -07:00
// Filtering traversal RESULTS by NounType is the top-level `type` param composed
// with `connected` (GraphConstraints.type/via filter EDGE VerbTypes, not node types).
2025-09-11 16:23:32 -07:00
const results = await brain . find ( {
2026-06-17 13:11:41 -07:00
type : NounType . Person ,
2025-09-11 16:23:32 -07:00
connected : {
from : 'alice' ,
2026-06-17 13:11:41 -07:00
direction : 'both'
2025-09-11 16:23:32 -07:00
} ,
limit : 10
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
results . forEach ( ( result : any ) = > {
expect ( result . entity . type ) . toBe ( 'person' )
} )
} )
it ( 'should handle multi-depth graph traversal' , async ( ) = > {
const results = await brain . find ( {
connected : {
from : 'alice' ,
direction : 'both' ,
maxDepth : 2
} ,
limit : 10
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
// Should find direct connections (Bob, Charlie) and second-degree (Diana).
// Compare against the canonical v5 ids the engine stored for each key.
const directConnections = [ v5 ( 'bob' ) , v5 ( 'charlie' ) ]
const secondDegreeConnections = [ v5 ( 'diana' ) ]
2025-09-11 16:23:32 -07:00
const hasDirect = results . some ( ( r : any ) = > directConnections . includes ( r . entity . id ) )
const hasSecondDegree = results . some ( ( r : any ) = > secondDegreeConnections . includes ( r . entity . id ) )
expect ( hasDirect || hasSecondDegree ) . toBe ( true )
} )
} )
describe ( 'Field-only Queries' , ( ) = > {
it ( 'should filter by exact metadata match' , async ( ) = > {
const results = await brain . find ( {
where : { name : 'Alice' }
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
results . forEach ( ( result : any ) = > {
expect ( result . entity . metadata ? . name ) . toBe ( 'Alice' )
} )
} )
it ( 'should filter by numeric comparison' , async ( ) = > {
2026-06-17 13:11:41 -07:00
// 8.0 uses BFO operators (gte/lte/gt/lt), not Mongo-style $gte.
2025-09-11 16:23:32 -07:00
const results = await brain . find ( {
2026-06-17 13:11:41 -07:00
where : { age : { gte : 30 } }
2025-09-11 16:23:32 -07:00
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
results . forEach ( ( result : any ) = > {
const age = result . entity . metadata ? . age
if ( age ) {
expect ( age ) . toBeGreaterThanOrEqual ( 30 )
}
} )
} )
it ( 'should filter by array contains' , async ( ) = > {
2026-06-17 13:11:41 -07:00
// Add entity with a multi-element array field.
2025-09-11 16:23:32 -07:00
await brain . add ( {
data : 'Tagged entity' ,
metadata : { tags : [ 'test' , 'integration' , 'qa' ] } ,
type : NounType . Document
} )
2026-06-17 13:11:41 -07:00
// 8.0 uses the BFO `contains` operator for array membership (not Mongo `$contains`).
fix(8.0): multi-valued array fields index every element (contains no longer misses)
addToIndex builds a fieldsMap from the extracted {field,value} entries, but
only __words__ accumulated — every other repeated field did fieldsMap[field]=value,
so a multi-valued field (tags:['a','b','c'] → three 'tags' entries from
extractIndexableFields) collapsed to last-value-wins. columnStore.addEntity
expands an array to one indexed entry per element, but it only ever received the
final scalar, so `contains` matched only the last element and missed the rest.
Accumulate any repeated non-__words__ field into an array before addEntity
(promote scalar→array on the second occurrence). __words__ keeps its always-array
special-case so its multiValue manifest flag stays set even for single-word docs.
find-unified-integration.test.ts → 0 failures (was 4):
- 'array contains' (A.4): now queries first/middle/last element — all match
(previously only the last-indexed element did).
- 'complete find workflow': $contains→contains (8.0 operator) AND fixed the test
premise — find() hard-ANDs vector∩graph∩metadata, and connected:{from:X} returns
X's NEIGHBOURS not X, so the graph anchor must be 'earth' (which the ML concept
relates to), not the concept itself. Multi-signal scores are reciprocal-rank
fusion (~1/61), not [0,1] cosine, so assert a positive fusion score, not >0.5.
- 'nonsense vector query': cosine search always returns nearest neighbours, so
assert the structural array/bound contract, not length===0 (a Tier-2 concern).
- 'hard-ANDs signals': a nonexistent connected.from is an empty graph signal that
zeros the intersection — assert length===0 (documented AND semantics), was >0.
1469 unit + full find-unified integration green.
2026-06-19 11:37:59 -07:00
// A.4 regression guard: query EVERY element — first ('test'), middle
// ('integration'), and last ('qa'). Before the fix only the LAST element
// was indexed (fieldsMap last-value-wins), so 'test'/'integration' missed.
for ( const tag of [ 'test' , 'integration' , 'qa' ] ) {
const results = await brain . find ( {
where : { tags : { contains : tag } }
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
results . forEach ( ( result : any ) = > {
expect ( Array . isArray ( result . entity . metadata ? . tags ) ) . toBe ( true )
expect ( result . entity . metadata . tags ) . toContain ( tag )
} )
}
2025-09-11 16:23:32 -07:00
} )
it ( 'should support complex logical operators' , async ( ) = > {
2026-06-17 13:11:41 -07:00
// 8.0 logical operators are anyOf (OR) / allOf (AND) / not, not Mongo $or/$and.
2025-09-11 16:23:32 -07:00
const results = await brain . find ( {
where : {
2026-06-17 13:11:41 -07:00
anyOf : [
2025-09-11 16:23:32 -07:00
{ name : 'Alice' } ,
{ name : 'Bob' }
]
}
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
const names = results . map ( ( r : any ) = > r . entity . metadata ? . name )
expect ( names ) . toContain ( 'Alice' )
expect ( names ) . toContain ( 'Bob' )
} )
it ( 'should filter by entity type' , async ( ) = > {
const results = await brain . find ( {
type : NounType . Person
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
results . forEach ( ( result : any ) = > {
expect ( result . entity . type ) . toBe ( NounType . Person )
} )
} )
} )
describe ( 'Combined Vector+Graph Queries' , ( ) = > {
it ( 'should combine vector similarity with graph connections' , async ( ) = > {
const results = await brain . find ( {
query : 'social network person' ,
connected : {
from : 'alice' ,
direction : 'both'
} ,
limit : 5
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
// Results should be fusion of vector and graph rankings
results . forEach ( ( result : any ) = > {
expect ( result . score ) . toBeGreaterThan ( 0 )
expect ( result . score ) . toBeLessThanOrEqual ( 1 )
} )
} )
it ( 'should prioritize highly connected entities in vector+graph fusion' , async ( ) = > {
const results = await brain . find ( {
query : 'network connection' ,
connected : {
from : 'charlie' ,
direction : 'both'
} ,
limit : 3
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
// Charlie should be highly ranked due to direct connection
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
const charlieResult = results . find ( ( r : any ) = > r . entity . id === v5 ( 'charlie' ) )
2025-09-11 16:23:32 -07:00
if ( charlieResult ) {
expect ( charlieResult . score ) . toBeGreaterThan ( 0.5 )
}
} )
} )
describe ( 'Combined Vector+Field Queries' , ( ) = > {
it ( 'should combine vector search with metadata filtering' , async ( ) = > {
const results = await brain . find ( {
query : 'person' ,
2026-06-17 13:11:41 -07:00
where : { age : { gte : 25 } } ,
2025-09-11 16:23:32 -07:00
limit : 5
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
results . forEach ( ( result : any ) = > {
expect ( result . entity . metadata ? . age ) . toBeGreaterThanOrEqual ( 25 )
} )
} )
it ( 'should handle conflicting vector and field constraints' , async ( ) = > {
const results = await brain . find ( {
query : 'Alice' ,
where : { name : 'Bob' } , // Different person
limit : 5
} )
// Should return results but with lower confidence due to conflict
expect ( Array . isArray ( results ) ) . toBe ( true )
if ( results . length > 0 ) {
expect ( results [ 0 ] . score ) . toBeLessThan ( 0.9 ) // Lower confidence
}
} )
} )
describe ( 'Combined Graph+Field Queries' , ( ) = > {
it ( 'should combine graph traversal with metadata filtering' , async ( ) = > {
const results = await brain . find ( {
connected : {
from : 'alice' ,
direction : 'both'
} ,
2026-06-17 13:11:41 -07:00
where : { age : { lte : 30 } } ,
2025-09-11 16:23:32 -07:00
limit : 5
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
results . forEach ( ( result : any ) = > {
expect ( result . entity . metadata ? . age ) . toBeLessThanOrEqual ( 30 )
} )
} )
it ( 'should filter graph results by multiple metadata criteria' , async ( ) = > {
const results = await brain . find ( {
connected : {
from : 'charlie' ,
direction : 'both'
} ,
where : {
2026-06-17 13:11:41 -07:00
age : { gte : 25 } ,
name : { notEquals : 'Alice' } // Exclude Alice
2025-09-11 16:23:32 -07:00
} ,
limit : 5
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
results . forEach ( ( result : any ) = > {
expect ( result . entity . metadata ? . age ) . toBeGreaterThanOrEqual ( 25 )
expect ( result . entity . metadata ? . name ) . not . toBe ( 'Alice' )
} )
} )
} )
describe ( 'Full Triple Intelligence (Vector+Graph+Fields)' , ( ) = > {
it ( 'should perform complete triple intelligence search' , async ( ) = > {
const results = await brain . find ( {
query : 'social network person' ,
connected : {
from : 'alice' ,
direction : 'both'
} ,
where : {
2026-06-17 13:11:41 -07:00
age : { gte : 25 } ,
anyOf : [
2025-09-11 16:23:32 -07:00
{ name : 'Bob' } ,
{ name : 'Charlie' }
]
} ,
limit : 5
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
// All results should satisfy all three criteria
results . forEach ( ( result : any ) = > {
expect ( result . entity . metadata ? . age ) . toBeGreaterThanOrEqual ( 25 )
const name = result . entity . metadata ? . name
expect ( [ 'Bob' , 'Charlie' ] ) . toContain ( name )
} )
} )
it ( 'should handle empty results from individual search types' , async ( ) = > {
const results = await brain . find ( {
query : 'nonexistent content' ,
connected : {
from : 'nonexistent' ,
direction : 'both'
} ,
where : { nonexistentField : 'value' } ,
limit : 5
} )
expect ( Array . isArray ( results ) ) . toBe ( true )
// Should handle gracefully without throwing
} )
it ( 'should maintain ranking consistency across search types' , async ( ) = > {
const results1 = await brain . find ( {
query : 'person social' ,
connected : { from : 'alice' } ,
2026-06-17 13:11:41 -07:00
where : { age : { gte : 25 } } ,
2025-09-11 16:23:32 -07:00
limit : 3
} )
const results2 = await brain . find ( {
query : 'person social' ,
connected : { from : 'alice' } ,
2026-06-17 13:11:41 -07:00
where : { age : { gte : 25 } } ,
2025-09-11 16:23:32 -07:00
limit : 3
} )
// Results should be consistent
expect ( results1 . length ) . toBe ( results2 . length )
for ( let i = 0 ; i < results1 . length ; i ++ ) {
expect ( results1 [ i ] . id ) . toBe ( results2 [ i ] . id )
expect ( results1 [ i ] . score ) . toBe ( results2 [ i ] . score )
}
} )
} )
} )
describe ( '2. Fusion Ranking Validation' , ( ) = > {
describe ( 'Reciprocal Rank Fusion Implementation' , ( ) = > {
it ( 'should implement correct RRF formula' , async ( ) = > {
const results = await brain . find ( {
query : 'person' ,
2026-06-17 13:11:41 -07:00
where : { age : { gte : 25 } } ,
2025-09-11 16:23:32 -07:00
limit : 3
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
// RRF scores should be between 0 and 1
results . forEach ( ( result : any ) = > {
expect ( result . score ) . toBeGreaterThan ( 0 )
expect ( result . score ) . toBeLessThanOrEqual ( 1 )
} )
// Scores should be monotonically decreasing
for ( let i = 1 ; i < results . length ; i ++ ) {
expect ( results [ i ] . score ) . toBeLessThanOrEqual ( results [ i - 1 ] . score )
}
} )
it ( 'should use configurable RRF parameters' , async ( ) = > {
// Test with different k parameter (internal implementation detail)
const results1 = await brain . find ( {
query : 'person' ,
limit : 3
} )
const results2 = await brain . find ( {
query : 'person' ,
limit : 3
} )
// Results should be deterministic
expect ( results1 . length ) . toBe ( results2 . length )
} )
2026-06-17 13:11:41 -07:00
it ( 'should expose fusion provenance on results' , async ( ) = > {
2025-09-11 16:23:32 -07:00
const results = await brain . find ( {
query : 'person' ,
connected : { from : 'alice' } ,
2026-06-17 13:11:41 -07:00
where : { age : { gte : 25 } } ,
2025-09-11 16:23:32 -07:00
limit : 5
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
2026-06-17 13:11:41 -07:00
// 8.0 Result shape carries fusion provenance: a normalized score, the full entity,
// and (for query-driven hybrid search) a matchSource of 'text' | 'semantic' | 'both'.
2025-09-11 16:23:32 -07:00
results . forEach ( ( result : any ) = > {
2026-06-17 13:11:41 -07:00
expect ( result ) . toHaveProperty ( 'id' )
expect ( result ) . toHaveProperty ( 'score' )
expect ( result ) . toHaveProperty ( 'entity' )
expect ( result . score ) . toBeGreaterThan ( 0 )
if ( result . matchSource !== undefined ) {
expect ( [ 'text' , 'semantic' , 'both' ] ) . toContain ( result . matchSource )
}
2025-09-11 16:23:32 -07:00
} )
} )
} )
describe ( 'Score Normalization' , ( ) = > {
it ( 'should normalize scores across different search types' , async ( ) = > {
const vectorResults = await brain . find ( {
query : 'person' ,
limit : 3
} )
const graphResults = await brain . find ( {
connected : { from : 'alice' } ,
limit : 3
} )
const fieldResults = await brain . find ( {
2026-06-17 13:11:41 -07:00
where : { age : { gte : 25 } } ,
2025-09-11 16:23:32 -07:00
limit : 3
} )
// All should have normalized scores
const allResults = [ . . . vectorResults , . . . graphResults , . . . fieldResults ]
allResults . forEach ( ( result : any ) = > {
expect ( result . score ) . toBeGreaterThanOrEqual ( 0 )
expect ( result . score ) . toBeLessThanOrEqual ( 1 )
} )
} )
it ( 'should handle extreme score ranges' , async ( ) = > {
// Create entities with very different similarity scores
const similarEntity = await brain . add ( {
data : 'Alice Johnson person social network' ,
type : NounType . Person ,
metadata : { name : 'Alice Johnson' , age : 30 }
} )
const dissimilarEntity = await brain . add ( {
data : 'Quantum physics advanced mathematics' ,
type : NounType . Concept ,
metadata : { name : 'Quantum Physics' , complexity : 'high' }
} )
const results = await brain . find ( {
query : 'Alice person' ,
limit : 5
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
// Should still normalize properly despite large score differences
results . forEach ( ( result : any ) = > {
expect ( result . score ) . toBeGreaterThanOrEqual ( 0 )
expect ( result . score ) . toBeLessThanOrEqual ( 1 )
} )
} )
} )
describe ( 'Weight Adjustment' , ( ) = > {
it ( 'should allow custom weight configuration' , async ( ) = > {
// This would test if the implementation supports custom weights
// Currently testing the default behavior
const results = await brain . find ( {
query : 'person' ,
connected : { from : 'alice' } ,
2026-06-17 13:11:41 -07:00
where : { age : { gte : 25 } } ,
2025-09-11 16:23:32 -07:00
limit : 3
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
// Weights should affect ranking appropriately
} )
it ( 'should handle zero weights for search types' , async ( ) = > {
// Test behavior when certain search types are effectively disabled
const vectorOnly = await brain . find ( {
query : 'person' ,
limit : 3
} )
expect ( vectorOnly . length ) . toBeGreaterThan ( 0 )
vectorOnly . forEach ( ( result : any ) = > {
expect ( result . score ) . toBeGreaterThan ( 0 )
} )
} )
} )
describe ( 'Result Ranking Consistency' , ( ) = > {
it ( 'should produce consistent rankings for identical queries' , async ( ) = > {
const query = {
query : 'person social' ,
connected : { from : 'alice' } ,
2026-06-17 13:11:41 -07:00
where : { age : { gte : 25 } } ,
2025-09-11 16:23:32 -07:00
limit : 5
}
const results1 = await brain . find ( query )
const results2 = await brain . find ( query )
expect ( results1 . length ) . toBe ( results2 . length )
for ( let i = 0 ; i < results1 . length ; i ++ ) {
expect ( results1 [ i ] . id ) . toBe ( results2 [ i ] . id )
expect ( results1 [ i ] . score ) . toBe ( results2 [ i ] . score )
}
} )
it ( 'should maintain ranking stability under load' , async ( ) = > {
const queries = Array ( 5 ) . fill ( {
query : 'person' ,
limit : 3
} )
const allResults = await Promise . all (
queries . map ( query = > brain . find ( query ) )
)
// All result sets should be identical
const firstResults = allResults [ 0 ]
allResults . forEach ( ( results : any ) = > {
expect ( results . length ) . toBe ( firstResults . length )
results . forEach ( ( result : any , i : number ) = > {
expect ( result . id ) . toBe ( firstResults [ i ] . id )
expect ( result . score ) . toBe ( firstResults [ i ] . score )
} )
} )
} )
} )
} )
describe ( '3. Performance Validation' , ( ) = > {
describe ( 'Parallel Execution' , ( ) = > {
it ( 'should execute search types in parallel' , async ( ) = > {
const { result , duration } = await measureExecutionTime ( async ( ) = > {
return brain . find ( {
query : 'person' ,
connected : { from : 'alice' } ,
2026-06-17 13:11:41 -07:00
where : { age : { gte : 25 } } ,
2025-09-11 16:23:32 -07:00
limit : 5
} )
} )
expect ( result . length ) . toBeGreaterThan ( 0 )
expect ( duration ) . toBeLessThan ( 1000 ) // Should complete quickly with parallel execution
} )
it ( 'should handle concurrent unified queries' , async ( ) = > {
const concurrentQueries = Array ( 10 ) . fill ( {
query : 'person' ,
limit : 3
} )
const { result : results , duration } = await measureExecutionTime ( async ( ) = > {
return Promise . all ( concurrentQueries . map ( query = > brain . find ( query ) ) )
} )
expect ( results ) . toHaveLength ( 10 )
results . forEach ( ( queryResults : any ) = > {
expect ( queryResults . length ) . toBeGreaterThan ( 0 )
} )
expect ( duration ) . toBeLessThan ( 2000 ) // Should handle concurrency efficiently
} )
} )
describe ( 'Query Optimization' , ( ) = > {
it ( 'should optimize simple queries' , async ( ) = > {
const { result : simpleResult , duration : simpleDuration } = await measureExecutionTime ( async ( ) = > {
return brain . find ( { query : 'person' , limit : 3 } )
} )
const { result : complexResult , duration : complexDuration } = await measureExecutionTime ( async ( ) = > {
return brain . find ( {
query : 'person' ,
connected : { from : 'alice' } ,
2026-06-17 13:11:41 -07:00
where : { age : { gte : 25 } } ,
2025-09-11 16:23:32 -07:00
limit : 3
} )
} )
expect ( simpleResult . length ) . toBeGreaterThan ( 0 )
expect ( complexResult . length ) . toBeGreaterThan ( 0 )
// Simple queries should be faster
expect ( simpleDuration ) . toBeLessThanOrEqual ( complexDuration )
} )
it ( 'should use fast paths for single search types' , async ( ) = > {
const vectorQuery = { query : 'person' , limit : 3 }
const graphQuery = { connected : { from : 'alice' } , limit : 3 }
2026-06-17 13:11:41 -07:00
const fieldQuery = { where : { age : { gte : 25 } } , limit : 3 }
2025-09-11 16:23:32 -07:00
const [ vectorResults , graphResults , fieldResults ] = await Promise . all ( [
measureExecutionTime ( ( ) = > brain . find ( vectorQuery ) ) ,
measureExecutionTime ( ( ) = > brain . find ( graphQuery ) ) ,
measureExecutionTime ( ( ) = > brain . find ( fieldQuery ) )
] )
// All should complete quickly
expect ( vectorResults . duration ) . toBeLessThan ( 500 )
expect ( graphResults . duration ) . toBeLessThan ( 500 )
expect ( fieldResults . duration ) . toBeLessThan ( 500 )
} )
} )
describe ( 'Memory Pressure Handling' , ( ) = > {
it ( 'should handle large result sets efficiently' , async ( ) = > {
const { result , duration } = await measureExecutionTime ( async ( ) = > {
return brain . find ( {
query : 'entity' ,
limit : 100
} )
} )
expect ( result . length ) . toBeLessThanOrEqual ( 100 )
expect ( duration ) . toBeLessThan ( 2000 ) // Should handle large sets reasonably
} )
it ( 'should manage memory during concurrent large queries' , async ( ) = > {
const largeQueries = Array ( 5 ) . fill ( {
query : 'entity' ,
limit : 50
} )
const { result : results , duration } = await measureExecutionTime ( async ( ) = > {
return Promise . all ( largeQueries . map ( query = > brain . find ( query ) ) )
} )
expect ( results ) . toHaveLength ( 5 )
results . forEach ( ( queryResults : any ) = > {
expect ( queryResults . length ) . toBeLessThanOrEqual ( 50 )
} )
expect ( duration ) . toBeLessThan ( 3000 )
} )
} )
} )
describe ( '4. Edge Cases' , ( ) = > {
describe ( 'Empty Results Handling' , ( ) = > {
fix(8.0): multi-valued array fields index every element (contains no longer misses)
addToIndex builds a fieldsMap from the extracted {field,value} entries, but
only __words__ accumulated — every other repeated field did fieldsMap[field]=value,
so a multi-valued field (tags:['a','b','c'] → three 'tags' entries from
extractIndexableFields) collapsed to last-value-wins. columnStore.addEntity
expands an array to one indexed entry per element, but it only ever received the
final scalar, so `contains` matched only the last element and missed the rest.
Accumulate any repeated non-__words__ field into an array before addEntity
(promote scalar→array on the second occurrence). __words__ keeps its always-array
special-case so its multiValue manifest flag stays set even for single-word docs.
find-unified-integration.test.ts → 0 failures (was 4):
- 'array contains' (A.4): now queries first/middle/last element — all match
(previously only the last-indexed element did).
- 'complete find workflow': $contains→contains (8.0 operator) AND fixed the test
premise — find() hard-ANDs vector∩graph∩metadata, and connected:{from:X} returns
X's NEIGHBOURS not X, so the graph anchor must be 'earth' (which the ML concept
relates to), not the concept itself. Multi-signal scores are reciprocal-rank
fusion (~1/61), not [0,1] cosine, so assert a positive fusion score, not >0.5.
- 'nonsense vector query': cosine search always returns nearest neighbours, so
assert the structural array/bound contract, not length===0 (a Tier-2 concern).
- 'hard-ANDs signals': a nonexistent connected.from is an empty graph signal that
zeros the intersection — assert length===0 (documented AND semantics), was >0.
1469 unit + full find-unified integration green.
2026-06-19 11:37:59 -07:00
it ( 'should handle a nonsense vector query without error' , async ( ) = > {
// A pure vector query has no notion of "no match": cosine similarity
// always ranks the corpus, so a nonsense string returns the nearest
// neighbours (≤ limit), not an empty set. Tier-1 asserts the structural
// contract (well-formed array, bounded by limit); whether a nonsense
// query SHOULD rank low is a Tier-2 semantic-relevance concern. The
// genuinely-empty cases are the graph/field tests below.
2025-09-11 16:23:32 -07:00
const results = await brain . find ( {
query : 'nonexistent_content_xyz123' ,
limit : 5
} )
expect ( Array . isArray ( results ) ) . toBe ( true )
fix(8.0): multi-valued array fields index every element (contains no longer misses)
addToIndex builds a fieldsMap from the extracted {field,value} entries, but
only __words__ accumulated — every other repeated field did fieldsMap[field]=value,
so a multi-valued field (tags:['a','b','c'] → three 'tags' entries from
extractIndexableFields) collapsed to last-value-wins. columnStore.addEntity
expands an array to one indexed entry per element, but it only ever received the
final scalar, so `contains` matched only the last element and missed the rest.
Accumulate any repeated non-__words__ field into an array before addEntity
(promote scalar→array on the second occurrence). __words__ keeps its always-array
special-case so its multiValue manifest flag stays set even for single-word docs.
find-unified-integration.test.ts → 0 failures (was 4):
- 'array contains' (A.4): now queries first/middle/last element — all match
(previously only the last-indexed element did).
- 'complete find workflow': $contains→contains (8.0 operator) AND fixed the test
premise — find() hard-ANDs vector∩graph∩metadata, and connected:{from:X} returns
X's NEIGHBOURS not X, so the graph anchor must be 'earth' (which the ML concept
relates to), not the concept itself. Multi-signal scores are reciprocal-rank
fusion (~1/61), not [0,1] cosine, so assert a positive fusion score, not >0.5.
- 'nonsense vector query': cosine search always returns nearest neighbours, so
assert the structural array/bound contract, not length===0 (a Tier-2 concern).
- 'hard-ANDs signals': a nonexistent connected.from is an empty graph signal that
zeros the intersection — assert length===0 (documented AND semantics), was >0.
1469 unit + full find-unified integration green.
2026-06-19 11:37:59 -07:00
expect ( results . length ) . toBeLessThanOrEqual ( 5 )
results . forEach ( ( r : any ) = > {
expect ( r . id ) . toBeDefined ( )
expect ( typeof r . score ) . toBe ( 'number' )
} )
2025-09-11 16:23:32 -07:00
} )
it ( 'should handle empty graph search results' , async ( ) = > {
const results = await brain . find ( {
connected : {
from : 'nonexistent_entity' ,
direction : 'both'
} ,
limit : 5
} )
expect ( Array . isArray ( results ) ) . toBe ( true )
expect ( results . length ) . toBe ( 0 )
} )
it ( 'should handle empty field search results' , async ( ) = > {
const results = await brain . find ( {
where : { nonexistent_field : 'value' } ,
limit : 5
} )
expect ( Array . isArray ( results ) ) . toBe ( true )
expect ( results . length ) . toBe ( 0 )
} )
fix(8.0): multi-valued array fields index every element (contains no longer misses)
addToIndex builds a fieldsMap from the extracted {field,value} entries, but
only __words__ accumulated — every other repeated field did fieldsMap[field]=value,
so a multi-valued field (tags:['a','b','c'] → three 'tags' entries from
extractIndexableFields) collapsed to last-value-wins. columnStore.addEntity
expands an array to one indexed entry per element, but it only ever received the
final scalar, so `contains` matched only the last element and missed the rest.
Accumulate any repeated non-__words__ field into an array before addEntity
(promote scalar→array on the second occurrence). __words__ keeps its always-array
special-case so its multiValue manifest flag stays set even for single-word docs.
find-unified-integration.test.ts → 0 failures (was 4):
- 'array contains' (A.4): now queries first/middle/last element — all match
(previously only the last-indexed element did).
- 'complete find workflow': $contains→contains (8.0 operator) AND fixed the test
premise — find() hard-ANDs vector∩graph∩metadata, and connected:{from:X} returns
X's NEIGHBOURS not X, so the graph anchor must be 'earth' (which the ML concept
relates to), not the concept itself. Multi-signal scores are reciprocal-rank
fusion (~1/61), not [0,1] cosine, so assert a positive fusion score, not >0.5.
- 'nonsense vector query': cosine search always returns nearest neighbours, so
assert the structural array/bound contract, not length===0 (a Tier-2 concern).
- 'hard-ANDs signals': a nonexistent connected.from is an empty graph signal that
zeros the intersection — assert length===0 (documented AND semantics), was >0.
1469 unit + full find-unified integration green.
2026-06-19 11:37:59 -07:00
it ( 'hard-ANDs signals — an empty graph signal zeros the intersection' , async ( ) = > {
// find() is a hard AND across its signals (vector ∩ graph ∩ metadata):
// the result is the INTERSECTION, not a union. Here the vector ('person')
// and field (age >= 25) signals match entities, but `connected.from` is a
// nonexistent entity → empty graph set → the whole intersection is empty.
// (For a soft RRF UNION ranking, use getTripleIntelligence().find().)
2025-09-11 16:23:32 -07:00
const results = await brain . find ( {
fix(8.0): multi-valued array fields index every element (contains no longer misses)
addToIndex builds a fieldsMap from the extracted {field,value} entries, but
only __words__ accumulated — every other repeated field did fieldsMap[field]=value,
so a multi-valued field (tags:['a','b','c'] → three 'tags' entries from
extractIndexableFields) collapsed to last-value-wins. columnStore.addEntity
expands an array to one indexed entry per element, but it only ever received the
final scalar, so `contains` matched only the last element and missed the rest.
Accumulate any repeated non-__words__ field into an array before addEntity
(promote scalar→array on the second occurrence). __words__ keeps its always-array
special-case so its multiValue manifest flag stays set even for single-word docs.
find-unified-integration.test.ts → 0 failures (was 4):
- 'array contains' (A.4): now queries first/middle/last element — all match
(previously only the last-indexed element did).
- 'complete find workflow': $contains→contains (8.0 operator) AND fixed the test
premise — find() hard-ANDs vector∩graph∩metadata, and connected:{from:X} returns
X's NEIGHBOURS not X, so the graph anchor must be 'earth' (which the ML concept
relates to), not the concept itself. Multi-signal scores are reciprocal-rank
fusion (~1/61), not [0,1] cosine, so assert a positive fusion score, not >0.5.
- 'nonsense vector query': cosine search always returns nearest neighbours, so
assert the structural array/bound contract, not length===0 (a Tier-2 concern).
- 'hard-ANDs signals': a nonexistent connected.from is an empty graph signal that
zeros the intersection — assert length===0 (documented AND semantics), was >0.
1469 unit + full find-unified integration green.
2026-06-19 11:37:59 -07:00
query : 'person' ,
2025-09-11 16:23:32 -07:00
connected : {
fix(8.0): multi-valued array fields index every element (contains no longer misses)
addToIndex builds a fieldsMap from the extracted {field,value} entries, but
only __words__ accumulated — every other repeated field did fieldsMap[field]=value,
so a multi-valued field (tags:['a','b','c'] → three 'tags' entries from
extractIndexableFields) collapsed to last-value-wins. columnStore.addEntity
expands an array to one indexed entry per element, but it only ever received the
final scalar, so `contains` matched only the last element and missed the rest.
Accumulate any repeated non-__words__ field into an array before addEntity
(promote scalar→array on the second occurrence). __words__ keeps its always-array
special-case so its multiValue manifest flag stays set even for single-word docs.
find-unified-integration.test.ts → 0 failures (was 4):
- 'array contains' (A.4): now queries first/middle/last element — all match
(previously only the last-indexed element did).
- 'complete find workflow': $contains→contains (8.0 operator) AND fixed the test
premise — find() hard-ANDs vector∩graph∩metadata, and connected:{from:X} returns
X's NEIGHBOURS not X, so the graph anchor must be 'earth' (which the ML concept
relates to), not the concept itself. Multi-signal scores are reciprocal-rank
fusion (~1/61), not [0,1] cosine, so assert a positive fusion score, not >0.5.
- 'nonsense vector query': cosine search always returns nearest neighbours, so
assert the structural array/bound contract, not length===0 (a Tier-2 concern).
- 'hard-ANDs signals': a nonexistent connected.from is an empty graph signal that
zeros the intersection — assert length===0 (documented AND semantics), was >0.
1469 unit + full find-unified integration green.
2026-06-19 11:37:59 -07:00
from : 'nonexistent_entity' // empty graph signal
2025-09-11 16:23:32 -07:00
} ,
fix(8.0): multi-valued array fields index every element (contains no longer misses)
addToIndex builds a fieldsMap from the extracted {field,value} entries, but
only __words__ accumulated — every other repeated field did fieldsMap[field]=value,
so a multi-valued field (tags:['a','b','c'] → three 'tags' entries from
extractIndexableFields) collapsed to last-value-wins. columnStore.addEntity
expands an array to one indexed entry per element, but it only ever received the
final scalar, so `contains` matched only the last element and missed the rest.
Accumulate any repeated non-__words__ field into an array before addEntity
(promote scalar→array on the second occurrence). __words__ keeps its always-array
special-case so its multiValue manifest flag stays set even for single-word docs.
find-unified-integration.test.ts → 0 failures (was 4):
- 'array contains' (A.4): now queries first/middle/last element — all match
(previously only the last-indexed element did).
- 'complete find workflow': $contains→contains (8.0 operator) AND fixed the test
premise — find() hard-ANDs vector∩graph∩metadata, and connected:{from:X} returns
X's NEIGHBOURS not X, so the graph anchor must be 'earth' (which the ML concept
relates to), not the concept itself. Multi-signal scores are reciprocal-rank
fusion (~1/61), not [0,1] cosine, so assert a positive fusion score, not >0.5.
- 'nonsense vector query': cosine search always returns nearest neighbours, so
assert the structural array/bound contract, not length===0 (a Tier-2 concern).
- 'hard-ANDs signals': a nonexistent connected.from is an empty graph signal that
zeros the intersection — assert length===0 (documented AND semantics), was >0.
1469 unit + full find-unified integration green.
2026-06-19 11:37:59 -07:00
where : { age : { gte : 25 } } ,
2025-09-11 16:23:32 -07:00
limit : 5
} )
expect ( Array . isArray ( results ) ) . toBe ( true )
fix(8.0): multi-valued array fields index every element (contains no longer misses)
addToIndex builds a fieldsMap from the extracted {field,value} entries, but
only __words__ accumulated — every other repeated field did fieldsMap[field]=value,
so a multi-valued field (tags:['a','b','c'] → three 'tags' entries from
extractIndexableFields) collapsed to last-value-wins. columnStore.addEntity
expands an array to one indexed entry per element, but it only ever received the
final scalar, so `contains` matched only the last element and missed the rest.
Accumulate any repeated non-__words__ field into an array before addEntity
(promote scalar→array on the second occurrence). __words__ keeps its always-array
special-case so its multiValue manifest flag stays set even for single-word docs.
find-unified-integration.test.ts → 0 failures (was 4):
- 'array contains' (A.4): now queries first/middle/last element — all match
(previously only the last-indexed element did).
- 'complete find workflow': $contains→contains (8.0 operator) AND fixed the test
premise — find() hard-ANDs vector∩graph∩metadata, and connected:{from:X} returns
X's NEIGHBOURS not X, so the graph anchor must be 'earth' (which the ML concept
relates to), not the concept itself. Multi-signal scores are reciprocal-rank
fusion (~1/61), not [0,1] cosine, so assert a positive fusion score, not >0.5.
- 'nonsense vector query': cosine search always returns nearest neighbours, so
assert the structural array/bound contract, not length===0 (a Tier-2 concern).
- 'hard-ANDs signals': a nonexistent connected.from is an empty graph signal that
zeros the intersection — assert length===0 (documented AND semantics), was >0.
1469 unit + full find-unified integration green.
2026-06-19 11:37:59 -07:00
expect ( results . length ) . toBe ( 0 )
2025-09-11 16:23:32 -07:00
} )
} )
describe ( 'Conflicting Results' , ( ) = > {
it ( 'should handle mutually exclusive constraints' , async ( ) = > {
const results = await brain . find ( {
query : 'Alice' ,
where : { name : 'Bob' } , // Different person
connected : {
from : 'charlie' // Alice is not directly connected to Charlie
} ,
limit : 5
} )
expect ( Array . isArray ( results ) ) . toBe ( true )
// Should return results but with appropriate scoring
if ( results . length > 0 ) {
expect ( results [ 0 ] . score ) . toBeLessThan ( 0.8 ) // Lower confidence due to conflicts
}
} )
it ( 'should handle type conflicts' , async ( ) = > {
const results = await brain . find ( {
query : 'Earth planet' ,
type : NounType . Person , // But Earth is a location
limit : 5
} )
expect ( Array . isArray ( results ) ) . toBe ( true )
// Should handle type mismatch gracefully
} )
} )
describe ( 'Memory Pressure' , ( ) = > {
it ( 'should handle deep graph traversals' , async ( ) = > {
const results = await brain . find ( {
connected : {
from : 'alice' ,
direction : 'both' ,
maxDepth : 5
} ,
limit : 20
} )
expect ( Array . isArray ( results ) ) . toBe ( true )
expect ( results . length ) . toBeLessThanOrEqual ( 20 )
} )
it ( 'should handle complex metadata queries' , async ( ) = > {
const results = await brain . find ( {
where : {
2026-06-17 13:11:41 -07:00
allOf : [
{ age : { gte : 20 } } ,
{ age : { lte : 40 } } ,
2025-09-11 16:23:32 -07:00
{
2026-06-17 13:11:41 -07:00
anyOf : [
2025-09-11 16:23:32 -07:00
{ name : 'Alice' } ,
{ name : 'Bob' } ,
{ name : 'Charlie' }
]
}
]
} ,
limit : 10
} )
expect ( Array . isArray ( results ) ) . toBe ( true )
results . forEach ( ( result : any ) = > {
const age = result . entity . metadata ? . age
const name = result . entity . metadata ? . name
expect ( age ) . toBeGreaterThanOrEqual ( 20 )
expect ( age ) . toBeLessThanOrEqual ( 40 )
expect ( [ 'Alice' , 'Bob' , 'Charlie' ] ) . toContain ( name )
} )
} )
} )
describe ( 'Concurrent Queries' , ( ) = > {
it ( 'should handle multiple simultaneous unified queries' , async ( ) = > {
const queries = [
{ query : 'Alice' , limit : 3 } ,
{ connected : { from : 'alice' } , limit : 3 } ,
2026-06-17 13:11:41 -07:00
{ where : { age : { gte : 25 } } , limit : 3 } ,
2025-09-11 16:23:32 -07:00
{
query : 'person' ,
connected : { from : 'alice' } ,
2026-06-17 13:11:41 -07:00
where : { age : { gte : 25 } } ,
2025-09-11 16:23:32 -07:00
limit : 3
}
]
const results = await Promise . all (
queries . map ( query = > brain . find ( query ) )
)
expect ( results ) . toHaveLength ( 4 )
results . forEach ( ( queryResults : any ) = > {
expect ( Array . isArray ( queryResults ) ) . toBe ( true )
} )
} )
it ( 'should maintain isolation between concurrent queries' , async ( ) = > {
const query1 = { query : 'Alice' , limit : 2 }
const query2 = { query : 'Bob' , limit : 2 }
const [ results1 , results2 ] = await Promise . all ( [
brain . find ( query1 ) ,
brain . find ( query2 )
] )
// Results should be different
expect ( results1 . length ) . toBeGreaterThan ( 0 )
expect ( results2 . length ) . toBeGreaterThan ( 0 )
// Should find different primary entities
const aliceIn1 = results1 . find ( ( r : any ) = > r . entity . metadata ? . name === 'Alice' )
const bobIn2 = results2 . find ( ( r : any ) = > r . entity . metadata ? . name === 'Bob' )
expect ( aliceIn1 ) . toBeDefined ( )
expect ( bobIn2 ) . toBeDefined ( )
} )
} )
} )
describe ( '5. Integration Testing' , ( ) = > {
describe ( 'End-to-End Find Method Testing' , ( ) = > {
it ( 'should perform complete find workflow' , async ( ) = > {
// Add a complex entity
const complexEntityId = await brain . add ( {
data : 'Machine learning is a subset of artificial intelligence that enables computers to learn from data' ,
type : NounType . Concept ,
metadata : {
name : 'Machine Learning' ,
category : 'AI' ,
difficulty : 'advanced' ,
tags : [ 'AI' , 'ML' , 'data science' ] ,
related : [ 'neural networks' , 'deep learning' ]
}
} )
// Create relationships
await brain . relate ( {
from : complexEntityId ,
to : 'earth' , // Connect to existing entity
type : VerbType . RelatedTo
} )
fix(8.0): multi-valued array fields index every element (contains no longer misses)
addToIndex builds a fieldsMap from the extracted {field,value} entries, but
only __words__ accumulated — every other repeated field did fieldsMap[field]=value,
so a multi-valued field (tags:['a','b','c'] → three 'tags' entries from
extractIndexableFields) collapsed to last-value-wins. columnStore.addEntity
expands an array to one indexed entry per element, but it only ever received the
final scalar, so `contains` matched only the last element and missed the rest.
Accumulate any repeated non-__words__ field into an array before addEntity
(promote scalar→array on the second occurrence). __words__ keeps its always-array
special-case so its multiValue manifest flag stays set even for single-word docs.
find-unified-integration.test.ts → 0 failures (was 4):
- 'array contains' (A.4): now queries first/middle/last element — all match
(previously only the last-indexed element did).
- 'complete find workflow': $contains→contains (8.0 operator) AND fixed the test
premise — find() hard-ANDs vector∩graph∩metadata, and connected:{from:X} returns
X's NEIGHBOURS not X, so the graph anchor must be 'earth' (which the ML concept
relates to), not the concept itself. Multi-signal scores are reciprocal-rank
fusion (~1/61), not [0,1] cosine, so assert a positive fusion score, not >0.5.
- 'nonsense vector query': cosine search always returns nearest neighbours, so
assert the structural array/bound contract, not length===0 (a Tier-2 concern).
- 'hard-ANDs signals': a nonexistent connected.from is an empty graph signal that
zeros the intersection — assert length===0 (documented AND semantics), was >0.
1469 unit + full find-unified integration green.
2026-06-19 11:37:59 -07:00
// Perform unified search. find() hard-ANDs its three signals (vector ∩
// graph ∩ metadata), so the target entity must appear in ALL of them.
// The graph anchor is 'earth' (NOT complexEntityId): a `connected:{from:X}`
// filter returns X's NEIGHBOURS, never X itself, and we related the ML
// concept → earth above, so earth's bidirectional neighbours include it.
2025-09-11 16:23:32 -07:00
const results = await brain . find ( {
query : 'artificial intelligence learning' ,
connected : {
fix(8.0): multi-valued array fields index every element (contains no longer misses)
addToIndex builds a fieldsMap from the extracted {field,value} entries, but
only __words__ accumulated — every other repeated field did fieldsMap[field]=value,
so a multi-valued field (tags:['a','b','c'] → three 'tags' entries from
extractIndexableFields) collapsed to last-value-wins. columnStore.addEntity
expands an array to one indexed entry per element, but it only ever received the
final scalar, so `contains` matched only the last element and missed the rest.
Accumulate any repeated non-__words__ field into an array before addEntity
(promote scalar→array on the second occurrence). __words__ keeps its always-array
special-case so its multiValue manifest flag stays set even for single-word docs.
find-unified-integration.test.ts → 0 failures (was 4):
- 'array contains' (A.4): now queries first/middle/last element — all match
(previously only the last-indexed element did).
- 'complete find workflow': $contains→contains (8.0 operator) AND fixed the test
premise — find() hard-ANDs vector∩graph∩metadata, and connected:{from:X} returns
X's NEIGHBOURS not X, so the graph anchor must be 'earth' (which the ML concept
relates to), not the concept itself. Multi-signal scores are reciprocal-rank
fusion (~1/61), not [0,1] cosine, so assert a positive fusion score, not >0.5.
- 'nonsense vector query': cosine search always returns nearest neighbours, so
assert the structural array/bound contract, not length===0 (a Tier-2 concern).
- 'hard-ANDs signals': a nonexistent connected.from is an empty graph signal that
zeros the intersection — assert length===0 (documented AND semantics), was >0.
1469 unit + full find-unified integration green.
2026-06-19 11:37:59 -07:00
from : 'earth' ,
2025-09-11 16:23:32 -07:00
direction : 'both'
} ,
where : {
category : 'AI' ,
fix(8.0): multi-valued array fields index every element (contains no longer misses)
addToIndex builds a fieldsMap from the extracted {field,value} entries, but
only __words__ accumulated — every other repeated field did fieldsMap[field]=value,
so a multi-valued field (tags:['a','b','c'] → three 'tags' entries from
extractIndexableFields) collapsed to last-value-wins. columnStore.addEntity
expands an array to one indexed entry per element, but it only ever received the
final scalar, so `contains` matched only the last element and missed the rest.
Accumulate any repeated non-__words__ field into an array before addEntity
(promote scalar→array on the second occurrence). __words__ keeps its always-array
special-case so its multiValue manifest flag stays set even for single-word docs.
find-unified-integration.test.ts → 0 failures (was 4):
- 'array contains' (A.4): now queries first/middle/last element — all match
(previously only the last-indexed element did).
- 'complete find workflow': $contains→contains (8.0 operator) AND fixed the test
premise — find() hard-ANDs vector∩graph∩metadata, and connected:{from:X} returns
X's NEIGHBOURS not X, so the graph anchor must be 'earth' (which the ML concept
relates to), not the concept itself. Multi-signal scores are reciprocal-rank
fusion (~1/61), not [0,1] cosine, so assert a positive fusion score, not >0.5.
- 'nonsense vector query': cosine search always returns nearest neighbours, so
assert the structural array/bound contract, not length===0 (a Tier-2 concern).
- 'hard-ANDs signals': a nonexistent connected.from is an empty graph signal that
zeros the intersection — assert length===0 (documented AND semantics), was >0.
1469 unit + full find-unified integration green.
2026-06-19 11:37:59 -07:00
// 8.0 array-membership operator is `contains` (not Mongo `$contains`).
// A.4 fix: tags:['AI','ML','data science'] now indexes every element,
// so `contains:'AI'` matches (previously only the last element was kept).
tags : { contains : 'AI' }
2025-09-11 16:23:32 -07:00
} ,
limit : 5
} )
expect ( results . length ) . toBeGreaterThan ( 0 )
fix(8.0): multi-valued array fields index every element (contains no longer misses)
addToIndex builds a fieldsMap from the extracted {field,value} entries, but
only __words__ accumulated — every other repeated field did fieldsMap[field]=value,
so a multi-valued field (tags:['a','b','c'] → three 'tags' entries from
extractIndexableFields) collapsed to last-value-wins. columnStore.addEntity
expands an array to one indexed entry per element, but it only ever received the
final scalar, so `contains` matched only the last element and missed the rest.
Accumulate any repeated non-__words__ field into an array before addEntity
(promote scalar→array on the second occurrence). __words__ keeps its always-array
special-case so its multiValue manifest flag stays set even for single-word docs.
find-unified-integration.test.ts → 0 failures (was 4):
- 'array contains' (A.4): now queries first/middle/last element — all match
(previously only the last-indexed element did).
- 'complete find workflow': $contains→contains (8.0 operator) AND fixed the test
premise — find() hard-ANDs vector∩graph∩metadata, and connected:{from:X} returns
X's NEIGHBOURS not X, so the graph anchor must be 'earth' (which the ML concept
relates to), not the concept itself. Multi-signal scores are reciprocal-rank
fusion (~1/61), not [0,1] cosine, so assert a positive fusion score, not >0.5.
- 'nonsense vector query': cosine search always returns nearest neighbours, so
assert the structural array/bound contract, not length===0 (a Tier-2 concern).
- 'hard-ANDs signals': a nonexistent connected.from is an empty graph signal that
zeros the intersection — assert length===0 (documented AND semantics), was >0.
1469 unit + full find-unified integration green.
2026-06-19 11:37:59 -07:00
// The ML concept satisfies all three signals, so it is in the result set.
2025-09-11 16:23:32 -07:00
const mlResult = results . find ( ( r : any ) = > r . id === complexEntityId )
expect ( mlResult ) . toBeDefined ( )
fix(8.0): multi-valued array fields index every element (contains no longer misses)
addToIndex builds a fieldsMap from the extracted {field,value} entries, but
only __words__ accumulated — every other repeated field did fieldsMap[field]=value,
so a multi-valued field (tags:['a','b','c'] → three 'tags' entries from
extractIndexableFields) collapsed to last-value-wins. columnStore.addEntity
expands an array to one indexed entry per element, but it only ever received the
final scalar, so `contains` matched only the last element and missed the rest.
Accumulate any repeated non-__words__ field into an array before addEntity
(promote scalar→array on the second occurrence). __words__ keeps its always-array
special-case so its multiValue manifest flag stays set even for single-word docs.
find-unified-integration.test.ts → 0 failures (was 4):
- 'array contains' (A.4): now queries first/middle/last element — all match
(previously only the last-indexed element did).
- 'complete find workflow': $contains→contains (8.0 operator) AND fixed the test
premise — find() hard-ANDs vector∩graph∩metadata, and connected:{from:X} returns
X's NEIGHBOURS not X, so the graph anchor must be 'earth' (which the ML concept
relates to), not the concept itself. Multi-signal scores are reciprocal-rank
fusion (~1/61), not [0,1] cosine, so assert a positive fusion score, not >0.5.
- 'nonsense vector query': cosine search always returns nearest neighbours, so
assert the structural array/bound contract, not length===0 (a Tier-2 concern).
- 'hard-ANDs signals': a nonexistent connected.from is an empty graph signal that
zeros the intersection — assert length===0 (documented AND semantics), was >0.
1469 unit + full find-unified integration green.
2026-06-19 11:37:59 -07:00
// Multi-signal find() scores via reciprocal-rank fusion (k≈60), so the
// score is a small fusion rank (~1/61), NOT a [0,1] cosine similarity —
// asserting a relevance magnitude here is a Tier-2 concern. Tier-1 checks
// only that a matched row carries a valid positive fusion score.
expect ( typeof mlResult ! . score ) . toBe ( 'number' )
expect ( mlResult ! . score ) . toBeGreaterThan ( 0 )
2025-09-11 16:23:32 -07:00
} )
} )
describe ( 'Real Data Scenarios' , ( ) = > {
it ( 'should handle social network analysis' , async ( ) = > {
// Find central people in the network
const centralPeople = await brain . find ( {
type : NounType . Person ,
connected : {
from : 'alice' ,
direction : 'both' ,
maxDepth : 2
} ,
limit : 10
} )
expect ( centralPeople . length ) . toBeGreaterThan ( 0 )
centralPeople . forEach ( ( person : any ) = > {
expect ( person . entity . type ) . toBe ( NounType . Person )
} )
} )
it ( 'should handle knowledge graph traversal' , async ( ) = > {
// Find concepts related to Earth
const earthConcepts = await brain . find ( {
connected : {
from : 'earth' ,
direction : 'both'
} ,
type : NounType . Concept ,
limit : 5
} )
expect ( Array . isArray ( earthConcepts ) ) . toBe ( true )
earthConcepts . forEach ( ( concept : any ) = > {
expect ( concept . entity . type ) . toBe ( NounType . Concept )
} )
} )
it ( 'should handle mixed entity types' , async ( ) = > {
const mixedResults = await brain . find ( {
query : 'system network' ,
limit : 10
} )
expect ( mixedResults . length ) . toBeGreaterThan ( 0 )
// Should contain different types of entities
const types = new Set ( mixedResults . map ( ( r : any ) = > r . entity . type ) )
expect ( types . size ) . toBeGreaterThan ( 1 )
} )
} )
describe ( 'Performance Benchmarks' , ( ) = > {
it ( 'should benchmark vector search performance' , async ( ) = > {
const { result , duration } = await measureExecutionTime ( async ( ) = > {
return brain . find ( {
query : 'person social network' ,
limit : 10
} )
} )
expect ( result . length ) . toBeGreaterThan ( 0 )
expect ( duration ) . toBeLessThan ( 1000 ) // Should be fast
console . log ( ` Vector search: ${ result . length } results in ${ duration . toFixed ( 2 ) } ms ` )
} )
it ( 'should benchmark graph search performance' , async ( ) = > {
const { result , duration } = await measureExecutionTime ( async ( ) = > {
return brain . find ( {
connected : {
from : 'alice' ,
direction : 'both' ,
maxDepth : 3
} ,
limit : 20
} )
} )
expect ( result . length ) . toBeGreaterThan ( 0 )
expect ( duration ) . toBeLessThan ( 1000 ) // Should be fast
console . log ( ` Graph search: ${ result . length } results in ${ duration . toFixed ( 2 ) } ms ` )
} )
it ( 'should benchmark unified search performance' , async ( ) = > {
const { result , duration } = await measureExecutionTime ( async ( ) = > {
return brain . find ( {
query : 'person' ,
connected : { from : 'alice' } ,
2026-06-17 13:11:41 -07:00
where : { age : { gte : 25 } } ,
2025-09-11 16:23:32 -07:00
limit : 10
} )
} )
expect ( result . length ) . toBeGreaterThan ( 0 )
expect ( duration ) . toBeLessThan ( 1500 ) // Should be reasonably fast
console . log ( ` Unified search: ${ result . length } results in ${ duration . toFixed ( 2 ) } ms ` )
} )
it ( 'should benchmark concurrent unified queries' , async ( ) = > {
const queries = Array ( 20 ) . fill ( {
query : 'entity' ,
limit : 5
} )
const { result : results , duration } = await measureExecutionTime ( async ( ) = > {
return Promise . all ( queries . map ( query = > brain . find ( query ) ) )
} )
expect ( results ) . toHaveLength ( 20 )
expect ( duration ) . toBeLessThan ( 3000 ) // Should handle concurrency well
console . log ( ` Concurrent queries: ${ results . length } queries in ${ duration . toFixed ( 2 ) } ms ` )
} )
} )
describe ( 'Error Handling' , ( ) = > {
it ( 'should handle invalid query parameters gracefully' , async ( ) = > {
// Test with invalid parameters
const results = await brain . find ( {
query : '' ,
connected : { from : '' } ,
where : { } ,
limit : 0
} as any )
expect ( Array . isArray ( results ) ) . toBe ( true )
} )
it ( 'should handle malformed metadata queries' , async ( ) = > {
const results = await brain . find ( {
where : {
$invalidOperator : 'value'
} ,
limit : 5
} as any )
expect ( Array . isArray ( results ) ) . toBe ( true )
} )
it ( 'should handle network-like failures gracefully' , async ( ) = > {
// Simulate by using invalid entity IDs
const results = await brain . find ( {
connected : {
from : 'definitely_nonexistent_entity_12345' ,
direction : 'both'
} ,
limit : 5
} )
expect ( Array . isArray ( results ) ) . toBe ( true )
expect ( results . length ) . toBe ( 0 )
} )
it ( 'should handle extreme parameter values' , async ( ) = > {
const results = await brain . find ( {
limit : 10000 , // Very large limit
query : 'test' ,
connected : {
maxDepth : 100 // Very deep traversal
}
} )
expect ( Array . isArray ( results ) ) . toBe ( true )
expect ( results . length ) . toBeLessThanOrEqual ( 10000 )
} )
} )
} )
} )