2026-06-19 10:13:04 -07:00
/ * *
* @module tests / unit / plugin - version - coupling
* @description Guards the brainy ↔ native - plugin version coupling ( audit P0 ) . A
* mismatched or failed accelerator must FAIL LOUD , never silently fall back to
* the default JS engine — that silent degrade was the # 1 cross - repo drift
* ( e . g . an old @soulcraft / cor running invisibly against brainy 8 . x ) . Covers :
* 1 . ` pluginRangeSatisfies ` ( the dep - free semver - range matcher , incl . RC tags )
* 2 . ` brainyRange ` mismatch → init throws
* 3 . activate ( ) throwing → init throws ( no swallow )
* 4 . the legacy provider - key cliff ( 'hnsw' but not 'vector' ) → init throws
* 5 . an explicitly - listed plugin that can ' t load → init throws
* 6 . a graceful decline ( activate ( ) → false ) → no throw , loud warn
* /
import { describe , it , expect } from 'vitest'
2026-06-29 10:03:38 -07:00
import { readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
import { dirname , join } from 'node:path'
2026-06-19 10:13:04 -07:00
import { Brainy } from '../../src/brainy.js'
2026-06-29 10:03:38 -07:00
import { getBrainyVersion } from '../../src/utils/version.js'
2026-06-19 10:13:04 -07:00
import { pluginRangeSatisfies , type BrainyPlugin , type BrainyPluginContext } from '../../src/plugin.js'
2026-06-29 10:03:38 -07:00
const PACKAGE_VERSION : string = JSON . parse (
readFileSync ( join ( dirname ( fileURLToPath ( import . meta . url ) ) , '../../package.json' ) , 'utf8' )
) . version
2026-06-19 10:13:04 -07:00
function memBrain ( ) : Brainy {
return new Brainy ( { requireSubtype : false , storage : { type : 'memory' } , silent : true } )
}
describe ( 'pluginRangeSatisfies (dep-free range matcher)' , ( ) = > {
it ( 'handles the comparator forms a brainyRange realistically uses' , ( ) = > {
expect ( pluginRangeSatisfies ( '8.0.0' , '>=8.0.0' ) ) . toBe ( true )
expect ( pluginRangeSatisfies ( '7.31.2' , '>=8.0.0' ) ) . toBe ( false )
expect ( pluginRangeSatisfies ( '8.4.1' , '>=8.0.0 <9.0.0' ) ) . toBe ( true )
expect ( pluginRangeSatisfies ( '9.0.0' , '>=8.0.0 <9.0.0' ) ) . toBe ( false )
expect ( pluginRangeSatisfies ( '8.2.0' , '^8.0.0' ) ) . toBe ( true )
expect ( pluginRangeSatisfies ( '9.0.0' , '^8.0.0' ) ) . toBe ( false )
expect ( pluginRangeSatisfies ( '8.0.0' , '=8.0.0' ) ) . toBe ( true )
expect ( pluginRangeSatisfies ( '8.0.1' , '=8.0.0' ) ) . toBe ( false )
} )
it ( 'tolerates a prerelease tag on the running version (RC builds satisfy a stable floor)' , ( ) = > {
// The lockstep ships as 8.0.0-rc1 — it MUST satisfy cor's `>=8.0.0` range.
expect ( pluginRangeSatisfies ( '8.0.0-rc1' , '>=8.0.0' ) ) . toBe ( true )
expect ( pluginRangeSatisfies ( '8.0.0-rc1' , '^8.0.0' ) ) . toBe ( true )
expect ( pluginRangeSatisfies ( '8.0.0-rc1' , '>=8.0.0 <9.0.0' ) ) . toBe ( true )
} )
it ( 'fails OPEN on a malformed range (never blocks a valid brain on a bad declaration)' , ( ) = > {
expect ( pluginRangeSatisfies ( '8.0.0' , 'not-a-range' ) ) . toBe ( true )
expect ( pluginRangeSatisfies ( '8.0.0' , '' ) ) . toBe ( true )
} )
} )
2026-06-29 10:03:38 -07:00
describe ( 'getBrainyVersion() — synchronously correct on first call' , ( ) = > {
it ( 'returns the real package version, not a stale build-time default' , ( ) = > {
// Regression: the version was read async, so the FIRST (synchronous) call —
// the one loadPlugins() makes to build context.version — returned a stale
// default ('3.14.0'), which fails any realistic cor 3.x `>=8.0.0` range and
// hard-rejects the matched native pairing on cold init. The sync read makes
// the first call correct.
const v = getBrainyVersion ( )
expect ( v ) . toBe ( PACKAGE_VERSION )
expect ( v ) . not . toBe ( '3.14.0' )
expect ( v ) . not . toBe ( '0.0.0' ) // the unknown-read sentinel must not surface in a real install
expect ( v . startsWith ( '8.' ) ) . toBe ( true )
} )
} )
2026-06-19 10:13:04 -07:00
/** A minimal fake plugin; `onActivate` lets a test register providers / throw. */
function fakePlugin (
name : string ,
opts : { brainyRange? : string ; onActivate ? : ( ctx : BrainyPluginContext ) = > boolean } = { }
) : BrainyPlugin {
return {
name ,
brainyRange : opts.brainyRange ,
async activate ( ctx ) {
return opts . onActivate ? opts . onActivate ( ctx ) : true
}
}
}
describe ( 'version coupling at init() — no silent fallback' , ( ) = > {
it ( 'throws when a plugin declares a brainyRange the running brainy is outside' , async ( ) = > {
const brain = memBrain ( )
brain . use ( fakePlugin ( '@fake/incompatible' , { brainyRange : '>=999.0.0' } ) )
await expect ( brain . init ( ) ) . rejects . toThrow ( /supports brainy|version-matched/ )
} )
it ( 'does NOT throw when the brainyRange is satisfied' , async ( ) = > {
const brain = memBrain ( )
brain . use ( fakePlugin ( '@fake/compatible' , { brainyRange : '>=0.0.0' } ) )
await expect ( brain . init ( ) ) . resolves . toBeUndefined ( )
await brain . close ( )
} )
2026-06-29 10:03:38 -07:00
it ( 'does NOT throw for a realistic cor 3.x range (^8.0.0) on a COLD init' , async ( ) = > {
// The actual regression: loadPlugins() is the first init step and makes the
// first getBrainyVersion() call, so a stale sync default would reject a
// correctly-matched native provider declaring the real 8.x range. A fresh
// brain registering a `^8.0.0` plugin must init cleanly.
const brain = memBrain ( )
brain . use ( fakePlugin ( '@fake/cor-3x' , { brainyRange : '^8.0.0' } ) )
await expect ( brain . init ( ) ) . resolves . toBeUndefined ( )
await brain . close ( )
} )
2026-06-19 10:13:04 -07:00
it ( 'throws (does not swallow) when activate() throws' , async ( ) = > {
const brain = memBrain ( )
brain . use ( fakePlugin ( '@fake/boom' , { onActivate : ( ) = > { throw new Error ( 'kaboom' ) } } ) )
await expect ( brain . init ( ) ) . rejects . toThrow ( /failed to activate|kaboom/ )
} )
it ( 'throws on the legacy provider-key cliff (registers hnsw but not vector)' , async ( ) = > {
const brain = memBrain ( )
brain . use ( fakePlugin ( '@fake/old-cor' , {
onActivate : ( ctx ) = > { ctx . registerProvider ( 'hnsw' , { } ) ; return true }
} ) )
await expect ( brain . init ( ) ) . rejects . toThrow ( /legacy vector provider|requires/ )
} )
it ( 'a graceful decline (activate()→false) is non-fatal — init succeeds on the default engine' , async ( ) = > {
// Decline is a documented, non-fatal path (brainy logs a loud warning and
// uses the default engine for that plugin's providers). The contract that
// matters here: it does NOT abort init the way a hard failure does.
const brain = memBrain ( )
brain . use ( fakePlugin ( '@fake/declines' , { onActivate : ( ) = > false } ) )
await expect ( brain . init ( ) ) . resolves . toBeUndefined ( )
await brain . close ( )
} )
it ( 'throws when an explicitly-listed plugin package cannot be loaded' , async ( ) = > {
const brain = new Brainy ( {
requireSubtype : false ,
storage : { type : 'memory' } ,
silent : true ,
plugins : [ '@soulcraft/this-package-does-not-exist-xyz' ]
} )
await expect ( brain . init ( ) ) . rejects . toThrow ( /could not be loaded|config\.plugins/ )
} )
} )