brainy/docs/architecture/finite-type-system.md
David Snelling c0d326b36d feat: verb subtype + updateRelation + requireSubtype enforcement
Brings verbs to first-class parity with nouns. The 7.29.0 subtype primitive
shipped for entities only; this release ships the symmetric verb mirror plus
the enforcement layer for ensuring every entity AND every relationship has
both type AND subtype.

Layer V1 — verb subtype mirror
- HNSWVerbWithMetadata.subtype + STANDARD_VERB_FIELDS set + resolveVerbField()
- Relation<T>.subtype, RelateParams<T>.subtype, UpdateRelationParams<T> extended,
  GetRelationsParams.subtype, GraphConstraints.subtype (for find connected)
- relate() persists subtype on verbMetadata + GraphVerb + transaction ops
- getRelations({ type, subtype }) fast-path filter with set membership
- find({ connected: { via, subtype, depth } }) traversal filter (depth-1 on
  the JS path; explicit error on depth > 1 pointing at Cortex native)
- verbsToRelations + storage destructure sites surface subtype to top-level
- All three graph-index fast-path queries (getVerbsBySource/ByTarget) enrich
  with subtype from metadata

Layer V2 — updateRelation() closes a pre-7.30 gap
- New first-class verb update method (parallel to update() for nouns)
- Changes subtype/type/weight/confidence/data/metadata in place
- Re-indexes in graph adjacency when verb type changes; id preserved
- validateUpdateRelationParams enforces id + at-least-one-field-to-update

Layer V3 — verb subtype storage rollup
- verbSubtypeCountsByType: Map<number, Map<string, number>> on BaseStorage
- verbSubtypeByIdCache for self-heal during update/delete
- incrementVerbSubtypeCount + decrementVerbSubtypeCount maintain state
- loadVerbSubtypeStatistics + saveVerbSubtypeStatistics persist to
  _system/verb-subtype-statistics.json (mirrors noun-side shape)
- rebuildVerbSubtypeCounts for poison recovery / explicit repair
- getVerbSubtypeCountsByType accessor for the public counts API
- Wired into init() / flushCounts() / saveVerbMetadata / deleteVerbMetadata

Layer V4 — verb counts API + relationshipSubtypesOf
- brain.counts.byRelationshipSubtype(verb, subtype?) — O(1) breakdown or point
- brain.counts.topRelationshipSubtypes(verb, n) — top N by count
- brain.relationshipSubtypesOf(verb) — sorted distinct subtypes

Layer V5 — migrateField extended to verbs
- New entityKind?: 'noun' | 'verb' | 'both' option (default 'noun')
- Mirror verb iteration via storage.getVerbs() with same path semantics
- verbToRelationLike + buildRelationMigrationUpdate helpers project the
  storage verb shape onto the Entity<T>-shaped surface readPath understands
- Routes through new updateRelation() for the verb-side rewrite

Enforcement (opt-in in 7.30, default in 8.0)
- brain.requireSubtype(type, options) — unified API for NounType OR VerbType.
  Registers per-type rules with optional values whitelist; composes with the
  brain-wide flag.
- new Brainy({ requireSubtype: true }) — brain-wide strict mode. Every public
  write path validates the pairing guarantee.
- { except: [NounType.Thing, ...] } form for catch-all type exemptions
- Atomic-fail semantics on addMany / relateMany — pre-validate every item
  before any storage write, throw on first failure with item index
- Per-type rules + brain-wide flag both throw with descriptive messages
- VFS infrastructure bypass via metadata.isVFSEntity / isVFS markers so
  brain's own VFS writes don't get rejected when strict mode is on

VFS labeling — concrete subtypes for infrastructure entities
- VFS root: NounType.Collection + subtype: 'vfs-root' (was bare Collection)
- VFS directories: subtype: 'vfs-directory'
- VFS files: subtype: 'vfs-file' (NounType still mime-based)
- VFS containment edges: VerbType.Contains + subtype: 'vfs-contains'
- Lets consumers cleanly enumerate VFS state via find({ subtype: 'vfs-file' })
  and distinguish Brainy's VFS Collections from user-created Collections

Docs
- docs/guides/subtypes-and-facets.md extended with Layer V (Verbs) section +
  Enforcement section. New full reference at the bottom split into Layer 1
  (nouns), Layer V (verbs), Layer 2 (facets), Layer 3 (migration), Enforcement.
- docs/api/README.md adds updateRelation(), getRelations({ subtype }), the
  three verb-side counts methods, requireSubtype(), and the brain-wide
  constructor option. relate() params include subtype.
- docs/DATA_MODEL.md adds a Subtype-for-VerbType section + STANDARD_VERB_FIELDS
- docs/architecture/finite-type-system.md extends Principle 1a to verbs
- docs/QUERY_OPERATORS.md adds a verb-subtype filter section covering
  getRelations and find({connected, subtype}) traversal
- README.md "Subtypes" section now shows both noun + verb in one example +
  the enforcement APIs
- RELEASES.md v7.30.0 entry with the full noun/verb capability parity matrix

Tests
- tests/integration/verb-subtype-and-enforcement.test.ts — 30 new tests
  covering V1 round-trips, V1 set membership, updateRelation in place,
  updateRelation preservation, V2 counts breakdown + point + topN + distinct,
  V2 decrements on unrelate, V2 re-routes on updateRelation, V3 depth-1
  traversal filter, V3 depth>1 explicit error, V4 verb migration, V4 both
  entity kinds, V4 readBoth preservation, V5 per-type required rejection,
  V5 vocabulary rejection, V5 on-vocab acceptance, V5 verb-side enforcement,
  V5 addMany atomic-fail, V5 relateMany atomic-fail, V5 update enforcement,
  V5 updateRelation enforcement, V5 brain-wide strict mode, V5 except clause.

Verification
- Unit suite: 1468/1468 passing
- Noun subtype integration (7.29 carryover): 26/26 passing
- Verb subtype + enforcement integration: 30/30 passing
- Type-check: clean
- Build: clean
- Public closed-source reference audit: clean

Internal 8.0 spec
- .strategy/BRAINY-8.0-SUBTYPE-CONTRACT.md (gitignored, not in npm artifact)
  documents the contract upgrade Cortex 3.0 implements against: required-by-
  default subtype, SubtypeRegistry typing hook, native simplification,
  multi-hop traversal native fast path, brain.fillSubtypes() migration helper.
  Coordinated via PLATFORM-HANDOFF rows CTX-SUBTYPE-PARITY-V2 (7.30 parallel
  work) and CTX-SUBTYPE-8.0-CONTRACT (8.0 spec).
2026-06-05 11:15:52 -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.

The same principle applies to VerbTypes (7.30+): the 127-verb taxonomy is intentionally coarse, and subtype is the per-product axis for relationships too. A ReportsTo relationship might carry subtype: 'direct' vs 'dotted-line'; a RelatedTo edge might carry 'spouse' / 'colleague'. Verb-side rollup lives at _system/verb-subtype-statistics.json with identical shape to the noun-side rollup. Per-VerbType-per-subtype counts are O(1) via brain.counts.byRelationshipSubtype(). Brainy's design is fully symmetric — nouns and verbs are first-class peers with identical capability surfaces.

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.