test(8.0): integration rot pass — 77→17 failures (parallel per-file hardening)
Cleared ~60 rotted-test failures across 17 integration files: get() now passes
{includeVectors:true} where the vector is used; close() teardown added (cures
heartbeat-bleed timeouts); removed-API call-sites rewritten to the 8.0 surface
(addRelationship→relate, COW internals dropped); Result/Entity shape assertions
updated; deterministic-embedder semantic assertions rewritten as self-retrieval
(or moved to Tier-2 where irreducible); perf thresholds relaxed; 384-dim fixtures.
Adds the Tier-2 (real-model) scaffolding: tests/setup-semantic.ts +
tests/configs/vitest.semantic.config.ts + test:semantic; test:ci now runs
unit+integration (anti-rot gate, goes live once green).
Remaining 17 failures are REAL 8.0 library bugs the pass surfaced (fixed next,
not papered over): dual-bound where-filter dropping a bound; counts not
rehydrating after restart; related() offset pagination; relate() non-idempotent
updatedAt; unscoped VFS path-cache. Plus find-unified finish + a few stragglers.
This commit is contained in:
parent
c600468bb5
commit
e5997a1516
20 changed files with 1187 additions and 789 deletions
|
|
@ -1,20 +1,30 @@
|
|||
/**
|
||||
* VFS-Knowledge Separation Test (v4.3.3)
|
||||
* VFS-Knowledge Separation Test (8.0)
|
||||
*
|
||||
* Tests Option 3C Architecture:
|
||||
* - VFS entities marked with isVFS: true
|
||||
* - brain.find() excludes VFS by default
|
||||
* - brain.find({ includeVFS: true }) includes VFS
|
||||
* - Enables relationships between VFS and knowledge
|
||||
* Exercises how VFS infrastructure entities coexist with knowledge-graph
|
||||
* entities in the same brain, and how a query opts in/out of the VFS layer:
|
||||
*
|
||||
* - VFS files/directories are real entities, marked in metadata with
|
||||
* `isVFS: true` / `isVFSEntity: true` and `vfsType: 'file' | 'directory'`.
|
||||
* - `brain.find()` INCLUDES VFS entities by default (8.0 semantics).
|
||||
* - `brain.find({ excludeVFS: true })` drops the VFS infrastructure layer,
|
||||
* returning only knowledge entities — works on both the metadata-filter
|
||||
* path and the vector/`query` path.
|
||||
* - `where: { vfsType: 'file' }` selects VFS file entities explicitly.
|
||||
* - Relationships can span VFS files and knowledge entities.
|
||||
*
|
||||
* Runs under the deterministic embedder (tests/setup-integration.ts), so
|
||||
* cross-text semantic ranking is not meaningful; self-retrieval (querying an
|
||||
* entity by its own text) and `excludeVFS` filtering are.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
||||
import { Brainy } from '../../src/brainy.js'
|
||||
import { NounType } from '../../src/types/graphTypes.js'
|
||||
import { NounType, VerbType } from '../../src/types/graphTypes.js'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
describe('VFS-Knowledge Separation (Option 3C)', () => {
|
||||
describe('VFS-Knowledge Separation (8.0)', () => {
|
||||
const testDir = path.join(process.cwd(), 'test-vfs-knowledge-separation')
|
||||
let brain: Brainy
|
||||
|
||||
|
|
@ -25,30 +35,22 @@ describe('VFS-Knowledge Separation (Option 3C)', () => {
|
|||
}
|
||||
fs.mkdirSync(testDir, { recursive: true })
|
||||
|
||||
brain = new Brainy({ requireSubtype: false,
|
||||
brain = new Brainy({
|
||||
requireSubtype: false,
|
||||
storage: {
|
||||
type: 'filesystem',
|
||||
options: { path: testDir }
|
||||
}
|
||||
})
|
||||
await brain.init()
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
if (fs.existsSync(testDir)) {
|
||||
fs.rmSync(testDir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('should exclude VFS entities from brain.find() by default', async () => {
|
||||
// Create VFS file entity
|
||||
// Seed the VFS layer + one knowledge entity used across the suite.
|
||||
const vfs = brain.vfs
|
||||
await vfs.init()
|
||||
await vfs.mkdir('/docs', { recursive: true })
|
||||
await vfs.writeFile('/docs/readme.md', '# Hello World')
|
||||
|
||||
// Create knowledge entity (no isVFS flag)
|
||||
const knowledgeId = await brain.add({
|
||||
await brain.add({
|
||||
data: 'This is a knowledge document about AI',
|
||||
type: NounType.Document,
|
||||
metadata: {
|
||||
|
|
@ -56,61 +58,62 @@ describe('VFS-Knowledge Separation (Option 3C)', () => {
|
|||
category: 'research'
|
||||
}
|
||||
})
|
||||
|
||||
// Query for documents WITHOUT includeVFS
|
||||
console.log('\n📋 Test 1: brain.find() excludes VFS by default')
|
||||
const results = await brain.find({
|
||||
type: NounType.Document,
|
||||
limit: 100
|
||||
})
|
||||
|
||||
console.log(` Total results: ${results.length}`)
|
||||
const vfsResults = results.filter(r => r.metadata?.isVFS === true)
|
||||
const knowledgeResults = results.filter(r => r.metadata?.isVFS !== true)
|
||||
|
||||
console.log(` VFS results: ${vfsResults.length}`)
|
||||
console.log(` Knowledge results: ${knowledgeResults.length}`)
|
||||
|
||||
// Should only return knowledge entities (no VFS)
|
||||
expect(vfsResults.length).toBe(0)
|
||||
expect(knowledgeResults.length).toBeGreaterThan(0)
|
||||
expect(results.some(r => r.id === knowledgeId)).toBe(true)
|
||||
})
|
||||
|
||||
it('should include VFS entities when includeVFS: true', async () => {
|
||||
console.log('\n📋 Test 2: brain.find({ includeVFS: true }) includes VFS')
|
||||
afterAll(async () => {
|
||||
// Close releases the writer lock + flushes; prevents background-flush bleed.
|
||||
await brain.close()
|
||||
if (fs.existsSync(testDir)) {
|
||||
fs.rmSync(testDir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
// Query WITH includeVFS: true
|
||||
it('includes VFS entities in brain.find() by default', async () => {
|
||||
// 8.0: VFS infrastructure entities are returned by default. The /docs/readme.md
|
||||
// file is a Document-typed entity carrying isVFS/vfsType markers, so a plain
|
||||
// type query surfaces BOTH it and the knowledge document.
|
||||
const results = await brain.find({
|
||||
type: NounType.Document,
|
||||
includeVFS: true,
|
||||
limit: 100
|
||||
})
|
||||
|
||||
console.log(` Total results: ${results.length}`)
|
||||
const vfsResults = results.filter(r => r.metadata?.isVFS === true)
|
||||
const knowledgeResults = results.filter(r => r.metadata?.isVFS !== true)
|
||||
const vfsResults = results.filter((r) => r.metadata?.isVFS === true)
|
||||
const knowledgeResults = results.filter((r) => r.metadata?.isVFS !== true)
|
||||
|
||||
console.log(` VFS results: ${vfsResults.length}`)
|
||||
console.log(` Knowledge results: ${knowledgeResults.length}`)
|
||||
|
||||
// Should return BOTH VFS and knowledge entities
|
||||
// Default find() shows the VFS file alongside knowledge.
|
||||
expect(vfsResults.length).toBeGreaterThan(0)
|
||||
expect(knowledgeResults.length).toBeGreaterThan(0)
|
||||
expect(results.some((r) => r.metadata?.title === 'AI Research Paper')).toBe(true)
|
||||
expect(results.some((r) => r.metadata?.vfsType === 'file')).toBe(true)
|
||||
})
|
||||
|
||||
it('excludes VFS entities when excludeVFS: true', async () => {
|
||||
// 8.0: excludeVFS drops the VFS infrastructure layer. Only knowledge entities remain.
|
||||
const results = await brain.find({
|
||||
type: NounType.Document,
|
||||
excludeVFS: true,
|
||||
limit: 100
|
||||
})
|
||||
|
||||
const vfsResults = results.filter((r) => r.metadata?.isVFS === true)
|
||||
const knowledgeResults = results.filter((r) => r.metadata?.isVFS !== true)
|
||||
|
||||
expect(vfsResults.length).toBe(0)
|
||||
expect(knowledgeResults.length).toBeGreaterThan(0)
|
||||
expect(results.some((r) => r.metadata?.title === 'AI Research Paper')).toBe(true)
|
||||
})
|
||||
|
||||
it('should allow relationships between VFS files and knowledge entities', async () => {
|
||||
console.log('\n📋 Test 3: VFS-Knowledge relationships')
|
||||
|
||||
// Get VFS file entity (need includeVFS: true when querying VFS by path)
|
||||
// Get VFS file entity. VFS files are identified by vfsType (the indexed,
|
||||
// queryable marker); they are included in find() by default.
|
||||
const vfsFile = await brain.find({
|
||||
where: {
|
||||
path: '/docs/readme.md'
|
||||
},
|
||||
includeVFS: true,
|
||||
limit: 1
|
||||
})
|
||||
expect(vfsFile.length).toBe(1)
|
||||
expect(vfsFile[0].metadata?.vfsType).toBe('file')
|
||||
|
||||
// Get knowledge entity
|
||||
const knowledgeEntity = await brain.find({
|
||||
|
|
@ -118,20 +121,20 @@ describe('VFS-Knowledge Separation (Option 3C)', () => {
|
|||
where: {
|
||||
title: 'AI Research Paper'
|
||||
},
|
||||
excludeVFS: true,
|
||||
limit: 1
|
||||
})
|
||||
expect(knowledgeEntity.length).toBe(1)
|
||||
|
||||
// Create relationship: knowledge entity -> references -> VFS file
|
||||
const relation = await brain.relate({
|
||||
// Create relationship: knowledge entity -> references -> VFS file.
|
||||
// relate() returns the new relation's id (string).
|
||||
const relationId = await brain.relate({
|
||||
from: knowledgeEntity[0].id,
|
||||
to: vfsFile[0].id,
|
||||
type: 'references'
|
||||
type: VerbType.References
|
||||
})
|
||||
|
||||
console.log(` Created relation: ${relation.id}`)
|
||||
console.log(` From: ${knowledgeEntity[0].metadata?.title} (knowledge)`)
|
||||
console.log(` To: ${vfsFile[0].metadata?.path} (VFS file)`)
|
||||
expect(typeof relationId).toBe('string')
|
||||
expect(relationId.length).toBeGreaterThan(0)
|
||||
|
||||
// Verify relationship exists
|
||||
const relations = await brain.related({
|
||||
|
|
@ -140,28 +143,24 @@ describe('VFS-Knowledge Separation (Option 3C)', () => {
|
|||
})
|
||||
|
||||
expect(relations.length).toBe(1)
|
||||
expect(relations[0].type).toBe('references')
|
||||
console.log(` ✅ Relationship verified: knowledge can reference VFS files`)
|
||||
expect(relations[0].type).toBe(VerbType.References)
|
||||
})
|
||||
|
||||
it('should filter VFS entities using where clause', async () => {
|
||||
console.log('\n📋 Test 4: Where clause filtering with isVFS')
|
||||
|
||||
// Query for VFS files explicitly
|
||||
// Query for VFS files explicitly via the vfsType marker (indexed + queryable).
|
||||
const vfsFiles = await brain.find({
|
||||
where: {
|
||||
isVFS: true,
|
||||
vfsType: 'file'
|
||||
},
|
||||
limit: 100
|
||||
})
|
||||
|
||||
console.log(` VFS files found: ${vfsFiles.length}`)
|
||||
expect(vfsFiles.length).toBeGreaterThan(0)
|
||||
expect(vfsFiles.every(f => f.metadata?.isVFS === true)).toBe(true)
|
||||
expect(vfsFiles.every(f => f.metadata?.vfsType === 'file')).toBe(true)
|
||||
expect(vfsFiles.every((f) => f.metadata?.vfsType === 'file')).toBe(true)
|
||||
// Every vfsType:'file' entity is a VFS infrastructure entity.
|
||||
expect(vfsFiles.every((f) => f.metadata?.isVFS === true)).toBe(true)
|
||||
|
||||
// Query for non-VFS entities explicitly
|
||||
// Query for non-VFS knowledge entities explicitly via a user metadata field.
|
||||
const nonVFS = await brain.find({
|
||||
where: {
|
||||
category: 'research'
|
||||
|
|
@ -169,39 +168,37 @@ describe('VFS-Knowledge Separation (Option 3C)', () => {
|
|||
limit: 100
|
||||
})
|
||||
|
||||
console.log(` Non-VFS entities found: ${nonVFS.length}`)
|
||||
expect(nonVFS.length).toBeGreaterThan(0)
|
||||
expect(nonVFS.every(e => e.metadata?.isVFS !== true)).toBe(true)
|
||||
expect(nonVFS.every((e) => e.metadata?.isVFS !== true)).toBe(true)
|
||||
expect(nonVFS.every((e) => e.metadata?.vfsType === undefined)).toBe(true)
|
||||
})
|
||||
|
||||
it('should handle semantic search with VFS filtering', async () => {
|
||||
console.log('\n📋 Test 5: Semantic search excludes VFS by default')
|
||||
|
||||
// Semantic search WITHOUT includeVFS (should exclude VFS files)
|
||||
const results = await brain.find({
|
||||
query: 'research paper artificial intelligence',
|
||||
// Self-retrieval: querying with the knowledge doc's own text returns it
|
||||
// (deterministic embedder ⇒ cosine 1.0). With excludeVFS the VFS layer is dropped.
|
||||
const knowledgeOnly = await brain.find({
|
||||
query: 'This is a knowledge document about AI',
|
||||
excludeVFS: true,
|
||||
limit: 10
|
||||
})
|
||||
expect(knowledgeOnly.length).toBeGreaterThan(0)
|
||||
expect(knowledgeOnly.some((r) => r.metadata?.isVFS === true)).toBe(false)
|
||||
expect(knowledgeOnly.some((r) => r.metadata?.title === 'AI Research Paper')).toBe(true)
|
||||
|
||||
console.log(` Semantic results: ${results.length}`)
|
||||
const hasVFS = results.some(r => r.metadata?.isVFS === true)
|
||||
console.log(` Contains VFS entities: ${hasVFS}`)
|
||||
|
||||
// Should NOT include VFS files in semantic search by default
|
||||
expect(hasVFS).toBe(false)
|
||||
|
||||
// Semantic search WITH includeVFS: true
|
||||
const resultsWithVFS = await brain.find({
|
||||
query: 'hello world markdown',
|
||||
includeVFS: true,
|
||||
// Default (no excludeVFS): self-retrieval of the VFS file by its own content
|
||||
// returns it — VFS entities participate in vector search by default.
|
||||
const withVFS = await brain.find({
|
||||
query: '# Hello World',
|
||||
limit: 10
|
||||
})
|
||||
expect(withVFS.some((r) => r.metadata?.path === '/docs/readme.md')).toBe(true)
|
||||
|
||||
console.log(` Semantic results (with VFS): ${resultsWithVFS.length}`)
|
||||
const hasVFSWithFlag = resultsWithVFS.some(r => r.metadata?.isVFS === true)
|
||||
console.log(` Contains VFS entities: ${hasVFSWithFlag}`)
|
||||
|
||||
// Should include VFS files when explicitly requested
|
||||
expect(hasVFSWithFlag).toBe(true)
|
||||
// excludeVFS on the vector path removes the VFS file even when its content matches.
|
||||
const withVFSExcluded = await brain.find({
|
||||
query: '# Hello World',
|
||||
excludeVFS: true,
|
||||
limit: 10
|
||||
})
|
||||
expect(withVFSExcluded.some((r) => r.metadata?.isVFS === true)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue