2026-08-03 13:27:36 -07:00
/ * *
* @module db / fieldAddressing
* @description The one field - addressing law for every query surface ( find ( ) ' s
* ` where ` / ` orderBy ` / ` groupBy ` , aggregation ` source.where ` ) , ruled
* 2026 - 08 - 03 after a production incident in which a user metadata field
* named ` level ` was silently shadowed by the engine ' s internal HNSW node
* layer ( VENUE - BRAINY - ORDERBY - NOOP — thread id kept verbatim as the audit
* key ; it names no product ) :
*
* 1 . A BARE field name addresses the user ' s metadata field . Always .
* No priority resolution , no fallback chain — ` orderBy: 'level' `
* reads ` entity.metadata.level ` , full stop .
* 2 . ` system.<field> ` addresses an engine scalar , reachable ONLY with the
* explicit prefix . The entity map is exactly ten scalars ; the relation
* map mirrors it with ` verb ` / ` sourceId ` / ` targetId ` as the structural
* members .
* 3 . Engine plumbing ( ` vector ` , ` connections ` , ` level ` , ` data ` , ` _rev ` ) is
* INVISIBLE to the query surface in either spelling — ` system.level `
* refuses ; bare ` level ` is the user ' s field .
* 4 . ` metadata.<field> ` is the explicit spelling of the bare form —
* identical semantics on every path .
* 5 . Anything unresolvable refuses with a TYPED error naming both
* candidate spellings — an accepted name either works or refuses ;
* there is no third state .
*
* This module is the SINGLE source of truth for the law : parsing , the maps ,
* and the refusal builders live here so the JS engine , the provider seams ,
* and the cross - engine conformance suite can never drift on the contract .
* /
import type { HNSWNounWithMetadata , HNSWVerbWithMetadata } from '../coreTypes.js'
/ * *
* @description The entity - side ` system.* ` map — EXACTLY the ten engine
* scalars David ruled queryable ( 2026 - 08 - 03 ) . Adding a name here is a
* cross - engine contract change : the native accelerator ' s conformance suite
* pins this list verbatim , so any edit must ship as a paired release .
* /
export const SYSTEM_ENTITY_SCALARS : ReadonlySet < string > = new Set ( [
'id' ,
'type' ,
'subtype' ,
'createdAt' ,
'updatedAt' ,
'confidence' ,
'weight' ,
'visibility' ,
'service' ,
'createdBy'
] )
/ * *
* @description The relation - side ` system.* ` map — the verb mirror of
* { @link SYSTEM_ENTITY_SCALARS } : ` verb ` , ` sourceId ` , ` targetId ` are the
* structural members beside the eight shared scalars . Same one law , same
* pairing rule for edits .
* /
export const SYSTEM_RELATION_SCALARS : ReadonlySet < string > = new Set ( [
'verb' ,
'sourceId' ,
'targetId' ,
'subtype' ,
'createdAt' ,
'updatedAt' ,
'confidence' ,
'weight' ,
'visibility' ,
'service' ,
'createdBy'
] )
/ * *
* @description Engine plumbing — never addressable from the query surface in
* ANY spelling . ` level ` is the HNSW node layer ( the incident field : listing
* it as resolvable shadowed real user data ) ; ` data ` is the payload container ,
* not a scalar — content is reached through the content / text - search APIs ,
* and addressing it as a sortable field would lie about its shape .
* /
export const PLUMBING_FIELDS : ReadonlySet < string > = new Set ( [
'vector' ,
'connections' ,
'level' ,
'data' ,
'_rev'
] )
/** @description Which record kind a field address is being resolved against. */
export type FieldAddressKind = 'entity' | 'relation'
/ * *
* @description A parsed , law - valid field address . ` scope ` says which side of
* the record the name lives on ; ` field ` is the unprefixed name to read .
* /
export interface FieldAddress {
/** 'metadata' = the user's field (bare or `metadata.`-prefixed); 'system' = an engine scalar. */
scope : 'metadata' | 'system'
/** The field name with any scope prefix removed. */
field : string
/** The exact spelling the caller used — preserved for error text and telemetry. */
raw : string
}
/ * *
* Parse a query - surface field name under the one law . Pure and data - blind :
* this validates the ADDRESS ( spelling + map membership ) , not whether any
* row actually carries the field — data - aware refusals ( the did - you - mean
* for a bare system - scalar name no row carries ) belong to the query layer ,
* which calls { @link buildUnresolvableMessage } with index knowledge .
*
* @param raw - The field name as the caller wrote it ( ` level ` ,
* ` metadata.level ` , ` system.createdAt ` , … )
* @param kind - Entity or relation resolution ( selects the system map )
* @returns The parsed { @link FieldAddress }
* @throws { InvalidFieldAddressError } for a ` system.* ` name outside the ruled
* map ( including every plumbing field ) or a malformed spelling — the error
* text enumerates the valid system scalars so the fix is in the message .
*
* @example
* parseFieldAddress ( 'level' , 'entity' ) // { scope: 'metadata', field: 'level' }
* parseFieldAddress ( 'metadata.level' , 'entity' ) // { scope: 'metadata', field: 'level' }
* parseFieldAddress ( 'system.createdAt' , 'entity' ) // { scope: 'system', field: 'createdAt' }
* parseFieldAddress ( 'system.level' , 'entity' ) // throws — plumbing is invisible
* /
export function parseFieldAddress (
raw : string ,
kind : FieldAddressKind
) : FieldAddress {
const systemMap =
kind === 'entity' ? SYSTEM_ENTITY_SCALARS : SYSTEM_RELATION_SCALARS
if ( raw . startsWith ( 'system.' ) ) {
const field = raw . slice ( 'system.' . length )
if ( ! systemMap . has ( field ) ) {
throw new InvalidFieldAddressError ( raw , kind , systemMap )
}
return { scope : 'system' , field , raw }
}
if ( raw . startsWith ( 'metadata.' ) ) {
const field = raw . slice ( 'metadata.' . length )
if ( field . length === 0 ) {
throw new InvalidFieldAddressError ( raw , kind , systemMap )
}
return { scope : 'metadata' , field , raw }
}
if ( raw . length === 0 ) {
throw new InvalidFieldAddressError ( raw , kind , systemMap )
}
// Bare name = the user's metadata field. Always. Even when the same name
// exists in the system map — `confidence` as a bare name is the user's
// metadata field named confidence; the engine scalar is system.confidence.
return { scope : 'metadata' , field : raw , raw }
}
/ * *
* Read the addressed value off an entity . The ONLY sanctioned way a query
* surface turns a { @link FieldAddress } into a value — direct property reads
* against records re - create the shadow class this module exists to kill .
*
* @returns The value , or ` undefined ` when the record does not carry it
* ( missing values sort LAST in both directions per the ordering contract —
* they are never grounds for dropping a row ) .
* /
export function readEntityFieldAddress (
entity : HNSWNounWithMetadata ,
address : FieldAddress
) : unknown {
2026-08-03 16:01:02 -07:00
const rec = entity as unknown as Record < string , unknown >
const bag =
rec . metadata && typeof rec . metadata === 'object'
? ( rec . metadata as Record < string , unknown > )
: null
2026-08-03 13:27:36 -07:00
if ( address . scope === 'system' ) {
feat(namespace): NO SPECIAL NAMES + storage fidelity — the ruled completion of the field-addressing law
The write side of the law, ruled 2026-08-03: data is either in main space
where developers can use anything, or it is in system.*.
- The reserved-name write door DIES: add/update/relate/updateRelation
metadata bags accept EVERY name (confidence, type, id, data, level,
content, ...) as ordinary user fields — indexed, filterable, sortable,
aggregatable, identical to any other field. The remap/enforce/warn
machinery, the reservedFieldPolicy config (now a typed init refusal),
and the compile-time metadata key bans are all removed. The one write
refusal left: keys spelled 'system.*' (namespace forgery), now enforced
on all four write doors.
- STORED RECORDS GO NESTED (v2): engine fields top-level, the user bag
nested verbatim under 'metadata', sealed by a format stamp — by-name
storage discrimination is unsound once colliders are admitted. Legacy
flat records stay readable forever through the shape-aware splitters
(sound for them: the old door refused colliders). Time travel rides the
same split (generation store snapshots whole records).
- Name-based index exclusions DIE: user frame indexes every name; the
excludeFields/indexedFields knobs and their silent-[] holes are gone;
bulk-payload protection is value-shape only, uniform across names.
- Consumer-sweep findings fixed in the same wave: per-type counts read
the frozen 'system.type' column (addToIndex sort, affinity tracking,
cold-count rehydration, VFS type bitmaps — legacy 'noun' fallback for
pre-rebuild reads); resolveHiddenIds addresses 'system.visibility'
(bare 'visibility' was a silent no-op under the law — VFS/system
entities leaked into default reads).
- Fidelity fallout fixed in the owning layers: readEntityFieldAddress
reads the bag first (colliders were absent-shadowed by its own guard)
and never serves system addresses from the bag; blob history refs read
the bag shape-aware; migration transforms now receive ONE normalized
view (engine fields + nested bag) regardless of stored era, and stray
flat-habit keys refuse with the fix in the message.
- THE REOPEN-COLLIDER CONFORMANCE CASE (required before any RC counts as
gates-green): all ten collider names + plumbing names written as user
fields, verified verbatim + queryable across live reads, flush+reopen,
a forced epoch rebuild, and asOf time travel; relation mirror; forgery
refusals; legacy flat-record compat. 8/8 green.
Gates: unit 1901/1901 (exit 0) · integration 758 (exit 0) · conformance
27/27 (exit 0) · consumer test sweep migrated (10 files).
2026-08-03 16:59:13 -07:00
// System scalars live at the record's top level, NEVER in the user's
// bag — a user field named `confidence` must be unreachable from
// system.confidence (and vice versa). Entity views carry the scalars
// top-level directly; record-derived views spell the type `noun`.
2026-08-03 16:01:02 -07:00
const top = rec [ address . field ]
if ( top !== undefined ) return top
feat(namespace): NO SPECIAL NAMES + storage fidelity — the ruled completion of the field-addressing law
The write side of the law, ruled 2026-08-03: data is either in main space
where developers can use anything, or it is in system.*.
- The reserved-name write door DIES: add/update/relate/updateRelation
metadata bags accept EVERY name (confidence, type, id, data, level,
content, ...) as ordinary user fields — indexed, filterable, sortable,
aggregatable, identical to any other field. The remap/enforce/warn
machinery, the reservedFieldPolicy config (now a typed init refusal),
and the compile-time metadata key bans are all removed. The one write
refusal left: keys spelled 'system.*' (namespace forgery), now enforced
on all four write doors.
- STORED RECORDS GO NESTED (v2): engine fields top-level, the user bag
nested verbatim under 'metadata', sealed by a format stamp — by-name
storage discrimination is unsound once colliders are admitted. Legacy
flat records stay readable forever through the shape-aware splitters
(sound for them: the old door refused colliders). Time travel rides the
same split (generation store snapshots whole records).
- Name-based index exclusions DIE: user frame indexes every name; the
excludeFields/indexedFields knobs and their silent-[] holes are gone;
bulk-payload protection is value-shape only, uniform across names.
- Consumer-sweep findings fixed in the same wave: per-type counts read
the frozen 'system.type' column (addToIndex sort, affinity tracking,
cold-count rehydration, VFS type bitmaps — legacy 'noun' fallback for
pre-rebuild reads); resolveHiddenIds addresses 'system.visibility'
(bare 'visibility' was a silent no-op under the law — VFS/system
entities leaked into default reads).
- Fidelity fallout fixed in the owning layers: readEntityFieldAddress
reads the bag first (colliders were absent-shadowed by its own guard)
and never serves system addresses from the bag; blob history refs read
the bag shape-aware; migration transforms now receive ONE normalized
view (engine fields + nested bag) regardless of stored era, and stray
flat-habit keys refuse with the fix in the message.
- THE REOPEN-COLLIDER CONFORMANCE CASE (required before any RC counts as
gates-green): all ten collider names + plumbing names written as user
fields, verified verbatim + queryable across live reads, flush+reopen,
a forced epoch rebuild, and asOf time travel; relation mirror; forgery
refusals; legacy flat-record compat. 8/8 green.
Gates: unit 1901/1901 (exit 0) · integration 758 (exit 0) · conformance
27/27 (exit 0) · consumer test sweep migrated (10 files).
2026-08-03 16:59:13 -07:00
if ( address . field === 'type' ) return rec . noun
2026-08-03 16:01:02 -07:00
return undefined
}
feat(namespace): NO SPECIAL NAMES + storage fidelity — the ruled completion of the field-addressing law
The write side of the law, ruled 2026-08-03: data is either in main space
where developers can use anything, or it is in system.*.
- The reserved-name write door DIES: add/update/relate/updateRelation
metadata bags accept EVERY name (confidence, type, id, data, level,
content, ...) as ordinary user fields — indexed, filterable, sortable,
aggregatable, identical to any other field. The remap/enforce/warn
machinery, the reservedFieldPolicy config (now a typed init refusal),
and the compile-time metadata key bans are all removed. The one write
refusal left: keys spelled 'system.*' (namespace forgery), now enforced
on all four write doors.
- STORED RECORDS GO NESTED (v2): engine fields top-level, the user bag
nested verbatim under 'metadata', sealed by a format stamp — by-name
storage discrimination is unsound once colliders are admitted. Legacy
flat records stay readable forever through the shape-aware splitters
(sound for them: the old door refused colliders). Time travel rides the
same split (generation store snapshots whole records).
- Name-based index exclusions DIE: user frame indexes every name; the
excludeFields/indexedFields knobs and their silent-[] holes are gone;
bulk-payload protection is value-shape only, uniform across names.
- Consumer-sweep findings fixed in the same wave: per-type counts read
the frozen 'system.type' column (addToIndex sort, affinity tracking,
cold-count rehydration, VFS type bitmaps — legacy 'noun' fallback for
pre-rebuild reads); resolveHiddenIds addresses 'system.visibility'
(bare 'visibility' was a silent no-op under the law — VFS/system
entities leaked into default reads).
- Fidelity fallout fixed in the owning layers: readEntityFieldAddress
reads the bag first (colliders were absent-shadowed by its own guard)
and never serves system addresses from the bag; blob history refs read
the bag shape-aware; migration transforms now receive ONE normalized
view (engine fields + nested bag) regardless of stored era, and stray
flat-habit keys refuse with the fix in the message.
- THE REOPEN-COLLIDER CONFORMANCE CASE (required before any RC counts as
gates-green): all ten collider names + plumbing names written as user
fields, verified verbatim + queryable across live reads, flush+reopen,
a forced epoch rebuild, and asOf time travel; relation mirror; forgery
refusals; legacy flat-record compat. 8/8 green.
Gates: unit 1901/1901 (exit 0) · integration 758 (exit 0) · conformance
27/27 (exit 0) · consumer test sweep migrated (10 files).
2026-08-03 16:59:13 -07:00
// User scope: the bag IS the user's namespace, authoritative — EVERY name
// reads from it, engine spellings included (`bag.confidence` is the user's
// confidence field under the field-addressing law).
if ( bag ) return bag [ address . field ]
// No bag at all: a LEGACY flat record (pre-nested-bag storage). Its keys
// matching system/plumbing names are the ENGINE's — the pre-law write door
// refused user colliders — so a bare system name reads as ABSENT rather
// than resurrecting the shadow this module exists to kill. Same for the
// legacy 'noun' spelling.
2026-08-03 16:01:02 -07:00
if (
SYSTEM_ENTITY_SCALARS . has ( address . field ) ||
PLUMBING_FIELDS . has ( address . field ) ||
address . field === 'noun'
) {
return undefined
2026-08-03 13:27:36 -07:00
}
2026-08-03 16:01:02 -07:00
return rec [ address . field ]
2026-08-03 13:27:36 -07:00
}
/ * *
* Relation twin of { @link readEntityFieldAddress } . The stored flat record
* keys the relation type under ` verb ` ; public Relation shapes may carry it
* as ` type ` — both spellings of the record are read , the ADDRESS is always
* ` system.verb ` .
* /
export function readRelationFieldAddress (
verb : HNSWVerbWithMetadata ,
address : FieldAddress
) : unknown {
if ( address . scope === 'system' ) {
const rec = verb as unknown as Record < string , unknown >
if ( address . field === 'verb' ) return rec . verb ? ? rec . type
return rec [ address . field ]
}
return verb . metadata ? . [ address . field ]
}
/ * *
* Build the ruled did - you - mean refusal text for a bare name that resolved to
* metadata but is UNKNOWN to the index — the data - aware half of the law ,
* called by the query layer once it has consulted the known - field set :
*
* " no metadata field 'createdAt' — did you mean system . createdAt or
* metadata . createdAt ? "
*
* When the bare name is NOT a system scalar the system candidate is omitted
* ( there is only one thing the caller could have meant ; the refusal exists
* because refusing beats silently sorting nothing ) .
* /
export function buildUnresolvableMessage (
raw : string ,
kind : FieldAddressKind
) : string {
const systemMap =
kind === 'entity' ? SYSTEM_ENTITY_SCALARS : SYSTEM_RELATION_SCALARS
if ( systemMap . has ( raw ) ) {
return (
` no metadata field ' ${ raw } ' — did you mean system. ${ raw } or metadata. ${ raw } ? ` +
` (bare names always address your metadata; engine fields need the system. prefix) `
)
}
return (
` no metadata field ' ${ raw } ' on this store — nothing carries it, so an ordered or ` +
` filtered read against it cannot mean anything. Spell it metadata. ${ raw } once the ` +
2026-08-03 16:07:27 -07:00
` field exists, or check the field name (system. ${ raw } is NOT valid — ' ${ raw } ' is ` +
` not one of the engine's system scalars). `
2026-08-03 13:27:36 -07:00
)
}
2026-08-03 16:01:02 -07:00
/ * *
* @description Refusal for a syntactically valid address that resolves to
* NOTHING — a bare name no user field carries . Carries the did - you - mean
* ( both candidate spellings when the name collides with a system scalar ) so
* the fix ships inside the error . Thrown by the query layer with index
* knowledge , never by the pure parser .
* /
feat(query): the sparse-store cut — where on a never-carried field serves operator truth, never a refusal
A first adopter's namespace migration went 341 red on one class: the
never-carried-field refusal firing on CORRECT filters against fresh and
sparse stores — a freshly provisioned tenant refused its own first
filtered read, with the did-you-mean built for typos firing hardest on
day-one stores where nothing is wrong.
The ruled cut: a WHERE filter naming a field no row carries is SERVED
OPERATOR-TRUTHFULLY — eq/in/range/contains answer [] (nothing carries
it, nothing matches); ne and exists:false answer ALL rows (the equally
true complement — a blanket empty here would be silently wrong, which is
why the simpler cut was rejected); exists:true answers []. Served from
the field registry, with the did-you-mean demoted to a once-per-field
WARN. orderBy and genuinely ambiguous addresses KEEP their hard typed
refusals: no truthful order exists over an uncarried field, and
ambiguity is a contract error while absence is data.
Mechanics: the negative operator absorbs the FIELD_NOT_INDEXED throw as
its empty exclude set (the clause-level catch correctly zeroes positive
operators only); the egress matcher already agreed. Plus the
provider-seam belt: a field refusal thrown by a replacement metadata
manager is normalized to THIS package's UnresolvableFieldError at every
filter call site — one class identity for consumers, instanceof works
(a first adopter's cross-package finding).
Conformance: tests/conformance/sparse-store-cut.test.ts — the shared
operator rows both engines run (positive-empty, negative-all,
fresh-tenant day-one, orderBy refusal kept, compound composition).
Gates: unit 2065/2065 · integration 832 · conformance 36/36.
2026-08-12 15:57:19 -07:00
/ * *
* Cross - package identity normalizer ( the seam belt ) : the native accelerator
* throws ITS OWN UnresolvableFieldError class , which fails ` instanceof `
* against this package ' s export — consumers were forced to match by name .
* Every provider - boundary catch routes suspected field - refusals through
* here : a foreign refusal ( matched by name , duck fields tolerated ) is
* rethrown as THIS package ' s class , so exactly one identity ever reaches
* consumers . Anything else returns null ( caller rethrows the original ) .
* /
export function asBrainyFieldRefusal ( err : unknown ) : UnresolvableFieldError | null {
if ( err instanceof UnresolvableFieldError ) return err
const e = err as { name? : string ; message? : string ; raw? : string ; kind? : string } | null
if ( e && e . name === 'UnresolvableFieldError' ) {
return new UnresolvableFieldError (
e . raw ? ? 'unknown-field' ,
( e . kind as FieldAddressKind ) ? ? 'entity' ,
e . message
)
}
return null
}
2026-08-03 16:01:02 -07:00
export class UnresolvableFieldError extends Error {
public readonly raw : string
public readonly kind : FieldAddressKind
constructor ( raw : string , kind : FieldAddressKind , messageOverride? : string ) {
super ( messageOverride ? ? buildUnresolvableMessage ( raw , kind ) )
this . name = 'UnresolvableFieldError'
this . raw = raw
this . kind = kind
}
}
2026-08-03 13:27:36 -07:00
/ * *
* @description Refusal for a malformed or out - of - map field ADDRESS —
* ` system.<anything-not-in-the-map> ` ( including all plumbing ) , an empty
* name , or a bare ` metadata. ` prefix . The message carries the full valid
* system map so the fix never needs a docs lookup .
* /
2026-08-03 16:01:02 -07:00
export class InvalidFieldAddressError extends UnresolvableFieldError {
2026-08-03 13:27:36 -07:00
constructor ( raw : string , kind : FieldAddressKind , systemMap : ReadonlySet < string > ) {
const valid = [ . . . systemMap ] . map ( ( f ) = > ` system. ${ f } ` ) . join ( ', ' )
super (
2026-08-03 16:01:02 -07:00
raw ,
kind ,
2026-08-03 13:27:36 -07:00
` ' ${ raw } ' is not an addressable ${ kind } field. Bare names address your own ` +
` metadata fields; engine fields are exactly: ${ valid } . Engine plumbing ` +
` (vector, connections, level, data, _rev) is not part of the query surface. `
)
this . name = 'InvalidFieldAddressError'
}
}
2026-08-03 15:51:14 -07:00
/ * *
* @description Refusal for a find ( ) option that is accepted by the type
* surface but NOT implemented — an accepted option must work or refuse ;
* accepted - and - ignored died as a class ( sealed 2026 - 08 - 03 ) . Names the
* option and the honest state so nobody discovers a no - op by measurement .
* /
export class UnsupportedFindOptionError extends Error {
public readonly option : string
constructor ( option : string ) {
super (
` find() option ' ${ option } ' is not implemented — it used to be silently ` +
` ignored, which read as working. Remove it from the call (or track the ` +
` feature request); it will be honored or refused, never swallowed. `
)
this . name = 'UnsupportedFindOptionError'
this . option = option
}
}
2026-08-03 15:53:13 -07:00
/ * *
* @description The capability signal both engines ' conformance suites arm on
* ( never a version guess ) : its presence at the package root means the one
* field - addressing law is LIVE on every query surface — bare = user metadata ,
* ` system.* ` = the ruled scalars , plumbing invisible , refusals typed .
* /
export const FIELD_ADDRESSING_CAPABILITY = 'field-addressing/v1'