feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
/ * *
* @module tests / integration / id - normalization
* @description Correctness gate for the 8.0 transparent entity - id normalization
* layer ( # 18 ) . A caller may use a natural string key ( e . g . ` 'user-1' ` ) anywhere
* an id is accepted ; it is mapped to a STABLE UUID ( ` v5('user-1') ` ) on creation
* AND on every lookup , so it round - trips transparently while the engine only
* ever sees a UUID . The caller ' s original string is preserved under
* { @link ORIGINAL_ID_KEY } in the stored entity metadata . A real UUID passes
* through untouched ( no ` _originalId ` ) .
*
* The layer is ALL - OR - NOTHING : every creation AND lookup path must normalize
* identically , or round - trips break . These tests prove the contract holds
* end - to - end across ` add ` / ` get ` / ` update ` / ` remove ` / ` relate ` / ` related `
* / `find({ connected })` / ` transact ` / ` addMany ` / ` relateMany ` , plus
* determinism ( same key → same UUID , upsert not duplicate ) , UUID passthrough ,
* and the v7 defaults for no - id ` add() ` and ` newId() ` .
*
* All entities carry explicit 384 - dim vectors so no test invokes the embedder .
* /
2026-09-03 09:18:57 -07:00
import { describe , it , expect , afterEach } from 'vitest'
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
import { Brainy } from '../../src/brainy.js'
import { NounType , VerbType } from '../../src/types/graphTypes.js'
import { v5 , v7 , isUUID } from '../../src/universal/uuid.js'
import { ORIGINAL_ID_KEY } from '../../src/utils/idNormalization.js'
/** Deterministic 384-dim vector so no test ever invokes the embedder. */
function vec ( seed : number ) : number [ ] {
return Array . from ( { length : 384 } , ( _ , i ) = > ( ( seed * 31 + i * 7 ) % 100 ) / 100 )
}
/** Fresh in-memory brain (no embedder, no subtype enforcement). */
async function makeBrain ( ) : Promise < Brainy > {
const brain = new Brainy ( { requireSubtype : false , storage : { type : 'memory' } } )
await brain . init ( )
return brain
}
describe ( 'id normalization — transparent string-key round-trips' , ( ) = > {
2026-09-03 09:18:57 -07:00
const opened : Brainy [ ] = [ ]
afterEach ( async ( ) = > {
for ( const b of opened . splice ( 0 ) ) await b . close ( ) . catch ( ( ) = > { } )
} )
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
it ( '1. add() returns v5(key); get(key) and get(returnedId) both resolve; _originalId preserved' , async ( ) = > {
const brain = await makeBrain ( )
2026-09-03 09:18:57 -07:00
opened . push ( brain )
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
const returnedId = await brain . add ( { id : 'user-1' , vector : vec ( 1 ) , type : NounType . Person } )
// The returned id is the stable v5 mapping, a real UUID.
expect ( returnedId ) . toBe ( v5 ( 'user-1' ) )
expect ( isUUID ( returnedId ) ) . toBe ( true )
// get() by the natural key AND by the canonical id both resolve.
const byKey = await brain . get ( 'user-1' )
const byId = await brain . get ( returnedId )
expect ( byKey ) . not . toBeNull ( )
expect ( byId ) . not . toBeNull ( )
expect ( byKey ! . id ) . toBe ( returnedId )
expect ( byId ! . id ) . toBe ( returnedId )
// The caller's original string is surfaced under ORIGINAL_ID_KEY.
expect ( byKey ! . metadata [ ORIGINAL_ID_KEY ] ) . toBe ( 'user-1' )
} )
it ( '2. relate() by string keys; related(key) and related({from:key}) return the edge to v5(toKey)' , async ( ) = > {
const brain = await makeBrain ( )
2026-09-03 09:18:57 -07:00
opened . push ( brain )
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
await brain . add ( { id : 'user-1' , vector : vec ( 1 ) , type : NounType . Person } )
await brain . add ( { id : 'doc-1' , vector : vec ( 2 ) , type : NounType . Document } )
await brain . relate ( { from : 'user-1' , to : 'doc-1' , type : VerbType . Creates } )
const expectedTo = v5 ( 'doc-1' )
const viaString = await brain . related ( 'user-1' )
expect ( viaString . length ) . toBe ( 1 )
expect ( viaString [ 0 ] . from ) . toBe ( v5 ( 'user-1' ) )
expect ( viaString [ 0 ] . to ) . toBe ( expectedTo )
const viaFrom = await brain . related ( { from : 'user-1' } )
expect ( viaFrom . length ) . toBe ( 1 )
expect ( viaFrom [ 0 ] . to ) . toBe ( expectedTo )
// And the inbound anchor resolves too.
const viaTo = await brain . related ( { to : 'doc-1' } )
expect ( viaTo . length ) . toBe ( 1 )
expect ( viaTo [ 0 ] . from ) . toBe ( v5 ( 'user-1' ) )
} )
it ( '3. update() by string key reflects on get(key)' , async ( ) = > {
const brain = await makeBrain ( )
2026-09-03 09:18:57 -07:00
opened . push ( brain )
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
await brain . add ( { id : 'user-1' , vector : vec ( 1 ) , type : NounType . Person , metadata : { role : 'admin' } } )
await brain . update ( { id : 'user-1' , metadata : { role : 'owner' } } )
const e = await brain . get ( 'user-1' )
expect ( e ) . not . toBeNull ( )
expect ( ( e ! . metadata as any ) . role ) . toBe ( 'owner' )
// Original id still surfaced after update.
expect ( e ! . metadata [ ORIGINAL_ID_KEY ] ) . toBe ( 'user-1' )
} )
it ( '4. remove() by string key deletes; get(key) is null' , async ( ) = > {
const brain = await makeBrain ( )
2026-09-03 09:18:57 -07:00
opened . push ( brain )
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
await brain . add ( { id : 'user-1' , vector : vec ( 1 ) , type : NounType . Person } )
expect ( await brain . get ( 'user-1' ) ) . not . toBeNull ( )
await brain . remove ( 'user-1' )
expect ( await brain . get ( 'user-1' ) ) . toBeNull ( )
// The canonical id is gone too.
expect ( await brain . get ( v5 ( 'user-1' ) ) ) . toBeNull ( )
} )
it ( '5. find({ connected: { from: key } }) resolves the anchor key' , async ( ) = > {
const brain = await makeBrain ( )
2026-09-03 09:18:57 -07:00
opened . push ( brain )
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
await brain . add ( { id : 'user-1' , vector : vec ( 1 ) , type : NounType . Person } )
await brain . add ( { id : 'doc-1' , vector : vec ( 2 ) , type : NounType . Document } )
await brain . relate ( { from : 'user-1' , to : 'doc-1' , type : VerbType . Creates } )
const results = await brain . find ( { connected : { from : 'user-1' } } )
const ids = results . map ( ( r ) = > r . id )
expect ( ids ) . toContain ( v5 ( 'doc-1' ) )
} )
it ( '6. transact() add+relate by string keys round-trips with consistent canonical ids' , async ( ) = > {
const brain = await makeBrain ( )
2026-09-03 09:18:57 -07:00
opened . push ( brain )
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
// Seed user-1 so the relate op has a target to point at.
await brain . add ( { id : 'user-1' , vector : vec ( 1 ) , type : NounType . Person } )
const db = await brain . transact ( [
{ op : 'add' , id : 'u-2' , vector : vec ( 3 ) , type : NounType . Person } ,
{ op : 'relate' , from : 'u-2' , to : 'user-1' , type : VerbType . RelatedTo }
] )
// Receipt ids resolve to the canonical mappings.
expect ( db . receipt . ids [ 0 ] ) . toBe ( v5 ( 'u-2' ) )
// get('u-2') works and surfaces the original id.
const u2 = await brain . get ( 'u-2' )
expect ( u2 ) . not . toBeNull ( )
expect ( u2 ! . id ) . toBe ( v5 ( 'u-2' ) )
expect ( u2 ! . metadata [ ORIGINAL_ID_KEY ] ) . toBe ( 'u-2' )
// The relation links the right canonical ids.
const rels = await brain . related ( 'u-2' )
expect ( rels . length ) . toBe ( 1 )
expect ( rels [ 0 ] . from ) . toBe ( v5 ( 'u-2' ) )
expect ( rels [ 0 ] . to ) . toBe ( v5 ( 'user-1' ) )
} )
it ( '7. addMany() + relateMany() with string ids round-trip' , async ( ) = > {
const brain = await makeBrain ( )
2026-09-03 09:18:57 -07:00
opened . push ( brain )
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
const added = await brain . addMany ( {
items : [
{ id : 'a-1' , vector : vec ( 10 ) , type : NounType . Person } ,
{ id : 'b-1' , vector : vec ( 11 ) , type : NounType . Document }
]
} )
expect ( added . successful ) . toContain ( v5 ( 'a-1' ) )
expect ( added . successful ) . toContain ( v5 ( 'b-1' ) )
const relIds = await brain . relateMany ( {
items : [ { from : 'a-1' , to : 'b-1' , type : VerbType . Creates } ]
} )
expect ( relIds . length ) . toBe ( 1 )
const a1 = await brain . get ( 'a-1' )
expect ( a1 ) . not . toBeNull ( )
expect ( a1 ! . metadata [ ORIGINAL_ID_KEY ] ) . toBe ( 'a-1' )
const rels = await brain . related ( 'a-1' )
expect ( rels . length ) . toBe ( 1 )
expect ( rels [ 0 ] . to ) . toBe ( v5 ( 'b-1' ) )
} )
it ( '8. determinism: same key maps to same UUID — two adds upsert ONE entity, not two' , async ( ) = > {
const brain = await makeBrain ( )
2026-09-03 09:18:57 -07:00
opened . push ( brain )
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
const id1 = await brain . add ( { id : 'user-1' , vector : vec ( 1 ) , type : NounType . Person , metadata : { n : 1 } } )
const id2 = await brain . add ( { id : 'user-1' , vector : vec ( 1 ) , type : NounType . Person , metadata : { n : 2 } } )
// Stable mapping across calls.
expect ( id1 ) . toBe ( id2 )
expect ( id1 ) . toBe ( v5 ( 'user-1' ) )
// Only ONE entity exists (the second add overwrote the first).
const count = await brain . getNounCount ( )
expect ( count ) . toBe ( 1 )
const e = await brain . get ( 'user-1' )
expect ( ( e ! . metadata as any ) . n ) . toBe ( 2 )
} )
it ( '9. valid-UUID passthrough: a real UUID is kept verbatim with NO _originalId' , async ( ) = > {
const brain = await makeBrain ( )
2026-09-03 09:18:57 -07:00
opened . push ( brain )
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
const realUuid = v7 ( )
const returnedId = await brain . add ( { id : realUuid , vector : vec ( 5 ) , type : NounType . Thing } )
expect ( returnedId ) . toBe ( realUuid )
const e = await brain . get ( realUuid )
expect ( e ) . not . toBeNull ( )
expect ( e ! . id ) . toBe ( realUuid )
expect ( e ! . metadata [ ORIGINAL_ID_KEY ] ) . toBeUndefined ( )
} )
it ( '10. no-id add() mints a v7; newId() mints a v7' , async ( ) = > {
const brain = await makeBrain ( )
2026-09-03 09:18:57 -07:00
opened . push ( brain )
feat(8.0): id-normalization (#18) + aggregation min/max delete-safety + RC-safe release
- id-normalization (#18): `brain.newId()` (UUID v7) + v7 default ids; non-UUID string ids are
transparently normalized to a stable UUID v5 on creation AND every lookup — get/update/remove,
relate(from,to), related, find({connected}), getMany, removeMany, the transact op-handler, and
db.with() overlays — with the caller's original key preserved under `_originalId`. The engine only
ever sees a UUID; real UUIDs pass through untouched. universal/uuid.ts gains v5/v7/isUUID +
BRAINY_ID_NAMESPACE; new utils/idNormalization.ts (coerceNewEntityId / resolveEntityId).
- aggregation min/max delete-safety: `queryAggregate` no longer leaves a stale min/max after
deleting the current extreme — min/max now track a value multiset and recompute in-memory (no
entity scan; that scan was the prior delete-then-hang a consumer reported). Other metrics were
already exact across deletes. Regression test proves resolve-after-delete + correct new min/max.
- release.sh RC-safe: explicit version arg, prerelease detection (npm `--tag rc` + GitHub
`--prerelease`), full `test:ci` gate (unit + integration), current-branch push, npm-access
verification after publish.
- native-engine references point at `@soulcraft/cor` (8.0's partner) in user-facing strings/docs.
Unit 1461/0 · integration 599/0 · tsc clean.
2026-06-20 14:40:57 -07:00
const autoId = await brain . add ( { vector : vec ( 6 ) , type : NounType . Thing } )
expect ( isUUID ( autoId ) ) . toBe ( true )
// v7 carries version nibble '7' at the canonical position.
expect ( autoId [ 14 ] ) . toBe ( '7' )
const minted = brain . newId ( )
expect ( isUUID ( minted ) ) . toBe ( true )
expect ( minted [ 14 ] ) . toBe ( '7' )
// The auto-id entity round-trips by its returned canonical id.
const e = await brain . get ( autoId )
expect ( e ) . not . toBeNull ( )
expect ( e ! . metadata [ ORIGINAL_ID_KEY ] ) . toBeUndefined ( )
} )
} )