brainy/docs/architecture/finite-type-system.md
David Snelling 2cdf70ee0f feat: subtype top-level field + trackField + migrateField
Promotes `subtype?: string` to a top-level standard field on every entity,
alongside `type` / `confidence` / `weight`. Flat string, no hierarchy — the
consumer-chosen vocabulary for sub-classifying entities within a NounType
(Person → employee/customer, Document → invoice/contract, etc.).

Layer 1 — subtype field + rollup
- HNSWNounWithMetadata.subtype + STANDARD_ENTITY_FIELDS entry
- Entity / Result / AddParams / UpdateParams / FindParams threading
- add()/update() persist subtype on storageMetadata + entityForIndexing
- get()/find() route through the standard-field fast path
- subtypeCountsByType (Map<NounTypeIdx, Map<subtype, count>>) on
  BaseStorage, mirrored after nounCountsByType with the same self-heal
  rebuild and persisted to _system/subtype-statistics.json
- brain.counts.bySubtype(type, subtype?) — O(1) point + breakdown
- brain.counts.topSubtypes(type, n) — top-N by count
- brain.subtypesOf(type) — distinct subtypes seen
- find({ type, subtype }) and find({ subtype: ['a','b'] }) on the fast path

Layer 2 — trackField for other facets
- brain.trackField(name, { perType?, values? }) registers a field for
  cardinality + per-NounType breakdown stats. Backed by the aggregation
  engine (auto-defines __fieldCounts__<name>), backfill-on-define applies.
- brain.counts.byField(name, { type? }) returns value frequencies
- Optional vocabulary whitelist rejects off-vocabulary writes at add/update

Layer 3 — generic migrateField
- brain.migrateField({ from, to, readBoth?, batchSize?, onProgress? })
  streams every entity, copies the value from one path to another, and
  (unless readBoth) clears the source. Supports top-level standard fields,
  metadata.X, and data.X paths. Idempotent — safe to re-run.

Docs
- New guide: docs/guides/subtypes-and-facets.md (Layer 1 + 2 + 3)
- README, DATA_MODEL, QUERY_OPERATORS, api/README, finite-type-system,
  quick-start all treat subtype as a core primitive with anonymous example
  vocabularies (employee/customer/invoice/milestone).

Tests
- 26 new integration tests covering write/read/update/delete round-trips,
  counts rollup decrement + re-route on mutation, trackField + byField
  with and without perType, vocabulary whitelist enforcement, and
  migrateField for metadata.X → subtype and data.X → subtype paths
  including readBoth deprecation-window semantics.

Unit suite: 1468/1468 passing. Type-check + build clean.
2026-06-04 17:25:28 -07:00

15 KiB
Raw Blame History

🎯 Brainy's Finite Noun/Verb Type System

Why Brainy's Finite Type System is Revolutionary for Knowledge Graphs at Billion Scale

Overview

Brainy introduces a finite type system that sits between traditional schemaless NoSQL and rigid relational databases. This approach unlocks unprecedented optimization opportunities while maintaining semantic flexibility.


The Three-Way Comparison

1. Traditional NoSQL (Schemaless)

// Complete freedom, zero optimization
{
  id: '123',
  randomField1: 'value',
  anotherWeirdKey: 42,
  whoKnowsWhatElse: { nested: 'chaos' }
}

Problems:

  • No index optimization possible
  • Tools can't understand data structure
  • Incompatible augmentations/extensions
  • Memory explosion with billions of unique keys
  • No semantic understanding
  • Query planning impossible

2. Traditional Relational (Rigid Schema)

CREATE TABLE entities (
  id UUID PRIMARY KEY,
  field1 VARCHAR(255),
  field2 INTEGER,
  ...
  field50 TEXT
);

Problems:

  • Must define schema upfront
  • Schema migrations are painful
  • Can't handle heterogeneous data
  • Requires restart for schema changes
  • Fixed columns waste space

3. Brainy's Finite Type System (Semantic Structure)

// Finite noun types (extensible but constrained)
type NounType =
  | 'person' | 'place' | 'organization' | 'document'
  | 'event' | 'concept' | 'thing' | ...

// Finite verb types (semantic relationships)
type VerbType =
  | 'relatedTo' | 'contains' | 'isA' | 'causedBy'
  | 'precedes' | 'influences' | ...

