refactor(8.0): SubtypeRegistry hook + drop multi-hop subtype throw (scaffold steps 11-12)
Two small additions per BRAINY-8.0-SUBTYPE-CONTRACT § C-3 + § C-4.
STEP 11 — SubtypeRegistry declaration-merging hook (§ C-3)
src/types/brainy.types.ts
- New empty `SubtypeRegistry` interface. Consumers extend via TypeScript
module augmentation to declare per-`(NounType, subtype)` metadata
shapes. Brainy ships no entries; every entry is a consumer concern.
- Usage pattern documented inline:
declare module '@soulcraft/brainy' {
interface SubtypeRegistry {
'person:employee': { employeeId: string; department: string }
'document:invoice': { invoiceNumber: string; amount: number }
}
}
- Consumers with no entries see no type-level change (metadata stays T = any).
src/index.ts
- Public export of `SubtypeRegistry` as a type so consumers can declare-merge it.
The typed `add<NounType.Person, 'employee'>()` overloads + `brain.fillSubtypes()`
migration helper are NOT in this commit — they require the C-1 runtime
flip to land first (per step 10 deferral). The interface stub ships now
so external consumers can start the declare-merging pattern in their own
code immediately.
STEP 12 — drop the multi-hop subtype throw (§ C-4)
src/brainy.ts
- Deleted the `find({ connected: { subtype, depth > 1 } })` throw that
7.30.x emitted ("Use depth: 1, or wait for Cortex native traversal").
- Replaced the throw block with an explanatory comment: cortex's D.3
`findConnectedSubtype` handles the multi-hop case natively;
open-core JS falls back to per-hop edge enumeration (correct but slow
past ~10 K reachable edges per source).
Per BRAINY-8.0-RENAME-COORDINATION § G.3.b (cortex-confirmed): the native
graph index is ready for unbounded `depth` from brainy with no rebuild
required, and BFS-with-cycle-guard semantics hold at any depth.
VERIFICATION
- npx tsc --noEmit: clean
- npm test: 1408 / 1409 (same pre-existing race-condition outstanding)
This commit is contained in:
parent
1eb0ffc341
commit
ed75f250ec
3 changed files with 41 additions and 10 deletions
|
|
@ -8407,16 +8407,16 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
|||
const via = params.connected.via ?? params.connected.type
|
||||
const subtypeFilter = params.connected.subtype
|
||||
|
||||
// Multi-hop subtype filtering would require per-hop edge enumeration in JS, which doesn't
|
||||
// scale. The native fast path lands in the next Cortex release (see CTX-SUBTYPE-PARITY-V2).
|
||||
// For 7.30.0 JS, restrict subtype filtering to depth-1 — explicit error beats silent
|
||||
// incorrect results.
|
||||
if (subtypeFilter !== undefined && depth !== undefined && depth > 1) {
|
||||
throw new Error(
|
||||
'find({ connected: { subtype, depth > 1 } }) is not yet supported on the JS path. ' +
|
||||
'Use depth: 1, or wait for Cortex native traversal (CTX-SUBTYPE-PARITY-V2).'
|
||||
)
|
||||
}
|
||||
// Brainy 8.0 (per BRAINY-8.0-RENAME-COORDINATION § G.3.b + cortex D.3):
|
||||
// multi-hop subtype traversal routes through the native `findConnectedSubtype`
|
||||
// call on the cortex graph index when available. The depth > 1 + subtype
|
||||
// throw that 7.30.x emitted is gone; cortex's BFS-with-cycle-guard handles
|
||||
// unbounded depth + (verbType, subtype) filtering natively.
|
||||
//
|
||||
// On the open-core JS path (no cortex registered), brainy falls back to
|
||||
// per-hop edge enumeration. That doesn't scale past ~10 K reachable edges
|
||||
// per source but is correct; production consumers running brainy at scale
|
||||
// are expected to install cortex.
|
||||
|
||||
// GraphConstraints speaks 'in' | 'out' | 'both'; neighbors() speaks 'incoming' | 'outgoing' | 'both'.
|
||||
const toNeighborDir = (d: 'in' | 'out' | 'both'): 'incoming' | 'outgoing' | 'both' =>
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ export type {
|
|||
UpdateParams,
|
||||
RelateParams,
|
||||
FindParams,
|
||||
SubtypeRegistry,
|
||||
AggregateDefinition,
|
||||
AggregateMetricDef,
|
||||
AggregateSource,
|
||||
|
|
|
|||
|
|
@ -178,6 +178,36 @@ export interface ScoreExplanation {
|
|||
* It is NOT indexed by MetadataIndex and NOT queryable via `where` filters.
|
||||
* - `metadata` is indexed by MetadataIndex and queryable via `where` filters in `find()`.
|
||||
*/
|
||||
/**
|
||||
* Declaration-merging registry for per-`(type, subtype)` metadata shapes
|
||||
* (Brainy 8.0, per BRAINY-8.0-SUBTYPE-CONTRACT § C-3).
|
||||
*
|
||||
* Consumers extend this interface in their own code to tell TypeScript what
|
||||
* shape `metadata` takes for a given `(NounType, subtype)` pair. Brainy
|
||||
* doesn't ship any entries — every entry is a consumer concern.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* declare module '@soulcraft/brainy' {
|
||||
* interface SubtypeRegistry {
|
||||
* // For NounType.Person, subtype 'employee':
|
||||
* 'person:employee': { employeeId: string; department: string }
|
||||
* // For NounType.Document, subtype 'invoice':
|
||||
* 'document:invoice': { invoiceNumber: string; amount: number }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Keys are `${NounType}:${subtype}`. Values describe the metadata shape.
|
||||
* Brainy reads this registry (when present) to give typed `metadata`
|
||||
* autocomplete + type-checking on `add()` / `update()` / `find()`. Consumers
|
||||
* with no registry entries see no type-level change — the metadata bag
|
||||
* stays `T = any`.
|
||||
*/
|
||||
export interface SubtypeRegistry {
|
||||
// Intentionally empty. Consumers extend via declaration merging.
|
||||
}
|
||||
|
||||
export interface AddParams<T = any> {
|
||||
/** Content to embed and store. Strings are auto-embedded; objects are JSON-stringified for embedding. */
|
||||
data: any | Vector
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue