Skip to content

Commit 5147a27

Browse files
authored
Merge pull request #149 from ruvnet/claude/crv-ruvector-integration-Fbl4V
2 parents 5925746 + 7d54946 commit 5147a27

13 files changed

Lines changed: 3108 additions & 1 deletion

File tree

Cargo.lock

Lines changed: 14 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ members = [
7171
"crates/ruvector-delta-index",
7272
"crates/ruvector-delta-graph",
7373
"crates/ruvector-delta-consensus",
74+
"crates/ruvector-crv",
7475
]
7576
resolver = "2"
7677

crates/ruvector-crv/Cargo.toml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[package]
2+
name = "ruvector-crv"
3+
version = "0.1.0"
4+
edition = "2021"
5+
authors = ["ruvector contributors"]
6+
description = "CRV (Coordinate Remote Viewing) protocol integration for ruvector - maps 6-stage signal line methodology to vector database subsystems"
7+
license = "MIT OR Apache-2.0"
8+
repository = "https://github.com/ruvnet/ruvector"
9+
keywords = ["crv", "signal-line", "vector-search", "attention", "hyperbolic"]
10+
categories = ["algorithms", "science"]
11+
12+
[lib]
13+
crate-type = ["rlib"]
14+
15+
[features]
16+
default = []
17+
18+
[dependencies]
19+
ruvector-attention = { path = "../ruvector-attention" }
20+
ruvector-gnn = { path = "../ruvector-gnn" }
21+
ruvector-mincut = { path = "../ruvector-mincut", default-features = false, features = ["exact"] }
22+
serde = { version = "1.0", features = ["derive"] }
23+
serde_json = "1.0"
24+
thiserror = "1.0"
25+
26+
[dev-dependencies]
27+
approx = "0.5"

