LearnNewsExamplesServices
Frontmatter
id14078
titleAtomic vector-write invariant — pure gate-core (explicit-embedding validity helper)
stateClosed
labels
enhancementai
assigneesneo-opus-vega
createdAtJun 26, 2026, 11:08 AM
updatedAtJun 26, 2026, 11:47 AM
githubUrlhttps://github.com/neomjs/neo/issues/14078
authorneo-opus-vega
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJun 26, 2026, 11:47 AM

Atomic vector-write invariant — pure gate-core (explicit-embedding validity helper)

neo-opus-vega
neo-opus-vega commented on Jun 26, 2026, 11:08 AM

Context

Parent: #14029 (atomic vector-write invariant). During PR #14077 a V-B-A of the actual Memory Core write paths surfaced that #14029 is two distinct mechanisms, not one:

  1. Explicit-embedding paths — the caller supplies the vector (collection.add/upsert({embeddings: rows.map(r => r.embedding)}), e.g. DatabaseService non-reEmbed import). A caller-side validity gate fits: reject a row whose explicit embedding is missing/empty/wrong-dimension before persist.
  2. Auto-embed paths — the caller passes no embeddings and relies on Chroma's server-side embedding function (DatabaseService reEmbed mode strips embeddings; SessionService artifact-upserts). ChromaManager sets an embeddingFunction, so these are not inherently vectorless; the invariant there is a different mechanism (verify the server-side embedding landed — read-back / fail-loud-on-embed-failure), coupled to the #14027 culprit forensics.

This sub-ticket is the first leaf: the pure, reusable gate-core (the validity logic + fail-loud partition) for the explicit-embedding paths. It is the substrate the explicit-path write-wiring (a separate sub) consumes, mirroring how #14056's producer-core shipped ahead of its #14061 consumer.

The Fix

A pure, I/O-free helper module ai/services/memory-core/helpers/vectorWriteInvariant.mjs that partitions write-path rows into persist-safe rows (valid same-dimension vector) and rejected rows (with a stable reason), so the caller persists only the valid set and routes the rest fail-loud — never half-writing a metadata-only row. Strictly additive safety: valid rows pass through unchanged.

Acceptance Criteria

  • partitionRowsByVectorValidity({rows, expectedDimension}){valid, rejected} rejects a row whose explicit embedding is missing / empty / wrong-dimension / non-finite (input order preserved for valid).
  • classifyRowVector(row, expectedDimension) returns the first/most-fundamental failure reason or null.
  • summarizeVectorRejections(rejected){count, byReason} for fail-loud logging.
  • VECTOR_REJECTION_REASONS frozen enum (missing-embedding | empty-embedding | wrong-dimension | non-finite-values).
  • Invalid inputs (non-array rows / non-positive-integer dimension) throw TypeError.
  • Unit coverage for each branch.

Out of Scope

  • The write-path wiring that consumes this gate-core (DatabaseService explicit-import sites, conditional on !reEmbed) — a separate #14029 sub.
  • The auto-embed verification mechanism (reEmbed + live SessionService paths) — coupled to #14027.

Related

  • #14029 (parent — the full invariant), #14027 (the auto-embed-failure forensics this defers to), #13999 (the incident shape), #14056 (the producer-core-before-consumer precedent).

Authored-by: @neo-opus-vega (Vega, Claude Opus 4.8)

tobiu closed this issue on Jun 26, 2026, 11:47 AM