brainy/docs/QUERY_OPERATORS.md

299 lines
8 KiB
Markdown
Raw Permalink Normal View History

# Query Operators (BFO)
> Brainy Field Operators — the complete reference for `where` filters in `find()`.
All operators work with `find({ where: { ... } })` and filter on **metadata fields** (not `data`).
---
## Equality
| Operator | Alias | Description | Example |
|----------|-------|-------------|---------|
| `eq` | `equals` | Exact match | `{ status: { eq: 'active' } }` |
| `ne` | `notEquals` | Not equal | `{ status: { ne: 'deleted' } }` |
**Shorthand:** A bare value is treated as `equals`:
```typescript
// These are equivalent:
brain.find({ where: { status: 'active' } })
brain.find({ where: { status: { equals: 'active' } } })
```
---
## Comparison
| Operator | Alias | Description | Example |
|----------|-------|-------------|---------|
| `gt` | `greaterThan` | Greater than | `{ age: { gt: 18 } }` |
| `gte` | `greaterThanOrEqual` | Greater or equal | `{ score: { gte: 90 } }` |
| `lt` | `lessThan` | Less than | `{ price: { lt: 100 } }` |
| `lte` | `lessThanOrEqual` | Less or equal | `{ rating: { lte: 3 } }` |
| `between` | — | Inclusive range `[min, max]` | `{ year: { between: [2020, 2025] } }` |
```typescript
// Range query
const recent = await brain.find({
where: {
createdAt: { between: [Date.now() - 86400000, Date.now()] }
}
})
```
---
## Array / Set
| Operator | Alias | Description | Example |
|----------|-------|-------------|---------|
| `oneOf` | `in` | Value is one of the given options | `{ color: { oneOf: ['red', 'blue'] } }` |
| `noneOf` | — | Value is NOT one of the given options | `{ status: { noneOf: ['deleted', 'archived'] } }` |
| `contains` | — | Array field contains value | `{ tags: { contains: 'ai' } }` |
| `excludes` | — | Array field does NOT contain value | `{ tags: { excludes: 'spam' } }` |
| `hasAll` | — | Array field contains ALL listed values | `{ skills: { hasAll: ['js', 'ts'] } }` |
```typescript
// Find entities tagged with 'ai'
const aiEntities = await brain.find({
where: { tags: { contains: 'ai' } }
})
// Find entities of specific types
const people = await brain.find({
where: { noun: { oneOf: ['Person', 'Agent'] } }
})
```
---
## Existence
| Operator | Description | Example |
|----------|-------------|---------|
| `exists: true` | Field exists (has any value) | `{ email: { exists: true } }` |
| `exists: false` | Field does NOT exist | `{ email: { exists: false } }` |
| `missing: true` | Field does NOT exist (alias for `exists: false`) | `{ email: { missing: true } }` |
| `missing: false` | Field exists (alias for `exists: true`) | `{ email: { missing: false } }` |
```typescript
// Find entities that have an email field
const withEmail = await brain.find({
where: { email: { exists: true } }
})
```
---
## Pattern (In-Memory Only)
These operators work via the in-memory filter path. They are applied **after** the indexed query, so use them with other indexed operators for best performance.
| Operator | Description | Example |
|----------|-------------|---------|
| `matches` | Regex or string pattern match | `{ name: { matches: /^Dr\./ } }` |
| `startsWith` | String prefix | `{ name: { startsWith: 'John' } }` |
| `endsWith` | String suffix | `{ email: { endsWith: '@gmail.com' } }` |
```typescript
const doctors = await brain.find({
where: {
type: NounType.Person, // Indexed — fast
name: { startsWith: 'Dr.' } // In-memory — applied after
}
})
```
---
## Logical
Combine multiple conditions:
| Operator | Description | Example |
|----------|-------------|---------|
| `allOf` | ALL sub-filters must match (AND) | `{ allOf: [{ status: 'active' }, { role: 'admin' }] }` |
| `anyOf` | ANY sub-filter must match (OR) | `{ anyOf: [{ role: 'admin' }, { role: 'owner' }] }` |
| `not` | Invert a filter | `{ not: { status: 'deleted' } }` |
```typescript
// Complex OR query
const adminsOrOwners = await brain.find({
where: {
anyOf: [
{ role: 'admin' },
{ role: 'owner' }
]
}
})
// NOT query
const notDeleted = await brain.find({
where: {
not: { status: 'deleted' }
}
})
// Combined AND + OR
const results = await brain.find({
where: {
allOf: [
{ department: 'engineering' },
{ anyOf: [
{ level: 'senior' },
{ yearsExperience: { greaterThan: 5 } }
]}
]
}
})
```
---
## Indexed vs In-Memory Operators
Brainy's MetadataIndex supports a subset of operators natively for O(1) field lookups. Other operators fall back to in-memory filtering.
| Operator | MetadataIndex (Indexed) | In-Memory Fallback |
|----------|:-----------------------:|:------------------:|
| `equals` / `eq` | Yes | Yes |
| `notEquals` / `ne` | — | Yes |
| `greaterThan` / `gt` | Yes | Yes |
| `greaterThanOrEqual` / `gte` | Yes | Yes |
| `lessThan` / `lt` | Yes | Yes |
| `lessThanOrEqual` / `lte` | Yes | Yes |
| `between` | Yes | Yes |
| `oneOf` / `in` | Yes | Yes |
| `noneOf` | — | Yes |
| `contains` | Yes | Yes |
| `exists` / `missing` | Yes | Yes |
| `matches` | — | Yes |
| `startsWith` | — | Yes |
| `endsWith` | — | Yes |
| `allOf` | Partial | Yes |
| `anyOf` | Partial | Yes |
| `not` | — | Yes |
**Performance tip:** Combine indexed operators (equals, greaterThan, oneOf, between, contains, exists) with pattern operators for optimal speed — the index narrows results first, then patterns filter in memory.
---
## Practical Examples
### Filter by entity type
```typescript
// Using the type shorthand (recommended)
brain.find({ type: NounType.Person })
// Using where.noun directly
brain.find({ where: { noun: NounType.Person } })
// Multiple types
brain.find({ type: [NounType.Person, NounType.Agent] })
```
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:24:36 -07:00
### Filter by subtype
`subtype` is a top-level standard field — takes the column-store fast path, not the metadata fallback. Pair with `type` for the typical "Person who is an employee" query:
```typescript
// Equality on subtype:
brain.find({ type: NounType.Person, subtype: 'employee' })
// Set membership:
brain.find({ type: NounType.Person, subtype: ['employee', 'contractor'] })
// Operator-form predicates use `where`:
brain.find({
type: NounType.Person,
where: { subtype: { exists: true } }
})
```
See the **[Subtypes & Facets guide](./guides/subtypes-and-facets.md)** for the full surface.
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
### Filter relationships by subtype (7.30+)
Verbs are first-class peers — `related()` and graph traversal both honor subtype filters on the fast path:
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
```typescript
// Filter relationships by VerbType subtype
const direct = await brain.related({
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
from: ceoId,
type: VerbType.ReportsTo,
subtype: 'direct'
})
// Set membership on verb subtype
const all = await brain.related({
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
from: ceoId,
type: VerbType.ReportsTo,
subtype: ['direct', 'dotted-line']
})
// Graph traversal — subtype filters traversal edges (depth-1 in 7.30 JS path;
// multi-hop subtype filtering lands on Cortex native)
const reports = await brain.find({
connected: {
from: ceoId,
via: VerbType.ReportsTo,
subtype: 'direct',
depth: 1
}
})
```
### Combine semantic search with filters
```typescript
const results = await brain.find({
query: 'machine learning engineer', // Semantic search (on data)
type: NounType.Person, // Type filter (indexed)
where: {
department: 'engineering', // Exact match (indexed)
yearsExperience: { greaterThan: 3 } // Range filter (indexed)
},
limit: 10
})
```
### Temporal queries
```typescript
const lastWeek = Date.now() - 7 * 24 * 60 * 60 * 1000
const recentEntities = await brain.find({
where: {
createdAt: { greaterThan: lastWeek }
},
orderBy: 'createdAt',
order: 'desc',
limit: 50
})
```
### Graph + metadata combination
```typescript
const results = await brain.find({
connected: {
from: teamLeadId,
via: VerbType.WorksWith,
depth: 2
},
where: {
role: { oneOf: ['engineer', 'designer'] },
active: true
}
})
```
---
## See Also
- [Data Model](./DATA_MODEL.md) — Entity structure, data vs metadata
- [API Reference](./api/README.md) — Complete API documentation
- [Find System](./FIND_SYSTEM.md) — Natural language find() details