ruvnet / ruvnet/RuVector

bug(rvf-runtime): RvfStore::open() resets metric to L2 and zeroes last_witness_hash

Open
#747 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

Summary

RvfStore::create(path, options) honors options.metric (e.g. DistanceMetric::Cosine).
RvfStore::open(path) constructs:

let opts = RvfOptions {
    domain_profile,
    ..Default::default()  // metric: L2
};
// last_witness_hash: [0u8; 32]

boot() restores dimension and profile from the MANIFEST, but never restores metric. Metric is not written into the manifest. A reopen silently switches distance ranking to L2 and restarts the witness chain at zeros.

Affected versions

  • Confirmed: 0.2.0 store.rs open / boot
  • Still present in spirit: 0.3.0 (open still ..Default::default(), no metric on parsed manifest)

Repro

use rvf_runtime::{DistanceMetric, RvfOptions, RvfStore};

fn main() {
    let dir = tempfile::tempdir().unwrap();
    let path = dir.path().join("metric.rvf");
    {
        let opts = RvfOptions {
            dimension: 3,
            metric: DistanceMetric::Cosine,
            ..Default::default()
        };
        let mut s = RvfStore::create(&path, opts).unwrap();
        let a = [1.0f32, 0.0, 0.0];
        let b = [10.0f32, 10.0, 0.0];
        s.ingest_batch(&[&a, &b], &[1, 2], None).unwrap();
        // If metric() accessor exists (0.3+): assert_eq!(s.metric(), Cosine);
        let _ = s.last_witness_hash(); // non-zero after witness_ingest
    }
    let s2 = RvfStore::open(&path).unwrap();
    // Actual: distance path uses L2; last_witness_hash() == [0; 32]
    // Expected: Cosine preserved; witness chain tip restored from file
    let _ = s2;
}

Expected

  1. Persist metric (and other durable options) in MANIFEST.
  2. Restore on open/boot.
  3. Restore or recompute last_witness_hash from the latest WITNESS segment so reopen continues the chain.

Optional API: open_with_options only for non-persisted overrides.

Downstream impact

WeftOS never uses Cosine at create time: we L2-normalize all vectors and always create with L2 (agenticow pattern) so reopen cannot change ranking. Witness restart on reopen is documented as a residual. Prefer a durable metric so other consumers are not foot-gunned.

Reported from WeftOS WEFT-662.

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 store.rs at RvfStore::open and boot, then inspect how MANIFEST data and the latest WITNESS segment are parsed. Reproduce the reopen case from the issue and trace where metric defaults to L2 and last_witness_hash is zeroed. Done means durable metric restoration and witness-chain continuation after reopen, with regression coverage for both behaviors.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.