// Example usage
const entity = {
  id: '123',
  nounType: 'person',        // Finite! Known type
  vector: [...],             // Semantic embedding
  metadata: {
    noun: 'person',          // Required type field
    name: 'Alice',           // Custom fields allowed
    occupation: 'Engineer'   // Flexible metadata
  }
}

Benefits:

  • Index Optimization: Fixed-size Uint32Arrays for type tracking (99.76% memory reduction)
  • Semantic Understanding: Types have meaning, not just structure
  • Tool Compatibility: All augmentations understand core types
  • Concept Extraction: NLP can map text to known types
  • Explicit Types: Clear type specification in API
  • Query Optimization: Type-aware query planning
  • Flexible Metadata: Any fields within typed structure
  • Billion-Scale Ready: Type tracking scales linearly

Revolutionary Benefits in Detail

1. Index Optimization at Billion Scale

The Problem: Traditional NoSQL stores arbitrary field names in indexes:

// Memory explosion with unique keys
Map<string, Set<string>> {
  "user_preference_notification_email_enabled": Set(['id1', 'id2', ...]),
  "customer_shipping_address_line_1": Set(['id3', 'id4', ...]),
  // Billions of unique, unpredictable keys!
}

Brainy's Solution: Fixed noun/verb types enable fixed-size tracking:

// 99.76% memory reduction with Uint32Arrays
class TypeAwareMetadataIndex {
  // Fixed size: nounTypes × verbTypes × fieldCount
  private nounTypeBitmaps: RoaringBitmap32[]        // One per noun type
  private verbTypeBitmaps: RoaringBitmap32[]        // One per verb type

  // Example: 100 noun types × 50 verb types = 5KB overhead
  // vs 500MB+ for arbitrary keys!
}

Real-World Impact (PROJECTED - not yet benchmarked):

  • Before: 500MB memory for 1M entities with diverse keys
  • After: PROJECTED 1.2MB memory for same dataset (385x reduction - calculated from Uint32Array size, not measured)
  • Scales to billions: Memory grows with entity count, not key diversity

2. Explicit Type System

The Design: Specify types clearly in your API calls:

import { Brainy, NounType, VerbType } from '@soulcraft/brainy'

// Add entity with explicit type
await brain.add({
  data: { name: 'Alice', role: 'CEO of Acme Corp' },
  type: NounType.Person  // Explicit type specification
})

// Query with type filtering
await brain.find({
  query: 'Alice',
  type: NounType.Person  // Type-optimized search
})

Why Explicit Types?:

  1. Deterministic: You control exactly how entities are classified
  2. Predictable: No inference surprises or edge cases
  3. Fast: No neural processing overhead on every add/query
  4. Smaller: No embedded keyword models needed

Real-World Use Case:

// Import data with known types
await brain.add({
  data: { name: 'Apple Inc.', industry: 'Technology' },
  type: NounType.Organization
})

await brain.add({
  data: { name: 'Cupertino', country: 'USA' },
  type: NounType.Location
})

// Create relationship
await brain.relate({
  from: appleId,
  to: cupertinoId,
  type: VerbType.LocatedIn
})

3. Tool & Augmentation Compatibility

The Problem with Schemaless: Every tool must handle infinite variations:

// Incompatible tools
const tool1Data = { type: 'person', name: 'Alice' }
const tool2Data = { kind: 'human', fullName: 'Alice' }
const tool3Data = { entity_type: 'individual', person_name: 'Alice' }

// Tools can't understand each other!

Brainy's Solution: Finite types create a common language:

// All tools/augmentations understand core types
interface NounMetadata {
  noun: NounType  // Agreed-upon type system
  // ... custom fields
}

// Augmentation 1: Adds caching for 'person' entities
class PersonCacheAugmentation {
  execute(op, params) {
    if (params.noun?.metadata?.noun === 'person') {
      // All person entities are understood!
    }
  }
}

// Augmentation 2: Enriches 'organization' entities
class OrgEnrichmentAugmentation {
  execute(op, params) {
    if (params.noun?.metadata?.noun === 'organization') {
      // Fetch industry data, employees, etc.
    }
  }
}

// Augmentations compose seamlessly!

Ecosystem Benefits:

  • Third-party augmentations are interoperable
  • Type-specific optimizations are portable
  • Query builders understand semantic structure
  • Visualization tools render type-appropriate displays
  • Import/export tools map to universal types

4. Concept Extraction & NLP Integration

Traditional Approach: Extract entities, ignore types:

// Generic NER (Named Entity Recognition)
"Alice works at Google"
// → ['Alice', 'Google']  // What are these?

Brainy's Approach: Extract typed concepts:

import { NaturalLanguageProcessor } from '@soulcraft/brainy'

const nlp = new NaturalLanguageProcessor()
const concepts = await nlp.extractConcepts("Alice works at Google in San Francisco")

// Returns typed entities:
[
  { text: 'Alice', nounType: 'person', confidence: 0.95 },
  { text: 'Google', nounType: 'organization', confidence: 0.98 },
  { text: 'San Francisco', nounType: 'place', confidence: 0.92 }
]

// And typed relationships:
[
  {
    from: 'Alice',
    to: 'Google',
    verbType: 'worksAt',
    confidence: 0.88
  },
  {
    from: 'Google',
    to: 'San Francisco',
    verbType: 'locatedIn',
    confidence: 0.85
  }
]

Downstream Benefits:

  • Smart Clustering: Group by semantic type, not arbitrary keys
  • Type-Aware Queries: "Find all organizations in California"
  • Relationship Reasoning: "Who works at companies in SF?"
  • Automatic Ontology: Types form natural hierarchy

5. Query Optimization & Planning

The Problem: Schemaless queries are guesswork:

-- MongoDB: No idea what fields exist
db.collection.find({ someField: 'value' })
// Full collection scan!

Brainy's Solution: Type-aware query planning:

// Query planner knows types exist!
brain.find({
  where: { noun: 'person' }  // Type index lookup: O(1)!
})

// Multi-type queries are optimized
brain.find({
  where: {
    noun: ['person', 'organization'],  // Bitmap union
    location: 'California'              // Then filter
  }
})

// Relationship traversal is type-aware
brain.find({
  verb: 'worksAt',          // Verb type index
  sourceType: 'person',     // Source noun type index
  targetType: 'organization' // Target noun type index
})

Query Performance:

  • Type Filtering: O(1) bitmap intersection
  • Join Planning: Type-aware join order optimization
  • Index Selection: Automatic best index for type
  • Cardinality Estimation: Type statistics guide planning

6. Architecture & Development Benefits

Memory-Efficient Type Tracking

// Traditional approach: Map per field
class TraditionalIndex {
  private fieldIndexes: Map<string, Map<any, Set<string>>>
  // Memory: O(unique_fields × unique_values × entities)
}

// Brainy approach: Fixed Uint32Array per type
class TypeAwareIndex {
  private nounTypeTracking: Uint32Array  // Fixed size!
  private typeIndexes: RoaringBitmap32[] // One per type
  // Memory: O(noun_types) + O(entities_per_type)
  // PROJECTED: 385x smaller at billion scale (calculated from architecture, not benchmarked)
}

Type-Driven Code Organization

// Natural code structure follows types
/src
  /nouns
    /person
      personStorage.ts       // Type-specific storage
      personQueries.ts       // Type-specific queries
      personAugmentation.ts  // Type-specific logic
    /organization
      orgStorage.ts
      orgQueries.ts
      orgAugmentation.ts
  /verbs
    /worksAt
      worksAtValidation.ts   // Relationship rules
      worksAtInference.ts    // Type inference

Type Safety in TypeScript

// Compiler-enforced type correctness
function processPerson(noun: Noun) {
  if (noun.metadata.noun === 'person') {
    // TypeScript narrows type!
    const name: string = noun.metadata.name  // Safe access
  }
}

// Exhaustive type checking
function processNoun(noun: Noun) {
  switch (noun.metadata.noun) {
    case 'person': return handlePerson(noun)
    case 'place': return handlePlace(noun)
    case 'organization': return handleOrg(noun)
    // Compiler error if missing cases!
  }
}

Public API: Type System

The type system is fully public for developers and augmentation authors:

import {
  NounType,
  VerbType,
  getNounTypes,
  getVerbTypes,
  BrainyTypes,
  suggestType
} from '@soulcraft/brainy'

