refactor(8.0): strictConfig + brain.stats() vector field + wireConnectionsCodec feature-detect (scaffold step 5)

Step 5 of the brainy 8.0 rename scaffolding. Three small additions, all
honoring contracts locked in handoff thread BRAINY-8.0-RENAME-COORDINATION:

A. strictConfig: boolean | 'warn'  (§ B.6)

src/types/brainy.types.ts
- New BrainyConfig.strictConfig field. Three tiers:
  - false: no enforcement (knob mismatches silently accepted)
  - 'warn' (8.0 default): one-shot warning per call site listing
    ignored knobs + escape-valve recipe + docs link
  - true: hard error at init()
- Format matches the 7.30.1 teaching-error pattern (problem → escape
  valves → caller location → docs link).
- Applies to ALL provider knob mismatches, not just vector (e.g.
  config.aggregation.x with no aggregation provider).

src/brainy.ts
- normalizeConfig() defaults to 'warn'. Wiring into the actual
  enforcement sites lands in the final cleanup commit alongside the
  removal of legacy knob names.

B. brain.stats().indexHealth.vector  (§ planning § 2.6)

src/types/brainy.types.ts
- BrainyStats.indexHealth gains a new `vector: boolean` field. Existing
  `hnsw: boolean` field marked @deprecated; same boolean, kept as a
  compat alias until the final cleanup.

src/brainy.ts:6272
- Implementation populates both `hnsw` and `vector` from the same
  `vectorHealthy` boolean. Refactored to async IIFE so the graph-size
  await sits cleanly alongside the new field.

C. wireConnectionsCodec feature-detect  (integration doc lines 459-461)

src/brainy.ts:9469-9486
- Added `typeof this.index.setConnectionsCodec === 'function'` guard
  before invoking. Native vector-index providers (DiskANN-style) persist
  the graph as a single mmap'd file with no per-node connection lists
  and have no analogue. Pre-8.0 the wire was unconditional and relied
  on the native wrapper exposing a no-op method; 8.0 makes it
  feature-detected.

NO-OP scope

No behavioural change in scaffolding. brain.stats() now returns both
field names (callers see the new field but the old still works).
strictConfig is defaulted but not yet enforced. wireConnectionsCodec
behaves identically when called against an impl that has the codec
method (the JS HNSW path); guards cleanly against impls that don't.

VERIFICATION

- npx tsc --noEmit: clean
- npm test: 1468 / 1468 unit
This commit is contained in:
David Snelling 2026-06-09 13:12:39 -07:00
parent 356f044d2a
commit 3e1ef957bc
2 changed files with 49 additions and 5 deletions

View file

