From a082e0efdd502941eb1baa2fa3d1ac30b0d0b095 Mon Sep 17 00:00:00 2001 From: David Snelling Date: Thu, 27 Aug 2026 15:07:25 -0700 Subject: [PATCH 1/2] docs(releases): 10.4.1 and 10.4.2 consumer notes; 10.4.2 is the last MIT release under this name, Open Brainy continues at @soulcraftlabs/brainy --- RELEASES.md | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index bc400412..6de11244 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -31,6 +31,95 @@ is sometimes cited as a 7.x removal — those methods never existed on 7.x; the --- +## v10.4.2 — 2026-08-28 (a zero-norm vector is not a vector) + +**This is the last release of the MIT engine under the `@soulcraft/brainy` name.** +The MIT package continues as **Open Brainy** — `@soulcraftlabs/brainy`: the open API, +client library, types and protocol, an openly specified canonical format, and the TypeScript +reference engine, scoped honestly as a single-node engine for stores up to roughly one +million rows. The `@soulcraft/brainy` name passes to the native engine, **Brainy**, at a +major version bump; that engine implements the same API over the same open format at +production scale, requires a license, and refuses loudly without one. Nothing changes +for existing installs until that major ships; the move is announced with it. + +Six fixes, one law: a vector with no magnitude carries no information, so it must +never reach a vector index — in any engine — and the canonical store must say so. + +- **The permanently-unvectored row.** `add({ ..., vector: [] })` (and the same item + shape in `addMany` / `transact`) is now the sanctioned "no vector" row: persisted + with an empty vector leg, never embedded, never indexed, counted as unvectored in + the canonical ledger. Metadata-only rows — telemetry tallies, counters, plumbing — + no longer need a placeholder vector and never enter the vector leg. `vector: []` + together with `deferEmbedding: true` is refused with a typed error (a supplied + vector has nothing to defer). Previously `vector: []` threw a dimension error. +- **The unvector door.** `update({ id, vector: [] })` (and its `transact()` twin) is + the sanctioned way to strip a vector from an existing row: canonical vector → `[]`, + removal from the vector index, the vectored ledger decremented exactly once — and + idempotent, so a resumed cleanup pass may simply re-issue. It never re-embeds, and + it clears a pending deferred-embed marker durably so the background worker cannot + re-vector the row later. Note that a rebuild never sheds vectors (it re-derives the + index from canonical rows); shedding historical vectors needs this door. +- **Zero-norm vectors are normalized at the write.** An explicit all-zero vector on + any write path is persisted as unvectored (`[]`) with one warning naming the row; + the vector-index operations keep their own refusal as a second line. The engine's + own VFS root, which used to persist a deliberate all-zero placeholder (harmless + under cosine distance, a false attractor under a downstream engine's + squared-euclidean serving — a production incident this week), is now created + unvectored, and an existing store's legacy root is migrated on open by a single + fixed-path read before the health gate runs — never a walk. +- **Enumeration keys on the identity record.** `getNouns()` / `getVerbs()` and the + cursor walks behind them enumerate by the metadata record, the same key the + canonical ledger counts by — previously the walk keyed on the vector file, so a + row holding metadata but no vector was counted yet never yielded (a permanent + "missing" phantom in coverage math), while an orphaned vector-only directory + could be yielded as a phantom id. The recovery fold also never deletes an existing + vector when it replays a metadata-only after-image (preserve-if-absent). One + documented gap remains: a verb's endpoints live only in its vector leg, so a + metadata-only verb is counted and loudly skipped, never fabricated — the fix is a + canonical-format change and lands with the open format. +- **The ledger's one-time derivation counts identity records.** Stores upgraded from + pre-ledger versions derived their ALL-visibility scalars once by counting id + directories, which included ghost and scar containers left by an old partial-delete + defect — an inflated denominator whose coverage row could never reach exact. The + derivation now counts only directories holding a metadata record, `counts.json` + carries a derivation-rule stamp, and a ledger derived under the old rule is marked + `suspect` at open (one O(1) field read, one warning) so the online `repairIndex()` + path clears it with a real recount. +- **The vector index refuses what it cannot hold.** `rebuild()` skips unvectored and + zero-norm rows (one summary line), re-pins the vector dimension from the first real + vector after a restart (previously a restart left the pin unset, so a wrong-length + insert became the new pin instead of being rejected), and `addItem` / `updateItem` + throw a typed `EmptyVectorIndexError` on a length-0 vector instead of ever storing + a vector-less node. +- **Smaller:** a failing plugin activation now rethrows with the original error as + `cause` (the originating file and line survive to the caller's log); build + generators stamp from the repository history of their inputs instead of wall clock, + so two builds of the same tree are byte-identical. + +Adoption: one restart, paired with its native-engine release. The first open of an +existing store runs the legacy-root migration (one narrated line) and, on stores that +upgraded from pre-ledger versions, marks the ledger suspect until the next sanctioned +recount — no rebuild in either case. + +## v10.4.1 — 2026-08-26 (reads refuse per family; an unchanged write never re-embeds) + +Two production defects from the same week, fixed together as a patch to 10.4.0. + +- **The read gate is per family.** A read now refuses only when the index family it + actually consults is unhealthy: a metadata filter is served while the vector leg is + rebuilding; a semantic query is refused only by the vector family; a graph + traversal only by the graph family. Previously any unhealthy family refused every + read on the brain — under a long vector rebuild, a production deployment's + metadata-only reads were refused for the duration, and the retries became a write + pump of their own. +- **Unchanged data never re-embeds.** `update()` compares the incoming `data` + structurally with the stored record; an update carrying identical data (a common + shape for periodic upserts) no longer embeds again and no longer churns the vector + leg. Previously every such update re-embedded and re-inserted, which under load + saturated the vector index with near-identical vectors. + +Adoption: one restart, paired with its native-engine release. + ## v10.4.0 — 2026-08-25 (the health report has a name) Three related cures, one root cause: an index deciding whether it could be trusted From 1f34fc6ce496ef9a359be04153da1397191f50b3 Mon Sep 17 00:00:00 2001 From: David Snelling Date: Thu, 27 Aug 2026 15:14:03 -0700 Subject: [PATCH 2/2] chore(release): 10.4.2 --- CHANGELOG.md | 5 +++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b154af5..d13a2d66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [10.4.2](https://source.soulcraft.com/soulcraft/brainy/compare/v10.4.2-rc.1...v10.4.2) (2026-08-27) + +- docs(releases): 10.4.1 and 10.4.2 consumer notes; 10.4.2 is the last MIT release under this name, Open Brainy continues at @soulcraftlabs/brainy (a082e0ef) + + ### [10.4.2-rc.1](https://source.soulcraft.com/soulcraft/brainy/compare/v10.4.1...v10.4.2-rc.1) (2026-08-27) - Merge branch 'next/zero-norm-unvector-door' (9b84ef5b) diff --git a/package-lock.json b/package-lock.json index 889c67c8..fb88681f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@soulcraft/brainy", - "version": "10.4.2-rc.1", + "version": "10.4.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@soulcraft/brainy", - "version": "10.4.2-rc.1", + "version": "10.4.2", "license": "MIT", "dependencies": { "@msgpack/msgpack": "^3.1.2", diff --git a/package.json b/package.json index 214feeac..17983c19 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@soulcraft/brainy", - "version": "10.4.2-rc.1", + "version": "10.4.2", "description": "Universal Knowledge Protocol™ - World's first Triple Intelligence database unifying vector, graph, and document search in one API. Stage 3 CANONICAL: 42 nouns × 127 verbs covering 96-97% of all human knowledge.", "main": "dist/index.js", "module": "dist/index.js",