open-brainy/tests/conformance/collider-fidelity.test.ts

308 lines
11 KiB
TypeScript
Raw Normal View History

feat(namespace): NO SPECIAL NAMES + storage fidelity — the ruled completion of the field-addressing law The write side of the law, ruled 2026-08-03: data is either in main space where developers can use anything, or it is in system.*. - The reserved-name write door DIES: add/update/relate/updateRelation metadata bags accept EVERY name (confidence, type, id, data, level, content, ...) as ordinary user fields — indexed, filterable, sortable, aggregatable, identical to any other field. The remap/enforce/warn machinery, the reservedFieldPolicy config (now a typed init refusal), and the compile-time metadata key bans are all removed. The one write refusal left: keys spelled 'system.*' (namespace forgery), now enforced on all four write doors. - STORED RECORDS GO NESTED (v2): engine fields top-level, the user bag nested verbatim under 'metadata', sealed by a format stamp — by-name storage discrimination is unsound once colliders are admitted. Legacy flat records stay readable forever through the shape-aware splitters (sound for them: the old door refused colliders). Time travel rides the same split (generation store snapshots whole records). - Name-based index exclusions DIE: user frame indexes every name; the excludeFields/indexedFields knobs and their silent-[] holes are gone; bulk-payload protection is value-shape only, uniform across names. - Consumer-sweep findings fixed in the same wave: per-type counts read the frozen 'system.type' column (addToIndex sort, affinity tracking, cold-count rehydration, VFS type bitmaps — legacy 'noun' fallback for pre-rebuild reads); resolveHiddenIds addresses 'system.visibility' (bare 'visibility' was a silent no-op under the law — VFS/system entities leaked into default reads). - Fidelity fallout fixed in the owning layers: readEntityFieldAddress reads the bag first (colliders were absent-shadowed by its own guard) and never serves system addresses from the bag; blob history refs read the bag shape-aware; migration transforms now receive ONE normalized view (engine fields + nested bag) regardless of stored era, and stray flat-habit keys refuse with the fix in the message. - THE REOPEN-COLLIDER CONFORMANCE CASE (required before any RC counts as gates-green): all ten collider names + plumbing names written as user fields, verified verbatim + queryable across live reads, flush+reopen, a forced epoch rebuild, and asOf time travel; relation mirror; forgery refusals; legacy flat-record compat. 8/8 green. Gates: unit 1901/1901 (exit 0) · integration 758 (exit 0) · conformance 27/27 (exit 0) · consumer test sweep migrated (10 files).
2026-08-03 16:59:13 -07:00
/**
* @module tests/conformance/collider-fidelity
* @description THE REOPEN-COLLIDER CONFORMANCE CASE (required cross-engine
* before any RC counts as gates-green ruled 2026-08-03). The
* field-addressing law's fidelity half: user metadata may carry ANY name
* including every engine spelling (`confidence`, `type`, `id`, `createdAt`,
* ) and every plumbing name (`level`, `data`, `vector`, `_rev`) and the
* value survives, verbatim and reachable, across the FULL lifecycle: live
* reads, where/orderBy, flush, close+reopen, a forced epoch rebuild, and
* time travel. The engine scalars stay separately reachable at `system.*`
* the whole way. No halfway states.
*
* Self-arming like the namespace-law suite: skips loudly until the arming
* exports are present, so the suite can sit on a branch ahead of the build.
*/
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
import { mkdtempSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import * as brainyExports from '../../src/index.js'
import { Brainy, NounType, VerbType } from '../../src/index.js'
import {
BRAIN_FORMAT_PATH,
EXPECTED_INDEX_EPOCH
} from '../../src/storage/brainFormat.js'
const ARMED = 'UnresolvableFieldError' in brainyExports
const suite = ARMED ? describe : describe.skip
if (!ARMED) {
// eslint-disable-next-line no-console
console.warn(
'[collider-fidelity] SKIPPING: package root does not export the ' +
'field-addressing law surface yet (UnresolvableFieldError absent).'
)
}
/** Every entity system scalar name written as a USER metadata field, with
* unmistakable user values, plus the plumbing names and naturals. */
const COLLIDER_BAG = {
// the ten entity system scalars, as user fields
id: 'user-id',
type: 'user-type',
subtype: 'user-subtype',
createdAt: 'user-createdAt',
updatedAt: 'user-updatedAt',
confidence: 'user-confidence',
weight: 'user-weight',
visibility: 'user-visibility',
service: 'user-service',
createdBy: 'user-createdBy',
// plumbing names, as user fields
level: 7,
data: 'user-data',
vector: 'user-vector',
_rev: 'user-rev',
// naturals previously silently un-indexed by name
content: 'user-content',
// a plain control field
plain: 'control'
} as const
suite('collider fidelity — the reopen-collider case (both suites, ruled)', () => {
let dir: string
let brain: Brainy
let colliderId: string
const open = async (): Promise<Brainy> => {
const b = new Brainy({
storage: { type: 'filesystem', path: dir },
requireSubtype: false
})
await b.init()
return b
}
/** The full read battery — run at every lifecycle boundary. */
const verifyColliderTruth = async (label: string): Promise<void> => {
// 1. get(): the bag comes back verbatim; engine scalars stay engine.
const entity = await brain.get(colliderId)
expect(entity, `${label}: entity readable`).toBeTruthy()
for (const [k, v] of Object.entries(COLLIDER_BAG)) {
expect(
(entity!.metadata as Record<string, unknown>)[k],
`${label}: bag.${k} verbatim`
).toEqual(v)
}
expect(entity!.type, `${label}: engine type intact`).toBe(NounType.Document)
expect(entity!.confidence, `${label}: engine confidence intact`).toBe(0.25)
// 2. where on collider names (bare = the user's field, always).
for (const [k, v] of [
['confidence', 'user-confidence'],
['type', 'user-type'],
['id', 'user-id'],
['content', 'user-content'],
['data', 'user-data'],
['level', 7]
] as const) {
const rows = await brain.find({ where: { [k]: v }, limit: 10 })
expect(
rows.map((r) => r.id),
`${label}: where {${k}} finds the collider row`
).toContain(colliderId)
}
// 3. system.* keeps reading the ENGINE values.
const byEngine = await brain.find({
where: { 'system.confidence': 0.25 },
limit: 10
})
expect(
byEngine.map((r) => r.id),
`${label}: system.confidence reads the engine scalar`
).toContain(colliderId)
const byUserSpelledSystem = await brain.find({
where: { 'system.confidence': 'user-confidence' },
limit: 10
})
expect(
byUserSpelledSystem.map((r) => r.id),
`${label}: the user's value is NOT reachable via system.*`
).not.toContain(colliderId)
// 4. orderBy a collider name orders by the USER values.
const ordered = await brain.find({
type: NounType.Document,
orderBy: 'level',
order: 'desc',
limit: 10
})
expect(ordered.length, `${label}: ordered read complete`).toBe(3)
expect(
(ordered[0].metadata as Record<string, unknown>).plain,
`${label}: user level orders desc (7 first)`
).toBe('control')
}
beforeAll(async () => {
dir = mkdtempSync(join(tmpdir(), 'brainy-collider-'))
brain = await open()
colliderId = await brain.add({
data: 'the collider probe document',
type: NounType.Document,
confidence: 0.25,
metadata: { ...COLLIDER_BAG }
})
// two ordering companions with smaller user `level`s
await brain.add({
data: 'ordering companion low',
type: NounType.Document,
metadata: { level: 3, plain: 'low' }
})
await brain.add({
data: 'ordering companion mid',
type: NounType.Document,
metadata: { level: 5, plain: 'mid' }
})
}, 120000)
afterAll(async () => {
await brain.close().catch(() => {})
rmSync(dir, { recursive: true, force: true })
})
it('LIVE: colliders are the users, verbatim and fully queryable', async () => {
await verifyColliderTruth('live')
})
it('REOPEN: the restart boundary loses nothing', async () => {
await brain.flush()
await brain.close()
brain = await open()
await verifyColliderTruth('reopen')
})
it('REBUILD: a forced epoch rebuild re-indexes the colliders from canonical', async () => {
await brain.close()
// Simulate epoch drift: a missing marker forces the full derived-index
// rebuild at open — the exact path every pre-law brain takes once.
rmSync(join(dir, BRAIN_FORMAT_PATH), { force: true })
brain = await open()
await verifyColliderTruth('rebuild')
// And the rebuild re-stamps the current epoch.
const marker = await (
brain as unknown as {
storage: { readRawObject(p: string): Promise<{ indexEpoch?: number } | null> }
}
).storage.readRawObject(BRAIN_FORMAT_PATH)
expect(marker?.indexEpoch).toBe(EXPECTED_INDEX_EPOCH)
})
it('TIME TRAVEL: asOf reads historical collider values faithfully', async () => {
const gen = brain.generation()
await brain.update({ id: colliderId, metadata: { confidence: 'user-confidence-v2' } })
const now = await brain.get(colliderId)
expect((now!.metadata as Record<string, unknown>).confidence).toBe('user-confidence-v2')
const past = await brain.asOf(gen)
try {
const then = await past.get(colliderId)
expect(
(then!.metadata as Record<string, unknown>).confidence,
'asOf reads the pre-update USER value'
).toBe('user-confidence')
} finally {
await past.release()
}
// engine scalar untouched throughout
expect(now!.confidence).toBe(0.25)
})
it('RELATION MIRROR: edge collider bags survive write → read → reopen', async () => {
const a = await brain.add({ data: 'edge endpoint a', type: NounType.Person, metadata: { plain: 'a' } })
const b = await brain.add({ data: 'edge endpoint b', type: NounType.Person, metadata: { plain: 'b' } })
const edgeBag = {
verb: 'user-verb',
confidence: 'user-edge-confidence',
weight: 'user-edge-weight',
subtype: 'user-edge-subtype',
createdAt: 'user-edge-createdAt',
service: 'user-edge-service'
}
const relId = await brain.relate({
from: a,
to: b,
type: VerbType.RelatedTo,
confidence: 0.5,
metadata: { ...edgeBag }
})
const check = async (label: string): Promise<void> => {
const rels = await brain.related({ from: a, type: VerbType.RelatedTo })
const rel = rels.find((r) => r.id === relId)
expect(rel, `${label}: relation readable`).toBeTruthy()
for (const [k, v] of Object.entries(edgeBag)) {
expect(
(rel!.metadata as Record<string, unknown>)[k],
`${label}: edge bag.${k} verbatim`
).toEqual(v)
}
expect(rel!.confidence, `${label}: engine edge confidence intact`).toBe(0.5)
expect(rel!.type, `${label}: engine verb intact`).toBe(VerbType.RelatedTo)
}
await check('live')
await brain.flush()
await brain.close()
brain = await open()
await check('reopen')
})
it('FORGERY: user metadata keys spelled system.* refuse at every write door', async () => {
await expect(
brain.add({ data: 'forged', type: NounType.Document, metadata: { 'system.confidence': 1 } })
).rejects.toThrow(/system\./)
await expect(
brain.update({ id: colliderId, metadata: { 'system.type': 'x' } })
).rejects.toThrow(/system\./)
const a = await brain.add({ data: 'forgery endpoint a', type: NounType.Person, metadata: {} })
const b = await brain.add({ data: 'forgery endpoint b', type: NounType.Person, metadata: {} })
await expect(
brain.relate({ from: a, to: b, type: VerbType.RelatedTo, metadata: { 'system.verb': 'x' } })
).rejects.toThrow(/system\./)
})
it('CONFIG: the dead reservedFieldPolicy option refuses loudly, never ignored', () => {
expect(
() => new Brainy({ storage: { type: 'memory' }, reservedFieldPolicy: 'throw' } as never)
).toThrow(/field-addressing law/)
})
it('LEGACY: a pre-law flat record still reads with engine fields top-level', async () => {
const storage = (
brain as unknown as {
storage: {
saveNoun(n: unknown): Promise<void>
saveNounMetadata(id: string, m: Record<string, unknown>): Promise<void>
}
}
).storage
const legacyId = '00000000-0000-4000-8000-00000000f1a7'
await storage.saveNoun({ id: legacyId, vector: new Array(384).fill(0.01), connections: new Map(), level: 0 })
// Legacy FLAT shape: engine + user keys mixed at one level, NO _fmt stamp.
// Sound to split by name — the pre-law door refused user colliders.
await storage.saveNounMetadata(legacyId, {
noun: NounType.Document,
confidence: 0.75,
createdAt: 1700000000000,
updatedAt: 1700000000000,
_rev: 1,
legacyField: 'legacy-value'
})
const entity = await brain.get(legacyId)
expect(entity).toBeTruthy()
expect(entity!.confidence, 'legacy flat confidence = engine').toBe(0.75)
expect(
(entity!.metadata as Record<string, unknown>).legacyField,
'legacy custom field = user bag'
).toBe('legacy-value')
expect(
(entity!.metadata as Record<string, unknown>).confidence,
'legacy flat engine key never leaks into the bag'
).toBeUndefined()
})
})