@ -6269,11 +6269,18 @@ export class Brainy<T = any> implements BrainyInterface<T> {
relationCount, relationCount,
relationsByType, relationsByType,
fieldRegistry, fieldRegistry,
indexHealth: { indexHealth: await (async () => {
hnsw: this.index.size() > 0 || entityCount === 0, // 8.0 rename: `vector` is the canonical name; `hnsw` is a compat
metadata: metadataStats.totalEntries > 0 || entityCount === 0, // alias that's removed in the final 8.0 cleanup commit.
graph: (await this.graphIndex.size()) > 0 || relationCount === 0 const vectorHealthy = this.index.size() > 0 || entityCount === 0
}, const graphSize = await this.graphIndex.size()
return {
hnsw: vectorHealthy,
vector: vectorHealthy,
metadata: metadataStats.totalEntries > 0 || entityCount === 0,
graph: graphSize > 0 || relationCount === 0
}
})(),
storage: { storage: {
backend: storageBackend, backend: storageBackend,
rootDir: typeof rootDir === 'string' ? rootDir : undefined rootDir: typeof rootDir === 'string' ? rootDir : undefined
@ -9304,6 +9311,9 @@ export class Brainy<T = any> implements BrainyInterface<T> {
// { except: [...] }: strict, but listed types may omit subtype. // { except: [...] }: strict, but listed types may omit subtype.
// Becomes the default in 8.0.0. // Becomes the default in 8.0.0.
requireSubtype: config?.requireSubtype ?? false, requireSubtype: config?.requireSubtype ?? false,
// Provider-knob mismatch strictness (8.0). Default is 'warn' (one-shot
// teaching message). See BRAINY-8.0-RENAME-COORDINATION § B.6.
strictConfig: config?.strictConfig ?? 'warn',
// Multi-process safety // Multi-process safety
mode: config?.mode ?? 'writer', mode: config?.mode ?? 'writer',
force: config?.force ?? false force: config?.force ?? false
@ -9464,6 +9474,13 @@ export class Brainy<T = any> implements BrainyInterface<T> {
const idMapper = this.metadataIndex.getIdMapper?.() const idMapper = this.metadataIndex.getIdMapper?.()
if (!idMapper) return if (!idMapper) return
// Feature-detect: only the JS HNSW path uses per-node connection lists.
// Native vector-index providers (DiskANN-style) persist the graph as a
// single mmap'd file and have no analogue, so skip the wiring there.
// Pre-8.0 the wire was unconditional and relied on the native wrapper
// exposing a no-op setConnectionsCodec(); 8.0 makes it feature-detected.
if (typeof (this.index as { setConnectionsCodec?: unknown }).setConnectionsCodec !== 'function') return
const codec = new ConnectionsCodec(provider, idMapper) const codec = new ConnectionsCodec(provider, idMapper)
this.index.setConnectionsCodec(codec) this.index.setConnectionsCodec(codec)
if (!this.config.silent) { if (!this.config.silent) {

View file

@ -1031,7 +1031,10 @@ export interface BrainyStats {
fieldRegistry: string[] fieldRegistry: string[]
/** Per-index health flags. `true` = index has entries OR no entities exist yet. */ /** Per-index health flags. `true` = index has entries OR no entities exist yet. */
indexHealth: { indexHealth: {
/** @deprecated 8.0 — renamed to `vector`. Same boolean; kept as a compat alias until the final 8.0 cleanup. */
hnsw: boolean hnsw: boolean
/** Vector index health (8.0 name — open-core JS HNSW path or a native acceleration provider). */
vector: boolean
metadata: boolean metadata: boolean
graph: boolean graph: boolean
} }
@ -1246,6 +1249,30 @@ export interface BrainyConfig {
*/ */
requireSubtype?: boolean | { except: Array<import('../types/graphTypes.js').NounType | import('../types/graphTypes.js').VerbType> } requireSubtype?: boolean | { except: Array<import('../types/graphTypes.js').NounType | import('../types/graphTypes.js').VerbType> }
/**
* Validation strictness for provider-knob mismatches (Brainy 8.0).
*
* When a registered provider silently ignores a configuration knob the
* user passed (e.g. `config.vector.advanced.diskann.*` on the open-core JS
* HNSW path, or `config.vector.advanced.hnsw.*` on a native DiskANN-style
* path), the user otherwise gets no feedback that their override has no
* effect. This option controls the response:
*
* - `false` no enforcement. Mismatched knobs are silently accepted.
* - `'warn'` (default in 8.0) one-shot warning per call site via
* `prodLog.warn`, listing the ignored knobs and the docs link to the
* appropriate `advanced.*` escape hatch.
* - `true` hard error at `init()`. Refuses to start until the config
* is consistent with the resolved provider impl.
*
* The warning / error format matches the 7.30.1 teaching-error pattern:
* problem escape valves caller location docs link.
*
* **Contract** locked in handoff thread BRAINY-8.0-RENAME-COORDINATION
* § B.6 (cortex-confirmed 2026-06-09).
*/
strictConfig?: boolean | 'warn'
/** /**
* Process role for multi-process safety on filesystem storage. * Process role for multi-process safety on filesystem storage.
* *