crates/ruvector-crv/src/error.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//! Error types for the CRV protocol integration.
2+
3+
use thiserror::Error;
4+
5+
/// CRV-specific errors.
6+
#[derive(Debug, Error)]
7+
pub enum CrvError {
8+
/// Dimension mismatch between expected and actual vector sizes.
9+
#[error("Dimension mismatch: expected {expected}, got {actual}")]
10+
DimensionMismatch { expected: usize, actual: usize },
11+
12+
/// Invalid CRV stage number.
13+
#[error("Invalid stage: {0} (must be 1-6)")]
14+
InvalidStage(u8),
15+
16+
/// Empty input data.
17+
#[error("Empty input: {0}")]
18+
EmptyInput(String),
19+
20+
/// Session not found.
21+
#[error("Session not found: {0}")]
22+
SessionNotFound(String),
23+
24+
/// Encoding failure.
25+
#[error("Encoding error: {0}")]
26+
EncodingError(String),
27+
28+
/// Attention mechanism error.
29+
#[error("Attention error: {0}")]
30+
AttentionError(#[from] ruvector_attention::AttentionError),
31+
32+
/// Serialization error.
33+
#[error("Serialization error: {0}")]
34+
SerializationError(#[from] serde_json::Error),
35+
}
36+
37+
/// Result type alias for CRV operations.
38+
pub type CrvResult<T> = Result<T, CrvError>;

crates/ruvector-crv/src/lib.rs

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
//! # ruvector-crv
2+
//!
3+
//! CRV (Coordinate Remote Viewing) protocol integration for ruvector.
4+
//!
5+
//! Maps the 6-stage CRV signal line methodology to ruvector's subsystems:
6+
//!
7+
//! | CRV Stage | Data Type | ruvector Component |
8+
//! |-----------|-----------|-------------------|
9+
//! | Stage I (Ideograms) | Gestalt primitives | Poincaré ball hyperbolic embeddings |
10+
//! | Stage II (Sensory) | Textures, colors, temps | Multi-head attention vectors |
11+
//! | Stage III (Dimensional) | Spatial sketches | GNN graph topology |
12+
//! | Stage IV (Emotional) | AOL, intangibles | SNN temporal encoding |
13+
//! | Stage V (Interrogation) | Signal line probing | Differentiable search |
14+
//! | Stage VI (3D Model) | Composite model | MinCut partitioning |
15+
//!
16+
//! ## Quick Start
17+
//!
18+
//! ```rust,no_run
19+
//! use ruvector_crv::{CrvConfig, CrvSessionManager, GestaltType, StageIData};
20+
//!
21+
//! // Create session manager with default config (384 dimensions)
22+
//! let config = CrvConfig::default();
23+
//! let mut manager = CrvSessionManager::new(config);
24+
//!
25+
//! // Create a session for a target coordinate
26+
//! manager.create_session("session-001".to_string(), "1234-5678".to_string()).unwrap();
27+
//!
28+
//! // Add Stage I ideogram data
29+
//! let stage_i = StageIData {
30+
//! stroke: vec![(0.0, 0.0), (1.0, 0.5), (2.0, 1.0), (3.0, 0.5)],
31+
//! spontaneous_descriptor: "angular rising".to_string(),
32+
//! classification: GestaltType::Manmade,
33+
//! confidence: 0.85,
34+
//! };
35+
//!
36+
//! let embedding = manager.add_stage_i("session-001", &stage_i).unwrap();
37+
//! assert_eq!(embedding.len(), 384);
38+
//! ```
39+
//!
40+
//! ## Architecture
41+
//!
42+
//! The Poincaré ball embedding for Stage I gestalts encodes the hierarchical
43+
//! gestalt taxonomy (root → manmade/natural/movement/energy/water/land) with
44+
//! exponentially less distortion than Euclidean space.
45+
//!
46+
//! For AOL (Analytical Overlay) separation, the spiking neural network temporal
47+
//! encoding models signal-vs-noise discrimination: high-frequency spike bursts
48+
//! correlate with AOL contamination, while sustained low-frequency patterns
49+
//! indicate clean signal line data.
50+
//!
51+
//! MinCut partitioning in Stage VI identifies natural cluster boundaries in the
52+
//! accumulated session graph, separating distinct target aspects.
53+
//!
54+
//! ## Cross-Session Convergence
55+
//!
56+
//! Multiple sessions targeting the same coordinate can be analyzed for
57+
//! convergence — agreement between independent viewers strengthens the
58+
//! signal validity:
59+
//!
60+
//! ```rust,no_run
61+
//! # use ruvector_crv::{CrvConfig, CrvSessionManager};
62+
//! # let mut manager = CrvSessionManager::new(CrvConfig::default());
63+
//! // After adding data to multiple sessions for "1234-5678"...
64+
//! let convergence = manager.find_convergence("1234-5678", 0.75).unwrap();
65+
//! // convergence.scores contains similarity values for converging entries
66+
//! ```
67+
68+
pub mod error;
69+
pub mod session;
70+
pub mod stage_i;
71+
pub mod stage_ii;
72+
pub mod stage_iii;
73+
pub mod stage_iv;
74+
pub mod stage_v;
75+
pub mod stage_vi;
76+
pub mod types;
77+
78+
// Re-export main types
79+
pub use error::{CrvError, CrvResult};
80+
pub use session::CrvSessionManager;
81+
pub use stage_i::StageIEncoder;
82+
pub use stage_ii::StageIIEncoder;
83+
pub use stage_iii::StageIIIEncoder;
84+
pub use stage_iv::StageIVEncoder;
85+
pub use stage_v::StageVEngine;
86+
pub use stage_vi::StageVIModeler;
87+
pub use types::{
88+
AOLDetection, ConvergenceResult, CrossReference, CrvConfig, CrvSessionEntry,
89+
GeometricKind, GestaltType, SensoryModality, SignalLineProbe, SketchElement,
90+
SpatialRelationType, SpatialRelationship, StageIData, StageIIData, StageIIIData,
91+
StageIVData, StageVData, StageVIData, TargetPartition,
92+
};
93+
94+
/// Library version.
95+
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
96+
97+
#[cfg(test)]
98+
mod tests {
99+
use super::*;
100+
101+
#[test]
102+
fn test_version() {
103+
assert!(!VERSION.is_empty());
104+
}
105+
106+
#[test]
107+
fn test_end_to_end_session() {
108+
let config = CrvConfig {
109+
dimensions: 32,
110+
..CrvConfig::default()
111+
};
112+
let mut manager = CrvSessionManager::new(config);
113+
114+
// Create two sessions for the same coordinate
115+
manager
116+
.create_session("viewer-a".to_string(), "target-001".to_string())
117+
.unwrap();
118+
manager
119+
.create_session("viewer-b".to_string(), "target-001".to_string())
120+
.unwrap();
121+
122+
// Viewer A: Stage I
123+
let s1_a = StageIData {
124+
stroke: vec![(0.0, 0.0), (1.0, 1.0), (2.0, 0.5), (3.0, 0.0)],
125+
spontaneous_descriptor: "tall angular".to_string(),
126+
classification: GestaltType::Manmade,
127+
confidence: 0.85,
128+
};
129+
manager.add_stage_i("viewer-a", &s1_a).unwrap();
130+
131+
// Viewer B: Stage I (similar gestalt)
132+
let s1_b = StageIData {
133+
stroke: vec![(0.0, 0.0), (0.5, 1.2), (1.5, 0.8), (2.5, 0.0)],
134+
spontaneous_descriptor: "structured upward".to_string(),
135+
classification: GestaltType::Manmade,
136+
confidence: 0.78,
137+
};
138+
manager.add_stage_i("viewer-b", &s1_b).unwrap();
139+
140+
// Viewer A: Stage II
141+
let s2_a = StageIIData {
142+
impressions: vec![
143+
(SensoryModality::Texture, "rough stone".to_string()),
144+
(SensoryModality::Temperature, "cool".to_string()),
145+
(SensoryModality::Color, "gray".to_string()),
146+
],
147+
feature_vector: None,
148+
};
149+
manager.add_stage_ii("viewer-a", &s2_a).unwrap();
150+
151+
// Viewer B: Stage II (overlapping sensory)
152+
let s2_b = StageIIData {
153+
impressions: vec![
154+
(SensoryModality::Texture, "grainy rough".to_string()),
155+
(SensoryModality::Color, "dark gray".to_string()),
156+
(SensoryModality::Luminosity, "dim".to_string()),
157+
],
158+
feature_vector: None,
159+
};
160+
manager.add_stage_ii("viewer-b", &s2_b).unwrap();
161+
162+
// Verify entries
163+
assert_eq!(manager.session_entry_count("viewer-a"), 2);
164+
assert_eq!(manager.session_entry_count("viewer-b"), 2);
165+
166+
// Both sessions should have embeddings
167+
let entries_a = manager.get_session_embeddings("viewer-a").unwrap();
168+
let entries_b = manager.get_session_embeddings("viewer-b").unwrap();
169+
170+
assert_eq!(entries_a.len(), 2);
171+
assert_eq!(entries_b.len(), 2);
172+
173+
// All embeddings should be 32-dimensional
174+
for entry in entries_a.iter().chain(entries_b.iter()) {
175+
assert_eq!(entry.embedding.len(), 32);
176+
}
177+
}
178+
}

0 commit comments

Comments
 (0)