// Get all available noun types
const nounTypes = getNounTypes()
// → ['Person', 'Organization', 'Location', 'Thing', 'Concept', ...]

// Get all available verb types
const verbTypes = getVerbTypes()
// → ['RelatedTo', 'Contains', 'CreatedBy', 'LocatedIn', ...]

// Use types directly
await brain.add({
  data: { name: 'Alice' },
  type: NounType.Person
})

// Query by type
await brain.find({
  type: NounType.Person,
  where: { name: 'Alice' }
})

Use Cases:

  • Type-Safe Code: Use TypeScript enums for compile-time checking
  • Import Tools: Specify entity types during data import
  • Query Builders: Filter by known types
  • Augmentations: Type-specific processing pipelines
  • Visualization: Type-appropriate rendering

Real-World Performance Comparison

Scenario: 1 Billion Entities with Rich Metadata

Aspect NoSQL (Schemaless) Relational (Fixed) Brainy (Finite Types)
Memory (Indexes) 500GB+ 250GB 1.3GB
Type Lookup Full scan O(log n) O(1) bitmap
Add New Type Zero cost Schema migration! Register type
Query Planning Impossible Table statistics Type statistics
Tool Compatibility None SQL only Full ecosystem
Semantic Understanding None None Built-in
Concept Extraction Manual Manual Via SmartExtractor
Flexibility Infinite Zero Optimal balance

Design Principles

1. Finite but Extensible

// Core types are finite
const coreNounTypes = [
  'person', 'place', 'organization', 'thing', ...
]

// But easily extended
brain.registerNounType('chemical_compound', {
  keywords: ['molecule', 'compound', 'element'],
  synonyms: ['substance', 'material'],
  parentType: 'thing'
})

1a. Subtypes — sub-classification without hierarchy

The 42-type taxonomy is intentionally coarse. Per-product vocabulary fits on the subtype axis — a top-level standard string field on every entity. Flat by design — no hierarchy, no parent chain, no recursive resolution. That preserves the Uint32Array-backed O(1) type stats while giving consumers a place to put 'employee' / 'customer' / 'invoice' / 'milestone' without burning a slot in the global enum.

// Same NounType, different subtypes:
await brain.add({ type: NounType.Person,   subtype: 'employee' })
await brain.add({ type: NounType.Person,   subtype: 'customer' })
await brain.add({ type: NounType.Document, subtype: 'invoice'  })

// Fast path — column-store hit, not metadata fallback:
await brain.find({ type: NounType.Person, subtype: 'employee' })

// Per-NounType-per-subtype counts maintained incrementally:
brain.counts.bySubtype(NounType.Person)
// → { employee: 12, customer: 847 }

Subtype has its own statistics rollup (_system/subtype-statistics.json) maintained alongside nounCountsByType, so per-subtype counts stay O(1) at billion scale. Full guide: Subtypes & Facets.

2. Semantic not Structural

// NOT structural types
type Person = {
  name: string
  age: number
  // Fixed structure
}

// Semantic types
type Noun = {
  nounType: 'person',  // Semantic meaning!
  metadata: {
    noun: 'person',    // Required type
    // Any custom fields!
  }
}

3. Optimizable yet Flexible

// Optimized type tracking
const typeIndex = new RoaringBitmap32()  // 99.76% smaller!

// Flexible metadata
const metadata = {
  noun: 'person',          // Required type
  customField1: 'value',   // Your fields
  customField2: 123,       // Any structure
  nested: { ... }          // Full flexibility
}

Conclusion

Brainy's Finite Noun/Verb Type System is revolutionary because it achieves the impossible:

  1. Billion-scale performance (99.76% memory reduction)
  2. Semantic understanding (NLP integration)
  3. Tool compatibility (ecosystem interoperability)
  4. Query optimization (type-aware planning)
  5. Concept extraction (via SmartExtractor for imports)
  6. Developer experience (clean architecture)
  7. Flexibility (metadata freedom within types)

It's not schemaless chaos. It's not rigid relational constraints. It's semantic structure - the perfect balance for knowledge graphs at scale.


Further Reading


Brainy's finite type system: The foundation of billion-scale, semantically-aware knowledge graphs.