docs: v9.0.0 release notes — the field-addressing law migration ledger; retitle the shipped 8.11.0 canonical-enumeration entry (header went stale at its cut)
This commit is contained in:
parent
19b477aec0
commit
55a7512c04
1 changed files with 99 additions and 6 deletions
105
RELEASES.md
105
RELEASES.md
|
|
@ -31,7 +31,7 @@ is sometimes cited as a 7.x removal — those methods never existed on 7.x; the
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Unreleased (canonical enumeration mode for export — storage-walked, canon-complete)
|
## v8.11.0 — 2026-07-27 (canonical enumeration mode for export — storage-walked, canon-complete)
|
||||||
|
|
||||||
From a fleet data-migration program's requirement for whole-brain exports that are
|
From a fleet data-migration program's requirement for whole-brain exports that are
|
||||||
provably canon-complete: `export()`'s default enumeration for a whole-brain/predicate
|
provably canon-complete: `export()`'s default enumeration for a whole-brain/predicate
|
||||||
|
|
@ -74,7 +74,102 @@ to the caller today.
|
||||||
on CI**, triggered by the release tag, instead of PUTting the tarball from the laptop
|
on CI**, triggered by the release tag, instead of PUTting the tarball from the laptop
|
||||||
over WAN — no change to what gets published or how a consumer installs it.
|
over WAN — no change to what gets published or how a consumer installs it.
|
||||||
|
|
||||||
## Unreleased (natural field names stop colliding with engine internals)
|
## v9.0.0 — 2026-08-04 (the field-addressing law: your names and system.*, nothing in between)
|
||||||
|
|
||||||
|
**Major.** One law now governs every field name, on every surface:
|
||||||
|
|
||||||
|
> **Data is either in main space — where you can use ANY name — or it is in
|
||||||
|
> `system.*`.**
|
||||||
|
|
||||||
|
Read `docs/concepts/field-addressing.md` (published on the docs site) for the
|
||||||
|
full contract; this entry is the migration ledger.
|
||||||
|
|
||||||
|
### Breaking — query surfaces (`where` / `orderBy` / `groupBy` / aggregation)
|
||||||
|
|
||||||
|
- **A bare field name ALWAYS addresses your metadata.** `orderBy: 'createdAt'`
|
||||||
|
no longer silently means the engine timestamp — it now refuses with a typed
|
||||||
|
`UnresolvableFieldError` naming both candidates unless you actually have a
|
||||||
|
user field of that name. Engine scalars are addressed explicitly:
|
||||||
|
`system.id`, `system.type`, `system.subtype`, `system.createdAt`,
|
||||||
|
`system.updatedAt`, `system.confidence`, `system.weight`,
|
||||||
|
`system.visibility`, `system.service`, `system.createdBy` (relations mirror
|
||||||
|
with `system.verb`/`system.sourceId`/`system.targetId`).
|
||||||
|
**Sweep list:** `where: { subtype: … }` → `where: { 'system.subtype': … }` ·
|
||||||
|
`orderBy: 'createdAt'` → `'system.createdAt'` · `groupBy: ['noun']` →
|
||||||
|
`['system.type']` · any bare `visibility`/`service`/`confidence` filter that
|
||||||
|
meant the engine value → its `system.*` spelling. Every missed site fails
|
||||||
|
LOUDLY with the correction in the error message — nothing silently changes
|
||||||
|
meaning without telling you.
|
||||||
|
- **Unimplemented `find()` options refuse** (`cursor`, `includeRelations`,
|
||||||
|
`writeOnly` → `UnsupportedFindOptionError`); `order` is validated;
|
||||||
|
accepted-and-ignored is dead as a class.
|
||||||
|
- **The ordering contract is pinned cross-engine:** missing/null `orderBy`
|
||||||
|
values sort LAST in both directions, ties break by id ascending, and rows
|
||||||
|
are never dropped from an ordered read.
|
||||||
|
|
||||||
|
### Breaking — write surfaces
|
||||||
|
|
||||||
|
- **There are no reserved metadata names anymore.** `metadata: { confidence,
|
||||||
|
type, id, level, data, content, … }` are ordinary user fields — stored
|
||||||
|
verbatim, indexed, filterable, sortable, aggregatable, faithful across
|
||||||
|
restarts, index rebuilds, and `asOf()` time travel. The 8.x
|
||||||
|
reserved-key-in-bag throw is GONE; code that relied on it (or on the
|
||||||
|
`'warn'`/`'remap'` lift) must set engine scalars via their dedicated params
|
||||||
|
(`confidence`, `weight`, `subtype`, `visibility`, …) — the bag never touches
|
||||||
|
them now.
|
||||||
|
- **`reservedFieldPolicy` is removed.** Passing it throws at construction with
|
||||||
|
the migration note. `RESERVED_ENTITY_FIELDS`/`RESERVED_RELATION_FIELDS`
|
||||||
|
remain exported but now describe the stored record's engine half, not a ban
|
||||||
|
list; the `NoReservedEntityKeys`/`NoReservedRelationKeys` types are no-op
|
||||||
|
(deprecated).
|
||||||
|
- **The one refused spelling:** a metadata key literally starting `system.`
|
||||||
|
(namespace forgery) — typed error on `add`/`update`/`relate`/`updateRelation`.
|
||||||
|
- **Name-based index exclusions are gone.** Fields named `content`, `data`,
|
||||||
|
`id`, `vector`, … in your bag now INDEX like everything else (they were
|
||||||
|
silently un-indexed before — `where` on them returned `[]` with no error).
|
||||||
|
Value-shape rules stay, uniform across all names: arrays >10 never become
|
||||||
|
posting scalars; long values index hashed.
|
||||||
|
- **Migration transforms receive one normalized view** (engine fields
|
||||||
|
top-level, your bag nested under `metadata`) regardless of how old the
|
||||||
|
stored record is, and must return the same shape — a stray non-engine
|
||||||
|
top-level key refuses with the fix in the message.
|
||||||
|
|
||||||
|
### Storage format (automatic, no action)
|
||||||
|
|
||||||
|
- New/updated records persist as **nested-bag records** (engine fields
|
||||||
|
top-level, your bag verbatim under `metadata`, sealed by a format stamp) —
|
||||||
|
the shape that makes collider names lossless. Old flat records stay
|
||||||
|
readable forever; nothing rewrites your data in place.
|
||||||
|
- **Index epoch 3:** derived-index keys split the namespaces (bare user keys ·
|
||||||
|
literal `system.<field>` keys; the legacy `noun` column is gone). Every
|
||||||
|
brain rebuilds its derived indexes from canonical once, at first open —
|
||||||
|
observable via `getIndexStatus()`, no manual step. Pair this release with
|
||||||
|
the same-day native-accelerator release (its peer floor rises to `>=9`).
|
||||||
|
- Raw-record consumers (fact-log scanners, export tooling): read bags through
|
||||||
|
the exported shape-aware splitters (`splitNounMetadataRecord` /
|
||||||
|
`splitVerbMetadataRecord`) — they handle both record eras.
|
||||||
|
|
||||||
|
### Fixed in the same train
|
||||||
|
|
||||||
|
- Default visibility exclusion was a silent no-op under the new addressing on
|
||||||
|
pre-release builds (internal/system-tier rows could leak into default
|
||||||
|
reads) — now pinned by conformance tests at every lifecycle boundary.
|
||||||
|
- Per-type count surfaces (`getStats()`, count-by-type) read the new type
|
||||||
|
column, with a legacy fallback for pre-rebuild reads.
|
||||||
|
- Aggregation `source.where` evaluated dotted keys as nested paths — dotted
|
||||||
|
addresses now match per-key, and the internal per-type counts aggregate
|
||||||
|
rebuilds itself onto the new keys automatically.
|
||||||
|
|
||||||
|
### Conformance
|
||||||
|
|
||||||
|
Both engines ship a shared self-arming conformance suite (the law cases, the
|
||||||
|
ordering contract, and the reopen-collider fidelity case: every collider name
|
||||||
|
written as user data, verified verbatim through live reads, reopen, a forced
|
||||||
|
epoch rebuild, and time travel). Capability signal:
|
||||||
|
`FIELD_ADDRESSING_CAPABILITY = 'field-addressing/v1'` plus the typed error
|
||||||
|
classes, exported from the package root.
|
||||||
|
|
||||||
|
## v8.10.3 — 2026-08-03, 8.10-line backport (natural field names stop colliding with engine internals)
|
||||||
|
|
||||||
From a production report: sorting by a user metadata field named `level` silently
|
From a production report: sorting by a user metadata field named `level` silently
|
||||||
returned insertion order — the engine's internal HNSW node layer (also called
|
returned insertion order — the engine's internal HNSW node layer (also called
|
||||||
|
|
@ -98,10 +193,8 @@ engine was wrong, not the caller.
|
||||||
fixed for `update()` but the transact plan builder still staged the
|
fixed for `update()` but the transact plan builder still staged the
|
||||||
unconditional save). If you batch stat touches through `transact()`, this is
|
unconditional save). If you batch stat touches through `transact()`, this is
|
||||||
your write-amplification fix.
|
your write-amplification fix.
|
||||||
- Coming next (announced so parsers and call sites can prepare): one
|
- (The "coming next" note this entry carried shipped as v9.0.0 — the
|
||||||
field-addressing law — bare names = user metadata, `system.<field>` for
|
field-addressing law above.)
|
||||||
engine fields, typed refusals for unresolvable names. Ships as its own
|
|
||||||
release with a migration advisory; nothing changes in this release.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue