brainy/tests/unit/boundary-no-native.test.ts

100 lines
4.9 KiB
TypeScript
Raw Permalink Normal View History

/**
* @module tests/unit/boundary-no-native
* @description Enforces the open-source / proprietary boundary in CI: the public
* MIT Brainy repo must never DEPEND ON the proprietary native-acceleration
* package to build or test. That package is **`@soulcraft/cor`** (formerly
* `@soulcraft/cortex` both names are guarded here through the rename
* transition). Brainy may NAME it (docs say `npm install @soulcraft/cor`, error
* messages point at its `idSpace:'u64'` mode) and registering it through the
* public plugin API is the supported runtime path but nothing in `src/` or
* `tests/` may statically `import`/`require` it, and it must not appear in any
* dependency field.
*
* This is load-bearing for the lockstep release model: because brainy cannot
* depend on `@soulcraft/cor`, the combined brainy-8.0 × cor-3.0 integration
* matrix (the "every code path proven with both engines" proof) lives in the
* **cor** repo, which devDeps brainy NOT here. See handoff LOCKSTEP-VERIFY.
* If this test ever needs `@soulcraft/cor` to go green, the boundary has been
* violated and an optional integration became a hard coupling on a private build.
*/
import { describe, it, expect } from 'vitest'
import * as fs from 'node:fs'
import * as path from 'node:path'
import { fileURLToPath } from 'node:url'
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..')
const SELF = fileURLToPath(import.meta.url)
/** The proprietary native package, across the cortex→cor rename. */
const NATIVE_PACKAGES = ['@soulcraft/cor', '@soulcraft/cortex'] as const
/** Recursively collect .ts/.js/.mjs/.cjs files under a directory. */
function sourceFiles(dir: string): string[] {
const out: string[] = []
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
if (entry.name === 'node_modules' || entry.name === 'dist' || entry.name.startsWith('.')) continue
const full = path.join(dir, entry.name)
if (entry.isDirectory()) out.push(...sourceFiles(full))
else if (/\.(ts|js|mjs|cjs)$/.test(entry.name) && full !== SELF) out.push(full)
}
return out
}
// Matches a real module specifier for the native package in an
// import/require/dynamic-import — NOT a bare string mention (docs / JSDoc /
// error-message / mock-name are allowed). `@soulcraft/cor` and
// `@soulcraft/cortex` both match; `@soulcraft/core` (a different name) does not,
// because the package must be followed by a subpath separator or the closing quote.
const NATIVE_MODULE =
refactor(8.0): API-surface + quality polish from the readiness audit - find() search-mode: collapsed the two overlapping options to one canonical `searchMode: SearchMode` (the redundant `mode` alias was silently ignored on the primary find() path while honored on the historical path — a footgun) and removed the unwired `explain?` FindParams field (never read by find()). - Documentation accuracy on the public type surface: entity ids documented as UUID v7 (auto) / v5 (natural key), not v4; dropped the stale "Brainy 3.0" banners and "backward compatibility" hedging on the fresh-8.0 Result type; documented the via/type alias; removed the dead GraphConstraints.bidirectional; fixed the no-op `EmbeddedGraphVerb = Omit<GraphVerb,'source'>` to omit the real sourceId; corrected the GraphIndexProvider.isInitialized JSDoc; documented removeMany's per-chunk generation granularity; JSDoc'd the public VFS surface. - Honest perf comments in source: removed unmeasured billion-scale figures from the LSMTree / graphAdjacencyIndex headers (the JS fallback is in-memory after open; native is the scale path). - Robustness: getVerbMetadata propagates read errors symmetrically with getNounMetadata; the find() egress integrity-guard keeps a row when the JS matcher doesn't implement an operator the provider already matched on; hardened the boundary-no-native CI guard to catch side-effect imports + re-exports. - Tests: de-theatricalized a relateMany test to assert the real contract; fixed a stale Model-B header. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 10:04:19 -07:00
/(?:import\s[^'"]*from\s*|export\s[^'"]*from\s*|import\s*\(\s*|require\s*\(\s*|import\s*)['"]@soulcraft\/cor(?:tex)?(?:\/[^'"]*)?['"]/
describe('open/proprietary boundary — public repo must not depend on @soulcraft/cor', () => {
refactor(8.0): API-surface + quality polish from the readiness audit - find() search-mode: collapsed the two overlapping options to one canonical `searchMode: SearchMode` (the redundant `mode` alias was silently ignored on the primary find() path while honored on the historical path — a footgun) and removed the unwired `explain?` FindParams field (never read by find()). - Documentation accuracy on the public type surface: entity ids documented as UUID v7 (auto) / v5 (natural key), not v4; dropped the stale "Brainy 3.0" banners and "backward compatibility" hedging on the fresh-8.0 Result type; documented the via/type alias; removed the dead GraphConstraints.bidirectional; fixed the no-op `EmbeddedGraphVerb = Omit<GraphVerb,'source'>` to omit the real sourceId; corrected the GraphIndexProvider.isInitialized JSDoc; documented removeMany's per-chunk generation granularity; JSDoc'd the public VFS surface. - Honest perf comments in source: removed unmeasured billion-scale figures from the LSMTree / graphAdjacencyIndex headers (the JS fallback is in-memory after open; native is the scale path). - Robustness: getVerbMetadata propagates read errors symmetrically with getNounMetadata; the find() egress integrity-guard keeps a row when the JS matcher doesn't implement an operator the provider already matched on; hardened the boundary-no-native CI guard to catch side-effect imports + re-exports. - Tests: de-theatricalized a relateMany test to assert the real contract; fixed a stale Model-B header. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 10:04:19 -07:00
it('the detector catches every static-dependency form (incl. side-effect imports + re-exports)', () => {
// Each of these creates a hard dependency on the proprietary package and MUST
// be caught (the prior regex missed the bare side-effect import and re-export forms).
for (const form of [
`import cor from '@soulcraft/cor'`,
`import { x } from '@soulcraft/cor'`,
`import '@soulcraft/cor'`,
`import '@soulcraft/cor/native'`,
`export { x } from '@soulcraft/cor'`,
`export * from '@soulcraft/cor'`,
`const x = require('@soulcraft/cor')`,
`const x = await import('@soulcraft/cor')`,
`import x from '@soulcraft/cortex'`
]) {
expect(NATIVE_MODULE.test(form), `should detect: ${form}`).toBe(true)
}
// A different package whose name merely starts with the same prefix is NOT a match.
for (const ok of [`import x from '@soulcraft/core'`, `// see @soulcraft/cor docs`]) {
expect(NATIVE_MODULE.test(ok), `should NOT match: ${ok}`).toBe(false)
}
})
it('no src/ or tests/ file imports or requires the native package', () => {
const offenders: string[] = []
for (const dir of ['src', 'tests']) {
for (const file of sourceFiles(path.join(repoRoot, dir))) {
if (NATIVE_MODULE.test(fs.readFileSync(file, 'utf8'))) {
offenders.push(path.relative(repoRoot, file))
}
}
}
expect(offenders, `These files statically depend on the proprietary package — use the public plugin API at runtime instead:\n${offenders.join('\n')}`).toEqual([])
})
it('the native package is in no dependency field of package.json', () => {
const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8'))
const fields = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'] as const
const present: string[] = []
for (const field of fields) {
for (const native of NATIVE_PACKAGES) {
if (pkg[field] && Object.prototype.hasOwnProperty.call(pkg[field], native)) {
present.push(`${field}:${native}`)
}
}
}
expect(present, `The proprietary native package must not be a dependency (public CI must pass with it absent); found in: ${present.join(', ')}`).toEqual([])
})
})