VelesQL Ecosystem Parity Matrix

August 19, 2026 · View on GitHub

Last updated: 2026-08-19 (v5.1.0; velesdb-memory 0.14.0)

This matrix tracks runtime contract and feature parity across the VelesDB ecosystem.

Contract Baseline

  • Canonical REST contract: docs/reference/VELESQL_CONTRACT.md
  • Canonical conformance fixture: conformance/velesql_contract_cases.json
  • Contract version: 3.0.0

Endpoint and Payload Parity

Surface/query/aggregate/collections/{name}/matchError model (code/message/hint/details)Contract meta
velesdb-serveryesyesyesyesyes (meta.velesql_contract_version)
TypeScript SDK (REST backend)yesyes (auto-routed for aggregate queries)indirectyes (nested error parsing)yes
WASM SDKno (/query unsupported by design)nonon/an/a
CLI (velesdb-cli)yes via server/core pathyes via server/core pathindirectpartial passthroughpartial assertion
Python bindings (velesdb-python)core path (non-REST)core path (non-REST)core path (non-REST)n/a RESTn/a REST
LangChain integrationvia Python bindingvia Python bindingvia Python bindingn/a RESTn/a REST
LlamaIndex integrationvia Python bindingvia Python bindingvia Python bindingn/a RESTn/a REST
Haystack integrationvia Python bindingvia Python bindingvia Python bindingn/a RESTn/a REST

Feature Parity Matrix (86 features, 11 components)

Legend: ✅ full support | ⚠️ partial / limited | ❌ not supported | N/A not applicable

Feature GroupCoreServerPythonWASMMobileCLITS SDKTauriLangChainLlamaIndexHaystack
Vector CRUD (insert, upsert, delete, get)
Batch Operations (batch_insert, batch_upsert)⚠️⚠️
Streaming Ingestion (enableStreaming / stream_insert)⚠️⚠️⚠️⚠️
Vector Search (k-NN, filtered, batch)
Multi-Query Fusion (RRF)⚠️
Multi-Query Fusion (RSF / Weighted)⚠️⚠️
Hybrid Search (dense+sparse, dense+text)⚠️
Text Search BM25⚠️
Sparse Vector Search (sparse index)
Sparse Vector Search (named indexes)⚠️⚠️
Graph Operations (nodes, edges, traversal)⚠️N/A
Cross-Collection MATCH (@collection)⚠️⚠️
VelesQL (parser + executor)⚠️⚠️⚠️
Collection Types (Vector)
Collection Types (Graph)N/A
Collection Types (Metadata)⚠️⚠️⚠️⚠️
Property Indexes (secondary, trigram)⚠️
Quantization (SQ8 / Binary / PQ)
Quantization (RaBitQ)⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
Agent Memory (semantic, episodic, procedural)⚠️⚠️⚠️N/A⚠️⚠️N/A
Persistence (WAL / mmap)N/AN/AN/AN/AN/AN/A
GPU Acceleration (wgpu)

