Skip to content

ruvector 0.3.6: full CRUD for vectors, RVF and hook memories - #1305

Merged
ruvnet merged 1 commit into
mainfrom
feat/ruvector-full-crud
Nov 1, 2026
Merged

ruvnet merged 1 commit into
mainfrom
feat/ruvector-full-crud

Conversation

@ruvnet

@ruvnet ruvnet commented Nov 1, 2026

Copy link
Copy Markdown
Owner

Summary

npx ruvector now has create/read/update/delete on every data surface: vector stores, RVF stores and hook memories, through the CLI, the MCP server and the library.

Surface Create Read Update Delete
Vector DB — CLI create, insert get, search, stats update delete
Vector DB — MCP vectordb_create, vectordb_insert vectordb_get, vectordb_search, vectordb_stats vectordb_update vectordb_delete
Vector DB — library insert, insertBatch (now true upserts) get, search update delete, deleteMany
RVF — CLI / MCP create, ingest (upsert) query, status ingest replaces an id rvf delete / rvf_delete
Hook memory — CLI remember recall (now with ids), memory-get, memory-list memory-update forget
Hook memory — MCP hooks_remember hooks_recall, hooks_memory_get, hooks_memory_list hooks_memory_update hooks_forget

The native VectorDB has no enumerate API, so there is no vector list; get by id is the read.

Bug fixed: duplicate search results after re-inserting an id

Re-inserting an existing id left the old node in the native HNSW index, so search returned that id twice, once with its stale vector. Duplicate ids within one insertBatch did the same. insert and insertBatch are now true upserts (the last entry wins). The root cause is in the native core; this is a wrapper-level fix that avoids a multi-platform native republish.

Memory ids

  • MCP memories had no id.
  • CLI ids (mem_<ms>) could collide within one millisecond.
  • MCP's legacy conversion gave every id-less memory the same id, which collapsed them in the engine.
  • New ids are collision-free.
  • Legacy entries get deterministic ids, so the CLI and the MCP server derive the same ones.
  • The MCP engine's recall set follows edits and deletes, including ones made by another process.

Security

  • Shared validation in bin/record-validate.js, used by both the CLI and MCP:
    • ids: bounded length, no control characters
    • vectors: finite numbers of the store's dimension
    • metadata: a plain object with no __proto__/constructor/prototype keys at any depth; ≤64 KB, ≤8 levels
    • batches: ≤10k entries; k ≤ 1000
  • vectordb_* paths are confined to the project (RUVECTOR_MCP_ROOTS to widen) and are always explicit, so the ./ruvector.db default can never be created from MCP.
  • Memory updates re-embed through the same embedder and ADR-210 provenance gate as remember, so an edit cannot create a mixed store.
  • The readonly MCP profile gains only hooks_memory_get and hooks_memory_list. All new write tools stay hidden and can't be called.
  • RVF tools:
    • rvf_ingest, rvf_query and rvf_delete now validate their input.
    • rvf_open no longer leaks the store handle.
    • rvf_delete accepts string ids; it previously accepted only numbers, while the store uses string ids.

Tests

tests/crud.test.mjs: 9 end-to-end tests covering the library, CLI subprocesses and MCP over stdio, including rejection cases. 7 of them fail on 0.3.5; the other two are a unit test of the new id module and the readonly-profile check, which have nothing to compare against on 0.3.5. Locally, npm test passes and node --test tests/*.test.mjs passes 61/61.

Benchmark

scripts/bench/crud-bench.mjs (not shipped). Run: 10k × 384-dim, native, Linux x64. Values are p50 / p95.

op p50 p95
get 11.5 µs 14.7 µs
insert, new id 2.94 ms 4.25 ms
insert, existing id (upsert) 2.98 ms 4.04 ms
update, vector 2.68 ms 3.97 ms
update, metadata merge 2.57 ms 3.69 ms
delete 144 µs 195 µs
search, k=10 1.45 ms 2.23 ms
memory get / list / forget (5k store) 3.5 / 16 / 57 µs 10 / 100 / 126 µs
  • The upsert check costs one get (~12 µs) per id, under 0.5% of an insert, and is skipped entirely when loading into an empty store.
  • Backfilling ids on a 5k-memory store takes 8.6 ms, once.

🤖 Generated with claude-flow

…P, library)

Fixes a correctness bug in VectorDB.insert: re-inserting an existing id left
the old node in the native HNSW index, so search returned the id twice (once
with its stale vector); duplicate ids within one insertBatch did the same.
insert/insertBatch are now true upserts (last entry wins), at ~12 µs per
existing-id check and none for loads into an empty store. The root cause is
in the native core; this is the wrapper-level fix.

Library: VectorDB#update (never creates, optional metadata merge) and
VectorDB#deleteMany ({deleted, missing}).

CLI: `get`, `update`, `delete` for vector stores; `rvf delete`; hook memory
`memory-get`, `memory-list`, `memory-update` (re-embedded through the same
embedder and ADR-210 provenance gate as remember) and `forget`. recall now
returns memory ids.

MCP: vectordb_create/insert/get/update/delete/search/stats (paths confined to
the project, always explicit, never the ./ruvector.db default),
hooks_memory_get/list/update and hooks_forget. The readonly profile gains only
the two memory reads. RVF tools now validate entries, ids, vectors and k, and
always close the store (rvf_open leaked it; rvf_delete accepted only numbers
while the store takes string ids).

Memories get stable ids: new ids are collision-free (mem_<ms> collided within
a millisecond), legacy id-less entries get deterministic ids so the CLI and
MCP server agree, and the MCP engine's recall set is kept in step with edits
and deletes, including ones made by another process.

Input validation shared by CLI and MCP (bin/record-validate.js): ids (length,
control characters), finite vectors of the store's dimension, metadata as a
plain object with no __proto__/constructor/prototype keys at any depth and
bounded size/depth, batch and k caps.

Tests: tests/crud.test.mjs (9 e2e tests, 7 fail on 0.3.5). Benchmark:
scripts/bench/crud-bench.mjs.

Co-Authored-By: claude-flow <ruv@ruv.net>
@ruvnet
ruvnet merged commit e926f77 into main Nov 1, 2026
57 of 59 checks passed
@ruvnet
ruvnet deleted the feat/ruvector-full-crud branch November 1, 2026 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant