ruvnet / ruvnet/RuVector

graph-node 2.1.0: createEdge/batchInsert silently discard metadata, blocking lossless recovery

Open
#984 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
4.5k
Forks
603
Avg merge
23h 32m
Merged PRs (30d)
59

Description

Reproduced on the current published native binding

@ruvector/graph-node@2.1.0 (npm latest checked 2026-09-13), Node 24.14.1, macOS arm64. Resolved from @claude-flow/cli@3.41.2.

Both createEdge() and batchInsert() accept the documented metadata: Record<string,string>, return successful edge IDs, and retain endpoints/connectivity after a fresh-process reopen. However, all supplied edge metadata is absent from query results before and after reopen. Node properties round-trip in the same fixture.

Source inspection confirms this is not merely a result projection: create_edge and batch_insert build persisted edge properties from only __confidence and __embedding, never copying edge.metadata. run_query returns non-internal properties, so public metadata would be observable if stored.

Minimal disposable reproduction

Use a new temporary directory, never a live managed graph. Run writer and reader in separate processes against that temporary path.

const db = new GraphDatabase({
  storagePath: temporaryGraphPath, dimensions: 8, distanceMetric: 'Cosine'
});
const embedding = new Float32Array([1,0,0,0,0,0,0,0]);
for (const id of ['mem:a', 'mem:b', 'mem:c'])
  await db.createNode({ id, embedding, properties: { diagnostic: 'true' } });
const edge = {
  from: 'mem:a', to: 'mem:b', description: 'supports', embedding,
  confidence: 0.75,
  metadata: {
    sourceEdgeId: 'fixture-source-edge',
    weight: '0.8',
    metadata: JSON.stringify({ witness: 'fixture-witness' })
  }
};
await db.createEdge(edge);
await db.batchInsert({ nodes: [], edges: [{ ...edge, to: 'mem:c' }] });
console.log(await db.query('MATCH (a)-[r]->(b) RETURN a,r,b'));
// nodes: diagnostic property retained
// both edges: properties: {}

A fresh reader process with the same options returns the same endpoints/types and empty edge properties. Counts remain 3 nodes / 2 edges. This issue does not dispute the connectivity/persistence fixes in #809/#879/#938.

Impact and bounded proposed fix

This blocks lossless reconstruction of a native graph from retained managed SQL relationships: weights carried as public metadata, witnesses, original SQL edge identity and other metadata cannot be verified or retained by this API. Retrying causal-edge writes in Ruflo is not an acceptable workaround because that handler also writes SQL.

  • Copy public JsEdge.metadata into stored edge properties in both single and batch insertion, with an explicit collision policy for reserved internal keys.
  • Preserve native confidence/embedding handling; do not repurpose relation type or node IDs to smuggle metadata.
  • Test exact public metadata before and after a separate-process reopen, including Unicode, JSON strings and reserved-key behavior.
  • Audit createHyperedge() separately: source appears to ignore its metadata too, but the executed reproduction above covers ordinary edges only.
  • Keep missing metadata observable; do not return successful import/recovery receipts without fidelity verification.

Related downstream persistence adapter fix: https://github.com/ruvnet/ruflo/issues/3313 . The constructor patch enables durable future graph writes but cannot repair this compiled native metadata omission. No production databases were changed during these tests.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in crates/ruvector-graph-node/src/lib.rs at the create_edge and batch_insert implementation, then run the disposable two-process JavaScript reproduction against a temporary graph path. Done means public edge metadata, including Unicode and JSON strings, is returned before and after reopen, while confidence and embedding handling and reserved-key behavior remain correct.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, rust
Domain
api, databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.