Notes

  • Cross-Collection MATCH: Core and Server support @collection annotation on MATCH node patterns. Python bindings support via _collection param. CLI supports via \use. Mobile reaches it through execute_query (full VelesQL pass-through, crates/velesdb-mobile/src/lib.rs:342). WASM, Tauri, and integrations do not yet expose this feature.

  • Batch Operations: WASM and Mobile use streaming chunked inserts instead of single-call bulk to stay within memory constraints. WASM additionally exposes a single-call raw-bulk path via VectorStore.insertBatchRaw (see the Raw-Bulk Insert note).

  • Streaming Ingestion (2026-07-23): Core, Server (POST /collections/{name}/stream/enable + /stream/insert), Python, Tauri, Mobile (enableStreaming() / streamInsert() on its own tokio streaming runtime), and the TS SDK (enableStreaming() / streamInsert(), REST backend) support the bounded ingestion channel. The CLI reaches it ⚠️ via the embedded core path with no dedicated REPL command. WASM throws NOT_SUPPORTED (no persistence layer). LangChain and LlamaIndex expose ⚠️ streaming via stream_insert()/add_texts_streaming()/add_streaming(), which forward to collection.stream_insert (caller is responsible for enable_streaming; covered by mock-collection unit tests). Haystack now exposes the same ⚠️ shape via VelesDBDocumentStore.stream_insert()/write_documents_streaming() (issue #1548), forwarding to collection.stream_insert with the same caller-managed enable_streaming contract.

  • Raw-Bulk Insert (2026-06-14): the zero-copy raw-bulk path is now exposed by Core (upsert_bulk_from_raw), Server (POST /collections/{name}/points/raw, VRB1 binary), the TS SDK (upsertBatchRaw), WASM (VectorStore.insertBatchRaw(ids, vectors, dim), writing into its in-memory buffer), and the CLI (velesdb data import <file.bin>, VRB1 binary). Mobile remains a follow-up. All surfaces share the one velesdb_core::wire::vrb1 codec.

  • Multi-Query Fusion (RSF/Weighted) (2026-06-14): WASM's multi-query fuse_results now delegates 4 of its 5 strategies (average, maximum, weighted, rrf) to the canonical velesdb_core::FusionStrategy::fuse, so the browser engine reproduces core's ranking 1:1 for those (crates/velesdb-wasm/src/fusion.rs; equivalence pinned by test_fuse_results_matches_core_ordering). The fifth strategy, relative_score / rsf, is intentionally kept WASM-local: core's RelativeScore is a two-branch (dense + sparse) weighted sum that zero-fills documents missing from a branch and discards branches beyond index 1, whereas WASM's is an N-branch equal-weight average that skips missing branches. The two semantics yield different rankings, so converging WASM onto core would silently change WASM search results — that convergence is a product decision deferred to a follow-up, and relative_score behaviour is unchanged. (This is the multi-query fusion entry point; the VelesQL USING FUSION (...) clause executor in velesql_fusion.rs already builds every strategy — including RSF — directly from velesdb_core::fusion::FusionStrategy.) LangChain and LlamaIndex expose RSF/Weighted through multi_query_search(fusion=...), which delegates to the shared velesdb_common.fusion.build_fusion_strategy (builds weighted() and relative_score()). Haystack reaches RSF/Weighted/RRF/etc. fusion via its own VelesDBDocumentStore.embedding_retrieval(fusion=..., fusion_params=...), which delegates to velesdb_common.fusion.build_fusion_strategy and Collection.multi_query_search.

  • Sparse Vector Search (named indexes) — LangChain/LlamaIndex: ⚠️ query-side only. Both integrations forward a sparse_index_name argument to the underlying collection.search/hybrid_search, so an existing named sparse index can be queried. Named sparse indexes are also created on the upsert/write path: passing a named mapping such as {"bge_m3": {0: 1.5}} to add_texts/add/add_bulk (LC/LI) or write_documents (Haystack) creates the named index, validated by velesdb_common.security.validate_named_sparse_vector.

  • LangGraph integration (2026-07-23, updated #1546): integrations/langgraph ships ten memory tools via make_memory_toolsremember (with links/metadata/ttl_seconds), recall, recall_where, recall_fused (incl. date_field= dated timelines), relate, forget, feedback, why, and save_working_context/load_working_context. That is not the whole wedge: entity, unrelate, and the context-compiler tools are not exposed (see the memory-surface gap block below). It is deliberately narrow — no vector-store surface — and is not yet a column in the matrices above. Remaining gap: list_working_contexts is not exposed by the LangGraph toolkit, though the velesdb Python binding (MemoryService.list_working_contexts) does have it since 0.11.x — load_working_context's other_sessions now covers the typo-recovery case the listing was mainly wanted for. The package's velesdb>=3.12.0 floor is deliberately kept there pending the 5.0.0 release that carries the load_working_context envelope (CHANGELOG [Unreleased]) — later velesdb releases exist on PyPI, but floors move with the 5.0.0 release train; feedback, save_working_context, load_working_context, and the _veles_date auto-stamp below landed in source after the 3.12.0 cut and need that release to work (see the integration's README "Compatibility" section).

  • Auto _veles_date stamp (introduced in velesdb-memory 0.11.0): every remember now auto-stamps a reserved _veles_date metadata field (YYYYMMDD, caller-set value never overwritten), making recall_fused(date_field=…) work with zero setup. Surfaced by delegation in Python (tests/test_memory_service.py asserts the stamp) and Node (recallFusedDated). WASM is read-side only: no clock exists on wasm32-unknown-unknown, so the WASM write path never stamps _veles_date (MemoryService::remember_with_ttl's contract) — recallFusedDated exists there, but zero-setup dating does not; a caller must set _veles_date explicitly for the timeline to fill. The TS SDK (which wraps WASM) types and documents the _veles_date key (sdks/typescript/src/memory.ts, MemoryMetadata._veles_date) and ships recallFusedDated, under the same explicit-stamp caveat. LangGraph now exposes recall_where/recall_fused(date_field=…) to reach it too (see above), pending a velesdb release past 3.12.0.

  • load_working_context returns an ENVELOPE on every surface (velesdb-memory 0.12.0): {found, working, other_sessions} — the MCP tool, the Node, Python and WASM bindings, and the TS SDK. Breaking for the three bindings and the SDK, which until 0.12.0 returned the bare working context (or null/None): read .working for that value. The bare form could not express the difference between "nothing was ever saved" and "a typo in session missed a session that exists" — other_sessions names the near-misses, and is filled in on a hit too, since a typo landing on another REAL session is the case a caller can least detect. Shape parity is now enforced, not just method-name parity: crates/velesdb-memory/tests/binding_parity_bdd.rs reads each tool's output_schema root keys off the LIVE server and requires every binding to relay them or declare the divergence. Three pre-existing divergences it surfaced were declared there as known gaps (six entries, since two of them spanned more than one binding): all three bindings dropped entity.relations_in (added server-side by #1681), the Node binding's CompiledContextJs dropped compile_context.warnings, and both the Node and Python bindings dropped remember_extracted.skipped_over_cap. All six are closed (#1690, #1691, #1692); SHAPE_DIVERGENCES now holds deliberate unwraps only.

  • The TypeScript SDK is inside a guard's perimeter (#1721): it had never been in one, and shipped 17 of the 19 methods the WASM binding exposed for its whole life — entity and unrelate were simply absent. It is checked as a SECOND LINK rather than as a fourth binding: the SDK wraps the WASM bundle and can never publish more than it does, so the invariant is "the SDK relays every tool that reaches WASM", composed with the existing "WASM relays every tool the server advertises". Framing it as a fourth binding would have duplicated WASM's feedback exemption into a second list — and a decision recorded twice is a decision that will drift. The reader is a small TypeScript-aware scan in the same file, because the tool list comes from a REAL running MCP server; a check living in the SDK's own test suite would have had to hard-code that list, which is the very defect #1721 reports.

  • Graph Operations (WASM): Basic node/edge CRUD is supported; multi-hop traversal and MATCH queries are limited.

  • VelesQL (LangChain/LlamaIndex/Haystack): Pass-through to Python bindings works for simple queries; full parser integration is not surfaced in the integration API.

  • Haystack DocumentStore protocol limits: The Haystack 2.x DocumentStore ABC exposes write_documents, filter_documents, embedding_retrieval, count_documents, and delete_documents. Dense retrieval in pipelines ships as the dedicated VelesDBEmbeddingRetriever component (integrations/haystack/src/haystack_velesdb/retriever.py); BM25/hybrid retriever components remain a follow-up. Graph collections, agent memory, and sparse-named indexes are intentionally N/A because they have no idiomatic mapping in Haystack's protocol and are reachable through the raw velesdb Python wrapper if needed.

  • Collection Types (Metadata): WASM and integration SDKs expose metadata collections with reduced column-type support.

  • Property Indexes (WASM): Disabled by design — no persistence layer means indexes cannot survive page reloads.

  • Quantization (RaBitQ): Experimental across all surfaces; API is unstable.

  • Agent Memory (Server): ⚠️ — durable point TTL is exposed over REST (PATCH /collections/{name}/points/{id}/ttl, persisted as _veles_expires_at and enforced on every read surface — search/get/scroll/ query/MATCH), and relation edges are managed via POST /collections/{name}/relations, DELETE .../relations/{edge_id}, and GET .../points/{id}/relations. Still embedded-only: temporal/confidence-only queries, reinforcement, and snapshots. Per-binding parity for the relation + durable-TTL surface:

    OperationRESTTS SDK (REST backend)TS SDK (WASM backend)Python
    relate() (create edge)POST .../relationsclient.relate()❌ (wasmRelate throws NOT_SUPPORTED — REST backend only)❌ (use GraphCollection.add_edge or the core API)
    unrelate() (delete edge)DELETE .../relations/{edge_id}client.unrelate()❌ (throws NOT_SUPPORTED)
    getRelations() (list outgoing)GET .../points/{id}/relationsclient.getRelations()❌ (throws NOT_SUPPORTED)
    Durable TTL set/refreshPATCH .../points/{id}/ttlclient.setTtlDurable()❌ (throws NOT_SUPPORTED)set_semantic/episodic/procedural_ttl_durable, store_with_ttl, record_with_ttl, learn_with_ttl
    Temporal recall facadesn/a (use /query)recallRecent / recallOlderThan❌ (throws NOT_SUPPORTED)episodic.recent / episodic.older_than
  • Agent Memory (WASM / Mobile): WASM now ships the high-level MemoryService wedge (remember — incl. per-fact ttlSeconds — /recall/recallWhere/recallFused/relate/unrelate/forget/entity/why/rememberExtracted; in-memory only, no persistence under WASM, #1310) alongside the primitive SemanticMemory. rememberExtracted on WASM (and on the TS SDK wrapping it) runs the deterministic, network-free outline extractor ONLY — a generative backend ("ollama") is refused by name rather than silently substituted, because it would put a network call in the bundle (crates/velesdb-wasm/src/memory_service.rs, sdks/typescript/src/memory.ts rememberExtracted). feedback remains deliberately absent on WASM (it sits behind the persistence feature; a durable learned confidence is meaningless for a store that disappears on page reload). Mobile remains ⚠️ semantic-only (VelesSemanticMemory). Episodic/procedural memory, the standalone TTL setters (setTtlDurable-style), and snapshots are not exposed on these bindings.

  • Auto-extraction (text → graph): lives in the high-level velesdb-memory MCP server, not in this core-feature matrix. MemoryService::remember_extracted (and the remember_extracted MCP tool) run an Extractor over raw text and auto-wire the fact↔topic graph; MCP accepts the backend per call, with the daemon's configured backend as the default and outline always available. The reusable core primitive it builds on is SemanticMemory::query_excluding (negative-filter vector search, used to keep internal entity hubs out of recall/why). The MCP recall/why tools inherit hub-exclusion transparently. The high-level MemoryService wedge (remember/recall/recall_where/relate/forget/why/remember_extracted) is now exposed beyond the MCP server in Python (velesdb-python, #1242), Node.js (velesdb-node / npm @wiscale/velesdb-memory-node, #1245), and the TS/WASM SDK (MemoryService over the in-browser backend, #1310 — rememberExtracted included there via the deterministic outline extractor only; a generative backend is refused, see the Agent Memory (WASM / Mobile) note).

  • Persistence (WASM): Disabled by design — persistence feature flag is excluded for wasm32-unknown-unknown targets.

  • GPU: Requires gpu feature flag; only available in crates that link wgpu (core, server, Python bindings).

Feature Execution Parity (Core Runtime)

FeatureParserExecutorStatus
SELECT ... FROM ... WHERE ...yesyesstable
MATCH (...) RETURN ...yesyesstable
MATCH via /query with collectionyesyesstable
JOIN ... ONyesyesstable
JOIN ... USING (...)yesyes (single-column)stable
LEFT/RIGHT/FULL JOINyesyesstable
GROUP BY, HAVINGyesyesstable
UNION/INTERSECT/EXCEPTyesyesstable

Conformance Test Coverage

SurfaceFixtureTest
Server REST contractconformance/velesql_contract_cases.jsoncrates/velesdb-server/tests/velesql_conformance_tests.rs
TypeScript SDK contract mappingconformance/velesql_contract_cases.jsonsdks/typescript/tests/velesql-contract-fixtures.test.ts
Core executor (rows/counts/ordering)conformance/velesql_executor_cases.jsoncrates/velesdb-core/tests/velesql_executor_conformance.rs
CLI executor (rows/counts/ordering)conformance/velesql_executor_cases.jsoncrates/velesdb-cli/tests/velesql_executor_conformance.rs
WASM executor (rows/counts/ordering)conformance/velesql_executor_cases.jsoncrates/velesdb-wasm/src/velesql_executor_conformance_tests.rs
Core parserconformance/velesql_parser_cases.jsoncrates/velesdb-core/tests/velesql_parser_conformance.rs
CLI parserconformance/velesql_parser_cases.jsoncrates/velesdb-cli/tests/velesql_parser_conformance.rs
WASM parserconformance/velesql_parser_cases.jsoncrates/velesdb-wasm/tests/velesql_parser_conformance.rs

The executor fixture (added 2026-06-14, extended 2026-06-20) asserts the exact result set (ids, count, ordering) each executor produces for a fixed dataset. As of 2026-06-20 the WASM and CLI executors are fixture-checked against the same goldens too — the CLI drives the real binary end-to-end and WASM runs its own SELECT/ORDER BY pipeline — so a result-shape divergence on those surfaces fails CI rather than going unnoticed. Coverage includes scalar WHERE filters, single- and multi-column ORDER BY, the ascending-id tie-break, and bounded top-k (ORDER BY ... LIMIT k); see KNOWN_LIMITATIONS #13 (resolved).

Enum Propagation Matrix

Tracks whether core enums are fully propagated to each ecosystem component.

Legend: ✅ full (all variants) | N/A not applicable (brute-force only, no HNSW)

DistanceMetric — 10/10 (100%)

All 5 variants (Cosine, Euclidean, DotProduct, Hamming, Jaccard) are supported in all 10 components (Haystack inherits via the Python binding pass-through).

ComponentStatus
Core✅ (source of truth)
Server
Python
WASM
Mobile
CLI
TS SDK
Tauri
LangChain
LlamaIndex
Haystack

StorageMode — 10/10 (100%)

All 5 variants (Full, SQ8, Binary, ProductQuantization, RaBitQ) are supported in all 10 components (Haystack inherits via the Python binding pass-through).

ComponentStatus
Core✅ (source of truth)
Server
Python
WASM
Mobile
CLI
TS SDK
Tauri
LangChain
LlamaIndex
Haystack

FusionStrategy — 10/10 (100%)

All 4 strategies (RRF, Weighted, Maximum, RSF) plus Average are supported in all 10 components (Haystack reaches RSF/Weighted/RRF/etc. fusion via its own VelesDBDocumentStore.embedding_retrieval(fusion=..., fusion_params=...), which delegates to velesdb_common.fusion.build_fusion_strategy and Collection.multi_query_search).

ComponentStatus
Core✅ (source of truth)
Server
Python
WASM
Mobile
CLI
TS SDK
Tauri
LangChain
LlamaIndex
Haystack

SearchQuality — 9/10

4 HNSW presets (Fast, Balanced, Accurate, Perfect) plus Custom(usize) and Adaptive. WASM uses brute-force search (no HNSW), so SearchQuality is not applicable there; Mobile and Tauri are HNSW-backed via core defaults and expose the presets (crates/velesdb-mobile/src/types.rs SearchQuality, crates/tauri-plugin-velesdb/src/helpers.rs parse_search_quality).

ComponentStatusNotes
Core✅ (source of truth)
Server
Python
WASMN/ABrute-force only, no HNSW index
MobileSearchQuality enum mapped to core (search_with_quality)
CLI
TS SDK
Taurisearch_quality param + hnsw_m/hnsw_ef_construction at creation
LangChain
LlamaIndex
Haystack

CollectionType — 9/10

3 types (Vector, MetadataOnly, Graph). All native crates expose graph collection creation; only Haystack is limited by its DocumentStore protocol.

ComponentStatusNotes
Core✅ (source of truth)
Server
Python
WASM
Mobilecreate_graph_collection / create_graph_collection_with_embeddings exposed via #[uniffi::export]
CLI
TS SDK
Tauri
LangChain
LlamaIndex
Haystack⚠️ 1/3Vector only — Graph and MetadataOnly have no idiomatic mapping in the Haystack DocumentStore protocol

Propagation Summary

EnumCoverageStatus
DistanceMetric10/10100%
StorageMode10/10100%
FusionStrategy10/10100%
SearchQuality9/10N/A for WASM only (brute-force, no HNSW)
CollectionType9/10Haystack Vector only by protocol; all native crates full

Recently Landed (2026-06-14)

  • WASM fusion now delegates 4/5 strategies to core. average/maximum/weighted/rrf map onto velesdb_core::FusionStrategy::fuse (ranking identical to core, pinned by an equivalence test); relative_score/rsf stays WASM-local by design because its N-branch equal-weight semantics differ from core's two-branch dense+sparse weighted sum. See the RSF/Weighted note above.
  • Executor-level conformance now exists for core. conformance/velesql_executor_cases.json + crates/velesdb-core/tests/velesql_executor_conformance.rs assert result rows/counts/ordering (not just that a query parses). Extended to the WASM and CLI executors on 2026-06-20 (action item 2 — now done).
  • Scalar ORDER BY + LIMIT correctness bug fixed. A scalar (non-similarity()) ORDER BY <col> ... LIMIT k previously truncated to k in storage order before sorting; it now fetches the full matching set so the sort precedes truncation, restoring the KNOWN_LIMITATIONS #9 bounded==unbounded guarantee. The similarity()-ordered HNSW fast path was untouched, so recall is unaffected. (Surfaced by the new executor conformance net above.)
  • Point-ID hashing single-sourced for Haystack. The Haystack DocumentStore now imports the canonical velesdb_common.ids.stable_hash_id instead of a bit-identical forked copy (behaviour-preserving; removes a re-implemented hash from an MIT package). The intentional remaining divergence — velesdb-migrate's distinct stable_point_id — is documented in KNOWN_LIMITATIONS #12.
  • (2026-07-23) FNV-1a stable-hash dedup, plus an opt-in Python alignment path (#1542). velesdb-core now exports a public hash_id_bytes; velesdb-memory::id::stable_id[_bytes] and velesdb-migrate::pipeline::fnv1a64 delegate to it instead of each re-declaring the FNV-1a offset/prime constants — behaviour-preserving (golden-vector regression tests pin the pre-refactor output for ASCII and multi-byte UTF-8). This removes the duplication risk flagged by the parity audit but does not change the ecosystem-level divergence: velesdb_common.ids.stable_hash_id's SHA-256 default is intentionally unchanged (flipping it would orphan every string ID already stored via LangChain/LlamaIndex/Haystack). It gains an opt-in algorithm="fnv1a" parameter, pure-Python and MIT-licensed, verified byte-for-byte against core's published golden vectors, for callers that need a Python-derived ID to agree with core/velesdb-migrate's FNV-1a for the same string. velesdb-migrate's numeric-preserve fast-path is now explicitly documented as a third, deliberately distinct semantics. Full contract in KNOWN_LIMITATIONS #12.

Remaining Gaps and Action Items

  1. Done (2026-06-24). Explicit server-side assertions for the full REST VelesqlErrorResponse shape (code/message/hint/details) are now enforced in crates/velesdb-server/tests/velesql_conformance_tests.rs via the shared fixture. Cases C002 (VELESQL_MISSING_COLLECTION), C003 (VELESQL_COLLECTION_NOT_FOUND), and C007 (VELESQL_AGGREGATION_ERROR) each assert all four fields, pinning the complete error body contract for the /query and /aggregate semantic-error paths. Parse errors (QueryErrorResponse) retain their own parser-specific shape and are tested separately by C004/C013 (status code only, by design — the parser error format is defined at E0XX layer). (The CLI has no HTTP layer — it executes against embedded core — so this contract belongs exclusively to velesdb-server.)
  2. Done (2026-06-20). The executor-level conformance net now covers core, WASM, and CLI — all three run conformance/velesql_executor_cases.json, including scalar WHERE filters, single- and multi-column ORDER BY, the ascending-id tie-break, and bounded top-k. See KNOWN_LIMITATIONS #13 (resolved).
  3. Keep docs, fixtures, and examples synchronized on every contract version change.
  4. Promote RaBitQ from experimental to stable once the API is finalized.
  5. Done. RSF/Weighted fusion is exposed in Haystack via embedding_retrieval(fusion=...) through velesdb_common.fusion (already exposed in LangChain and LlamaIndex via the shared velesdb_common.fusion module).
  6. Done. Named-sparse-index creation is exposed on the upsert/write path of LangChain, LlamaIndex, and Haystack (query-side sparse_index_name targeting already works).
  7. Propagate @collection cross-collection MATCH to WASM, Mobile, Tauri, LangChain, LlamaIndex, and Haystack.
  8. Add cross-collection vector search (similarity() on @collection-annotated nodes).
  9. Memory-surface gaps (2026-08 audit).
    • Autograph exposure: the decoupled autograph path (MemoryService::spawn_autograph_worker) is spawned only by the MCP server/daemon (McpServer::new); the Python, Node, and TS-SDK bindings expose no way to enable autograph at all — neither the inline mode nor the worker. Follow-up decision: expose it, or record the daemon-only scoping as deliberate.
    • LangGraph toolkit omissions: make_memory_tools exposes ten tools and deliberately omits entity, unrelate, and every context-compiler tool (plus list_working_contexts, tracked above). Presumed by-design toolkit scoping — to be confirmed and recorded, not inferred.
    • Mobile: velesdb-mobile ships only a thin semantic-memory slice (VelesSemanticMemory) plus its own RAM-only MobileGraphStore; no doc records whether full memory-wedge parity on mobile is wanted or declined. Open decision.
    • REST relation/TTL divergences from the memory wedge (documented pending a decision, not silently): REST relate (POST /collections/{name}/relations, crates/velesdb-server/src/handlers/points/relations.rs:114) is non-idempotent — a fresh auto-assigned edge id per POST, and no self-loop refusal — where the wedge derives the edge id from (from, relation, to) and refuses from == to; REST unrelate (DELETE .../relations/{edge_id}, relations.rs:204) answers 404 on an absent edge where the wedge replays safely with found: false; REST TTL (PATCH .../points/{id}/ttl, relations.rs:290) accepts ttl_seconds: 0 as expire-now where the wedge refuses Some(0) (ZeroTtl).
  10. Read-path gate (observer) parity (audit F-5.4). The 3.10.0 read-path gate — velesdb_core::observer + database::gated_search / authorize_read (scope AND-composed with the caller filter, fail-closed on non-filterable paths) — is wired into velesdb-server (search/match/graph handlers) and velesdb-python (.search() gating). tauri-plugin-velesdb ships a notify-only observer (no deny). velesdb-mobile now ships a deny-capable observer (open_with_observer + MobileObserver/MobileAccessDecision, crates/velesdb-mobile/src/lib.rs:145). velesdb-node (memory-only, out of scope by design) and velesdb-wasm expose no observer, so the gate is inactive there. This is a parity gap, not a vulnerability: the core contract is fail-open only when no observer is registered (no policy ⇒ no denial to enforce), so an ungated binding simply has no governance layer to bypass. Governance-sensitive deployments must use the server or Python surface. Wiring an observer hook into mobile/wasm is a follow-up; node is intentionally excluded (it never touches the gated core Collection).