ruvnet / ruvnet/RuVector

Sweep: 91 panicky float sorts (`sort_by(partial_cmp().unwrap())`) across 27 crates — NaN-reachable in core query paths (ADR-340 invariant 1)

Open
#931 0 comments 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

Defect class

The #901 fix (NaN candidate confidence panicking route()) closed one instance of a pattern the workspace has 91 occurrences of, across 27 crates:

xs.sort_by(|a, b| a.partial_cmp(b).unwrap())

partial_cmp returns None when either operand is NaN, so every one of these sites panics the moment a NaN reaches it with 2+ elements. Per ADR-340 invariant 1, sorts over floats that originate outside the module's control must reject non-finite values at the boundary or use total_cmp (preferably both).

Inventory

grep -rn "sort_by(.*partial_cmp.*unwrap())" crates/*/src (excluding unwrap_or variants): 91 hits. Affected crates:

emergent-time, mcp-brain-server, ruvector-bench, ruvector-bounded-rag, ruvector-capgated, ruvector-consciousness, ruvector-core, ruvector-diskann, ruvector-entropy-ann, ruvector-graph, ruvector-graph-transformer, ruvector-hyperbolic-hnsw, ruvector-lsm-ann, ruvector-math, ruvector-matryoshka, ruvector-maxsim, ruvector-mincut-gated-transformer, ruvector-postgres, ruvector-query-cache, ruvector-sota-bench, ruvector-sparse-inference, ruvector-streaming-qng, ruvector-temporal-coherence, ruvector-tiny-dancer-core (non-router files), ruvllm, ruvllm-cli, ruvllm-wasm

Triage order — user-reachable first

Not all 91 are equal. The ones in query paths fed by user-supplied vectors are remotely triggerable: inserting or querying with a NaN component makes every distance NaN, and the first result sort panics the server. Highest priority:

  • ruvector-core/src/advanced_features/hybrid_search.rs:248 — result score sort
  • ruvector-core/src/advanced_features/diskann.rs:182,186,202,293,297,352 — distance sorts in search
  • ruvector-core/src/advanced_features/product_quantization.rs:257 — distance sort
  • ruvector-core/src/advanced_features/conformal_prediction.rs:148,316 — score quantiles
  • ruvector-core/src/agenticdb.rs:664 — utility-score sort
  • ruvector-core/src/advanced/{neural_hash.rs:297, tda.rs:93,301, hypergraph.rs:262,446}
  • ruvector-graph/src/typed_graph.rs:745

ruvector-postgres deserves special mention: a panic inside a Postgres extension aborts the backend process, so a single NaN in a query vector is a crash for every connection sharing it.

Second tier: bench/CLI/analysis crates (ruvector-bench, ruvllm-cli, mcp-brain-server, …) where a panic costs a run, not a service.

Suggested mechanics

  • Mechanical rewrite a.partial_cmp(b).unwrap()a.total_cmp(b) where the element type is f32/f64 directly, and f32::total_cmp on the projected key for tuple/struct sorts. This is behavior-preserving for all finite inputs and NaN-total otherwise.
  • Where the crate already has an input-validation boundary (e.g. ruvector-core insert/query dimension checks), also reject non-finite components there so degenerate inputs fail loudly instead of ordering NaNs — matching the #901 fix shape.
  • Add one shared regression pattern: query with a NaN component must return an error (validated boundary) or a stable ordering (total_cmp), never a panic.
  • A clippy lint can hold the line: disallowed_methods for partial_cmp inside sort_by isn't directly expressible, but a repo-level grep gate in CI (like the ADR index check) is trivial and catches regressions.

Found during the ADR-340 hardening pass; #901 fixed the router instance, this issue tracks the remaining 91.

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 with the inventory command and the priority sites in ruvector-core/src/advanced_features/, ruvector-core/src/agenticdb.rs, and ruvector-graph/src/typed_graph.rs. Check the existing #901 validation shape and identify relevant insert/query tests before working through the 91 hits. Done means no listed panicking float sorts remain, user-reachable NaN inputs error or sort stably, and the regression pattern and CI grep gate are covered.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend, databases, security, testing
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.