brainy/src/aggregation/materializer.ts

219 lines
6.5 KiB
TypeScript
Raw Normal View History

/**
* AggregateMaterializer - Writes aggregate results as NounType.Measurement entities
*
* Converts aggregate group states into Brainy entities that are automatically
* visible in OData, Google Sheets, SSE, and webhook integrations.
*
* Uses debouncing to avoid excessive writes during high-throughput ingestion.
*/
import type { NounType } from '../types/graphTypes.js'
import type {
AggregateDefinition,
AggregateGroupState,
AggregateMetricDef
} from '../types/brainy.types.js'
import { serializeGroupKey } from './AggregationIndex.js'
/**
* Callback interface for the materializer to create/update Brainy entities.
* This avoids a direct dependency on the Brainy class (breaks circular deps).
*/
export interface MaterializerBrainAccess {
add(params: {
data: string
type: NounType
fix: internal subtype consistency + brain.audit() diagnostic + improved enforcement errors Brainy 7.30 shipped opt-in subtype enforcement; SDK 3.20.0 then registered SDK_CORE_VOCABULARY on every consumer's brain (Event, Collection, Message, Contract, Media, Document NounTypes). On 2026-06-08 Venue's /book flow went 500 because their brain.add({ type: NounType.Event, ... }) call sites lacked subtype. An audit of Brainy's OWN source revealed 14 HIGH-risk internal write paths that also omit subtype — any consumer running the same vocabulary would have hit Brainy's infrastructure paths next. 7.30.1 closes both gaps before 8.0 makes strict mode the default. Additive across the board. Zero behavior change for consumers not using strict mode. Every change is JS-side — Cortex needs no work for 7.30.1. NEW — brain.audit() diagnostic - Read-only method walking storage.getNouns() / getVerbs() pagination - Returns { entitiesWithoutSubtype: { type: count }, relationshipsWithoutSubtype, total, scanned, recommendation } - VFS infrastructure entities excluded by default (they bypass enforcement via isVFSEntity marker); pass { includeVFS: true } to surface them - The companion to migrateField (7.x) and fillSubtypes (8.0): tells consumers exactly what would break under strict enforcement, deterministically NEW — Improved enforcement error messages - Caller's source location extracted from Error().stack so users see their own call site, not a Brainy internal frame - Specific guidance branches: registered vocabulary → "Pass one of: a, b, c"; brain-wide strict mode → mentions the except clause; otherwise → registration recipe via brain.requireSubtype() - Documentation link to the canonical migration recipe - Same shape for noun and verb enforcement NEW — CLI --subtype flag - brainy add and brainy relate gain -s/--subtype <value> - Defaults to 'cli-add' / 'cli-relate' so the CLI works against strict-mode brains without the user needing to know the vocabulary in advance INTERNAL — every Brainy write path now sets subtype - VFS Contains edges (5 sites at lines 503/905/1694/1772/1886) → 'vfs-contains' - VFS symlink entity → 'vfs-symlink' (NEW — distinct from 'vfs-file') - VFS copy-file → preserves source subtype, falls back to 'vfs-file' - VFS symlink also adopts the isVFSEntity infrastructure marker so it bypasses enforcement in strict mode - Aggregation materializer (Measurement entities) → 'materialized-aggregate' - ImportCoordinator (3 sites): document → 'import-source'; entities → options.defaultSubtype ?? 'imported'; placeholder → 'import-placeholder' - SmartImportOrchestrator (4 entity sites + 2 batch relate sites): same precedence (extractor → options.defaultSubtype → 'imported') - EntityDeduplicator → candidate.subtype ?? 'imported' - UniversalImportAPI → extractor → 'extracted' for both entities and relations - NeuralImport → adds defaultSubtype to NeuralImportOptions; precedence same - GoogleSheetsIntegration → request body 'subtype' ?? 'imported-from-sheets' - ODataIntegration → request body 'Subtype' ?? 'imported-from-odata' - MCP client message storage → 'mcp-message' (also fixes pre-existing missing data field and missing type by aliasing from the prior text field) Side-effect fix: storage.getNouns() paginated now surfaces subtype to top-level - Single-noun getNoun() already did this in 7.30; the paginated path was missed - Without this fix brain.audit() saw missing subtype on entities that actually had one (caught by the strict-mode self-test before release) NEW — tests/integration/strict-mode-self-test.test.ts (13 tests) - Creates a brain under the exact SDK_CORE_VOCABULARY shape Venue hit + brain- wide strict mode - Exercises every internal Brainy path: VFS root + mkdir + writeFile + cp + mv + ln + symlink; aggregation engine; audit diagnostic with includeVFS toggle - Validates error message UX: caller location, vocabulary guidance, brain-wide strict mode guidance, off-vocabulary value reporting Docs - New "Strict mode in practice" section in docs/guides/subtypes-and-facets.md covering the SDK_CORE_VOCABULARY pattern, 4-step migration recipe (audit → migrateField → hand-fix → re-audit), the Brainy-internal label reference table, and an 8.0 forward-look on fillSubtypes() - docs/api/README.md: new audit() entry, strict-mode tips on add() and relate() - RELEASES.md: full 7.30.1 entry Cortex parity (forward-looking, not blocking 7.30.1) - 6th open question added to .strategy/BRAINY-8.0-SUBTYPE-CONTRACT.md: native fast path for audit() and fillSubtypes() via column-store null-subtype bitmap for billion-scale brains - Cortex should add a parity test mirroring strict-mode-self-test.test.ts against their native paths to catch any latent bug where native writes bypass JS validation - Brainy-internal subtype labels become a documented part of the 8.0 contract (useful for Cortex telemetry surfacing Brainy-managed infrastructure %) Verification - npx tsc --noEmit: clean - npm test: 1468/1468 unit - 7.29 noun integration suite: 26/26 (no regression) - 7.30 verb subtype + enforcement integration suite: 30/30 (no regression) - New strict-mode-self-test integration suite: 13/13 - npm run build: clean - Closed-source product reference audit: clean Addresses VE-SUBTYPE-MIGRATION (Venue's reported request) and ships internal labels Venue did NOT ask for but that would have broken them next under their own vocabulary registration.
2026-06-08 11:31:47 -07:00
/** Sub-classification of the materialized entity (7.30.1+). */
subtype?: string
metadata: Record<string, unknown>
id?: string
service?: string
}): Promise<string>
update(params: {
id: string
data?: string
fix: internal subtype consistency + brain.audit() diagnostic + improved enforcement errors Brainy 7.30 shipped opt-in subtype enforcement; SDK 3.20.0 then registered SDK_CORE_VOCABULARY on every consumer's brain (Event, Collection, Message, Contract, Media, Document NounTypes). On 2026-06-08 Venue's /book flow went 500 because their brain.add({ type: NounType.Event, ... }) call sites lacked subtype. An audit of Brainy's OWN source revealed 14 HIGH-risk internal write paths that also omit subtype — any consumer running the same vocabulary would have hit Brainy's infrastructure paths next. 7.30.1 closes both gaps before 8.0 makes strict mode the default. Additive across the board. Zero behavior change for consumers not using strict mode. Every change is JS-side — Cortex needs no work for 7.30.1. NEW — brain.audit() diagnostic - Read-only method walking storage.getNouns() / getVerbs() pagination - Returns { entitiesWithoutSubtype: { type: count }, relationshipsWithoutSubtype, total, scanned, recommendation } - VFS infrastructure entities excluded by default (they bypass enforcement via isVFSEntity marker); pass { includeVFS: true } to surface them - The companion to migrateField (7.x) and fillSubtypes (8.0): tells consumers exactly what would break under strict enforcement, deterministically NEW — Improved enforcement error messages - Caller's source location extracted from Error().stack so users see their own call site, not a Brainy internal frame - Specific guidance branches: registered vocabulary → "Pass one of: a, b, c"; brain-wide strict mode → mentions the except clause; otherwise → registration recipe via brain.requireSubtype() - Documentation link to the canonical migration recipe - Same shape for noun and verb enforcement NEW — CLI --subtype flag - brainy add and brainy relate gain -s/--subtype <value> - Defaults to 'cli-add' / 'cli-relate' so the CLI works against strict-mode brains without the user needing to know the vocabulary in advance INTERNAL — every Brainy write path now sets subtype - VFS Contains edges (5 sites at lines 503/905/1694/1772/1886) → 'vfs-contains' - VFS symlink entity → 'vfs-symlink' (NEW — distinct from 'vfs-file') - VFS copy-file → preserves source subtype, falls back to 'vfs-file' - VFS symlink also adopts the isVFSEntity infrastructure marker so it bypasses enforcement in strict mode - Aggregation materializer (Measurement entities) → 'materialized-aggregate' - ImportCoordinator (3 sites): document → 'import-source'; entities → options.defaultSubtype ?? 'imported'; placeholder → 'import-placeholder' - SmartImportOrchestrator (4 entity sites + 2 batch relate sites): same precedence (extractor → options.defaultSubtype → 'imported') - EntityDeduplicator → candidate.subtype ?? 'imported' - UniversalImportAPI → extractor → 'extracted' for both entities and relations - NeuralImport → adds defaultSubtype to NeuralImportOptions; precedence same - GoogleSheetsIntegration → request body 'subtype' ?? 'imported-from-sheets' - ODataIntegration → request body 'Subtype' ?? 'imported-from-odata' - MCP client message storage → 'mcp-message' (also fixes pre-existing missing data field and missing type by aliasing from the prior text field) Side-effect fix: storage.getNouns() paginated now surfaces subtype to top-level - Single-noun getNoun() already did this in 7.30; the paginated path was missed - Without this fix brain.audit() saw missing subtype on entities that actually had one (caught by the strict-mode self-test before release) NEW — tests/integration/strict-mode-self-test.test.ts (13 tests) - Creates a brain under the exact SDK_CORE_VOCABULARY shape Venue hit + brain- wide strict mode - Exercises every internal Brainy path: VFS root + mkdir + writeFile + cp + mv + ln + symlink; aggregation engine; audit diagnostic with includeVFS toggle - Validates error message UX: caller location, vocabulary guidance, brain-wide strict mode guidance, off-vocabulary value reporting Docs - New "Strict mode in practice" section in docs/guides/subtypes-and-facets.md covering the SDK_CORE_VOCABULARY pattern, 4-step migration recipe (audit → migrateField → hand-fix → re-audit), the Brainy-internal label reference table, and an 8.0 forward-look on fillSubtypes() - docs/api/README.md: new audit() entry, strict-mode tips on add() and relate() - RELEASES.md: full 7.30.1 entry Cortex parity (forward-looking, not blocking 7.30.1) - 6th open question added to .strategy/BRAINY-8.0-SUBTYPE-CONTRACT.md: native fast path for audit() and fillSubtypes() via column-store null-subtype bitmap for billion-scale brains - Cortex should add a parity test mirroring strict-mode-self-test.test.ts against their native paths to catch any latent bug where native writes bypass JS validation - Brainy-internal subtype labels become a documented part of the 8.0 contract (useful for Cortex telemetry surfacing Brainy-managed infrastructure %) Verification - npx tsc --noEmit: clean - npm test: 1468/1468 unit - 7.29 noun integration suite: 26/26 (no regression) - 7.30 verb subtype + enforcement integration suite: 30/30 (no regression) - New strict-mode-self-test integration suite: 13/13 - npm run build: clean - Closed-source product reference audit: clean Addresses VE-SUBTYPE-MIGRATION (Venue's reported request) and ships internal labels Venue did NOT ask for but that would have broken them next under their own vocabulary registration.
2026-06-08 11:31:47 -07:00
subtype?: string
metadata?: Record<string, unknown>
merge?: boolean
}): Promise<void>
}
interface PendingMaterialization {
aggName: string
definition: AggregateDefinition
groupKey: Record<string, string | number>
groupState: AggregateGroupState
}
const DEFAULT_DEBOUNCE_MS = 1000
export class AggregateMaterializer {
private brain: MaterializerBrainAccess
private pending = new Map<string, PendingMaterialization>()
private debounceTimers = new Map<string, ReturnType<typeof setTimeout>>()
private defaultDebounceMs: number
private flushing = false
constructor(brain: MaterializerBrainAccess, debounceMs?: number) {
this.brain = brain
this.defaultDebounceMs = debounceMs ?? DEFAULT_DEBOUNCE_MS
}
/**
* Schedule a group to be materialized as a Measurement entity.
* Debounces writes to avoid thrashing during batch ingestion.
*/
scheduleMaterialize(
aggName: string,
definition: AggregateDefinition,
groupKey: Record<string, string | number>,
groupState: AggregateGroupState
): void {
const materializeConfig = definition.materialize
if (materializeConfig === false || materializeConfig === undefined) return
const debounceMs = typeof materializeConfig === 'object'
? (materializeConfig.debounceMs ?? this.defaultDebounceMs)
: this.defaultDebounceMs
const key = `${aggName}:${serializeGroupKey(groupKey)}`
this.pending.set(key, { aggName, definition, groupKey, groupState })
// Reset debounce timer
const existing = this.debounceTimers.get(key)
if (existing) clearTimeout(existing)
this.debounceTimers.set(key, setTimeout(() => {
this.materializeOne(key).catch(() => {
// Non-fatal — materialization is derived data
})
}, debounceMs))
}
/**
* Flush all pending materializations immediately.
*/
async flush(): Promise<void> {
if (this.flushing) return
this.flushing = true
try {
// Cancel all timers
for (const timer of this.debounceTimers.values()) {
clearTimeout(timer)
}
this.debounceTimers.clear()
// Process all pending
const entries = Array.from(this.pending.entries())
this.pending.clear()
await Promise.all(entries.map(([key, entry]) => this.doMaterialize(entry)))
} finally {
this.flushing = false
}
}
/**
* Cancel all pending timers and discard pending materializations.
*/
close(): void {
for (const timer of this.debounceTimers.values()) {
clearTimeout(timer)
}
this.debounceTimers.clear()
this.pending.clear()
}
// ============= Internal =============
private async materializeOne(key: string): Promise<void> {
const entry = this.pending.get(key)
if (!entry) return
this.pending.delete(key)
this.debounceTimers.delete(key)
await this.doMaterialize(entry)
}
private async doMaterialize(entry: PendingMaterialization): Promise<void> {
const { aggName, definition, groupKey, groupState } = entry
// Compute metric values for the materialized entity
const metricValues: Record<string, number> = {}
let totalCount = 0
for (const [metricName, metricDef] of Object.entries(definition.metrics)) {
const state = groupState.metrics[metricName]
if (!state) continue
switch (metricDef.op) {
case 'count':
metricValues[metricName] = state.count
break
case 'sum':
metricValues[metricName] = state.sum
break
case 'avg':
metricValues[metricName] = state.count > 0 ? Math.round((state.sum / state.count) * 100) / 100 : 0
break
case 'min':
metricValues[metricName] = state.min === Infinity ? 0 : state.min
break
case 'max':
metricValues[metricName] = state.max === -Infinity ? 0 : state.max
break
}
totalCount = Math.max(totalCount, state.count)
}
// Build human-readable data string
const groupKeyStr = Object.entries(groupKey)
.map(([k, v]) => `${k}=${v}`)
.join(', ')
const metricsStr = Object.entries(metricValues)
.map(([k, v]) => `${k}=${v}`)
.join(', ')
const dataString = `${aggName}: ${groupKeyStr} -- ${metricsStr}`
// Build metadata
const metadata: Record<string, unknown> = {
__aggregate: aggName,
__aggregateGroup: serializeGroupKey(groupKey),
...groupKey,
...metricValues,
lastUpdated: Date.now()
}
const existingId = groupState.materializedEntityId
if (existingId) {
// Update existing materialized entity
await this.brain.update({
id: existingId,
data: dataString,
metadata,
merge: false
})
} else {
// Create new materialized entity
// NounType.Measurement = 'measurement'
fix: internal subtype consistency + brain.audit() diagnostic + improved enforcement errors Brainy 7.30 shipped opt-in subtype enforcement; SDK 3.20.0 then registered SDK_CORE_VOCABULARY on every consumer's brain (Event, Collection, Message, Contract, Media, Document NounTypes). On 2026-06-08 Venue's /book flow went 500 because their brain.add({ type: NounType.Event, ... }) call sites lacked subtype. An audit of Brainy's OWN source revealed 14 HIGH-risk internal write paths that also omit subtype — any consumer running the same vocabulary would have hit Brainy's infrastructure paths next. 7.30.1 closes both gaps before 8.0 makes strict mode the default. Additive across the board. Zero behavior change for consumers not using strict mode. Every change is JS-side — Cortex needs no work for 7.30.1. NEW — brain.audit() diagnostic - Read-only method walking storage.getNouns() / getVerbs() pagination - Returns { entitiesWithoutSubtype: { type: count }, relationshipsWithoutSubtype, total, scanned, recommendation } - VFS infrastructure entities excluded by default (they bypass enforcement via isVFSEntity marker); pass { includeVFS: true } to surface them - The companion to migrateField (7.x) and fillSubtypes (8.0): tells consumers exactly what would break under strict enforcement, deterministically NEW — Improved enforcement error messages - Caller's source location extracted from Error().stack so users see their own call site, not a Brainy internal frame - Specific guidance branches: registered vocabulary → "Pass one of: a, b, c"; brain-wide strict mode → mentions the except clause; otherwise → registration recipe via brain.requireSubtype() - Documentation link to the canonical migration recipe - Same shape for noun and verb enforcement NEW — CLI --subtype flag - brainy add and brainy relate gain -s/--subtype <value> - Defaults to 'cli-add' / 'cli-relate' so the CLI works against strict-mode brains without the user needing to know the vocabulary in advance INTERNAL — every Brainy write path now sets subtype - VFS Contains edges (5 sites at lines 503/905/1694/1772/1886) → 'vfs-contains' - VFS symlink entity → 'vfs-symlink' (NEW — distinct from 'vfs-file') - VFS copy-file → preserves source subtype, falls back to 'vfs-file' - VFS symlink also adopts the isVFSEntity infrastructure marker so it bypasses enforcement in strict mode - Aggregation materializer (Measurement entities) → 'materialized-aggregate' - ImportCoordinator (3 sites): document → 'import-source'; entities → options.defaultSubtype ?? 'imported'; placeholder → 'import-placeholder' - SmartImportOrchestrator (4 entity sites + 2 batch relate sites): same precedence (extractor → options.defaultSubtype → 'imported') - EntityDeduplicator → candidate.subtype ?? 'imported' - UniversalImportAPI → extractor → 'extracted' for both entities and relations - NeuralImport → adds defaultSubtype to NeuralImportOptions; precedence same - GoogleSheetsIntegration → request body 'subtype' ?? 'imported-from-sheets' - ODataIntegration → request body 'Subtype' ?? 'imported-from-odata' - MCP client message storage → 'mcp-message' (also fixes pre-existing missing data field and missing type by aliasing from the prior text field) Side-effect fix: storage.getNouns() paginated now surfaces subtype to top-level - Single-noun getNoun() already did this in 7.30; the paginated path was missed - Without this fix brain.audit() saw missing subtype on entities that actually had one (caught by the strict-mode self-test before release) NEW — tests/integration/strict-mode-self-test.test.ts (13 tests) - Creates a brain under the exact SDK_CORE_VOCABULARY shape Venue hit + brain- wide strict mode - Exercises every internal Brainy path: VFS root + mkdir + writeFile + cp + mv + ln + symlink; aggregation engine; audit diagnostic with includeVFS toggle - Validates error message UX: caller location, vocabulary guidance, brain-wide strict mode guidance, off-vocabulary value reporting Docs - New "Strict mode in practice" section in docs/guides/subtypes-and-facets.md covering the SDK_CORE_VOCABULARY pattern, 4-step migration recipe (audit → migrateField → hand-fix → re-audit), the Brainy-internal label reference table, and an 8.0 forward-look on fillSubtypes() - docs/api/README.md: new audit() entry, strict-mode tips on add() and relate() - RELEASES.md: full 7.30.1 entry Cortex parity (forward-looking, not blocking 7.30.1) - 6th open question added to .strategy/BRAINY-8.0-SUBTYPE-CONTRACT.md: native fast path for audit() and fillSubtypes() via column-store null-subtype bitmap for billion-scale brains - Cortex should add a parity test mirroring strict-mode-self-test.test.ts against their native paths to catch any latent bug where native writes bypass JS validation - Brainy-internal subtype labels become a documented part of the 8.0 contract (useful for Cortex telemetry surfacing Brainy-managed infrastructure %) Verification - npx tsc --noEmit: clean - npm test: 1468/1468 unit - 7.29 noun integration suite: 26/26 (no regression) - 7.30 verb subtype + enforcement integration suite: 30/30 (no regression) - New strict-mode-self-test integration suite: 13/13 - npm run build: clean - Closed-source product reference audit: clean Addresses VE-SUBTYPE-MIGRATION (Venue's reported request) and ships internal labels Venue did NOT ask for but that would have broken them next under their own vocabulary registration.
2026-06-08 11:31:47 -07:00
// Subtype `materialized-aggregate` distinguishes engine-emitted Measurement entities
// from any user-authored ones, and makes them queryable: `brain.find({ type: 'measurement',
// subtype: 'materialized-aggregate' })` enumerates every active aggregate output. Also
// ensures the aggregation engine itself doesn't trip enforcement when a consumer
// registers a vocabulary on NounType.Measurement (added 7.30.1).
const id = await this.brain.add({
data: dataString,
type: 'measurement' as NounType,
fix: internal subtype consistency + brain.audit() diagnostic + improved enforcement errors Brainy 7.30 shipped opt-in subtype enforcement; SDK 3.20.0 then registered SDK_CORE_VOCABULARY on every consumer's brain (Event, Collection, Message, Contract, Media, Document NounTypes). On 2026-06-08 Venue's /book flow went 500 because their brain.add({ type: NounType.Event, ... }) call sites lacked subtype. An audit of Brainy's OWN source revealed 14 HIGH-risk internal write paths that also omit subtype — any consumer running the same vocabulary would have hit Brainy's infrastructure paths next. 7.30.1 closes both gaps before 8.0 makes strict mode the default. Additive across the board. Zero behavior change for consumers not using strict mode. Every change is JS-side — Cortex needs no work for 7.30.1. NEW — brain.audit() diagnostic - Read-only method walking storage.getNouns() / getVerbs() pagination - Returns { entitiesWithoutSubtype: { type: count }, relationshipsWithoutSubtype, total, scanned, recommendation } - VFS infrastructure entities excluded by default (they bypass enforcement via isVFSEntity marker); pass { includeVFS: true } to surface them - The companion to migrateField (7.x) and fillSubtypes (8.0): tells consumers exactly what would break under strict enforcement, deterministically NEW — Improved enforcement error messages - Caller's source location extracted from Error().stack so users see their own call site, not a Brainy internal frame - Specific guidance branches: registered vocabulary → "Pass one of: a, b, c"; brain-wide strict mode → mentions the except clause; otherwise → registration recipe via brain.requireSubtype() - Documentation link to the canonical migration recipe - Same shape for noun and verb enforcement NEW — CLI --subtype flag - brainy add and brainy relate gain -s/--subtype <value> - Defaults to 'cli-add' / 'cli-relate' so the CLI works against strict-mode brains without the user needing to know the vocabulary in advance INTERNAL — every Brainy write path now sets subtype - VFS Contains edges (5 sites at lines 503/905/1694/1772/1886) → 'vfs-contains' - VFS symlink entity → 'vfs-symlink' (NEW — distinct from 'vfs-file') - VFS copy-file → preserves source subtype, falls back to 'vfs-file' - VFS symlink also adopts the isVFSEntity infrastructure marker so it bypasses enforcement in strict mode - Aggregation materializer (Measurement entities) → 'materialized-aggregate' - ImportCoordinator (3 sites): document → 'import-source'; entities → options.defaultSubtype ?? 'imported'; placeholder → 'import-placeholder' - SmartImportOrchestrator (4 entity sites + 2 batch relate sites): same precedence (extractor → options.defaultSubtype → 'imported') - EntityDeduplicator → candidate.subtype ?? 'imported' - UniversalImportAPI → extractor → 'extracted' for both entities and relations - NeuralImport → adds defaultSubtype to NeuralImportOptions; precedence same - GoogleSheetsIntegration → request body 'subtype' ?? 'imported-from-sheets' - ODataIntegration → request body 'Subtype' ?? 'imported-from-odata' - MCP client message storage → 'mcp-message' (also fixes pre-existing missing data field and missing type by aliasing from the prior text field) Side-effect fix: storage.getNouns() paginated now surfaces subtype to top-level - Single-noun getNoun() already did this in 7.30; the paginated path was missed - Without this fix brain.audit() saw missing subtype on entities that actually had one (caught by the strict-mode self-test before release) NEW — tests/integration/strict-mode-self-test.test.ts (13 tests) - Creates a brain under the exact SDK_CORE_VOCABULARY shape Venue hit + brain- wide strict mode - Exercises every internal Brainy path: VFS root + mkdir + writeFile + cp + mv + ln + symlink; aggregation engine; audit diagnostic with includeVFS toggle - Validates error message UX: caller location, vocabulary guidance, brain-wide strict mode guidance, off-vocabulary value reporting Docs - New "Strict mode in practice" section in docs/guides/subtypes-and-facets.md covering the SDK_CORE_VOCABULARY pattern, 4-step migration recipe (audit → migrateField → hand-fix → re-audit), the Brainy-internal label reference table, and an 8.0 forward-look on fillSubtypes() - docs/api/README.md: new audit() entry, strict-mode tips on add() and relate() - RELEASES.md: full 7.30.1 entry Cortex parity (forward-looking, not blocking 7.30.1) - 6th open question added to .strategy/BRAINY-8.0-SUBTYPE-CONTRACT.md: native fast path for audit() and fillSubtypes() via column-store null-subtype bitmap for billion-scale brains - Cortex should add a parity test mirroring strict-mode-self-test.test.ts against their native paths to catch any latent bug where native writes bypass JS validation - Brainy-internal subtype labels become a documented part of the 8.0 contract (useful for Cortex telemetry surfacing Brainy-managed infrastructure %) Verification - npx tsc --noEmit: clean - npm test: 1468/1468 unit - 7.29 noun integration suite: 26/26 (no regression) - 7.30 verb subtype + enforcement integration suite: 30/30 (no regression) - New strict-mode-self-test integration suite: 13/13 - npm run build: clean - Closed-source product reference audit: clean Addresses VE-SUBTYPE-MIGRATION (Venue's reported request) and ships internal labels Venue did NOT ask for but that would have broken them next under their own vocabulary registration.
2026-06-08 11:31:47 -07:00
subtype: 'materialized-aggregate',
metadata,
service: 'brainy:aggregation'
})
groupState.materializedEntityId = id
}
}
}