use super::*;
use crate::config::{NamespaceToken as TokenCtor, RuntimeConfig};
use crate::embedder_registry::EmbedderProvider;
use crate::retrieval::SearchSource;
use khive_gate::ActorRef;
use khive_types::{namespace::Namespace, SubstrateKind};
use lattice_embed::{EmbeddingModel, EmbeddingService};
use std::sync::Arc;
struct ConstantEmbeddingService {
dimensions: usize,
}
#[async_trait::async_trait]
impl EmbeddingService for ConstantEmbeddingService {
async fn embed(
&self,
texts: &[String],
_model: EmbeddingModel,
) -> Result<Vec<Vec<f32>>, lattice_embed::EmbedError> {
Ok(texts.iter().map(|_| vec![1.0; self.dimensions]).collect())
}
fn supports_model(&self, _model: EmbeddingModel) -> bool {
true
}
fn name(&self) -> &'static str {
"resolve-test-constant-embedding"
}
}
struct ConstantEmbedderProvider {
name: String,
dimensions: usize,
}
#[async_trait::async_trait]
impl EmbedderProvider for ConstantEmbedderProvider {
fn name(&self) -> &str {
&self.name
}
fn dimensions(&self) -> usize {
self.dimensions
}
async fn build(&self) -> RuntimeResult<Arc<dyn EmbeddingService>> {
Ok(Arc::new(ConstantEmbeddingService {
dimensions: self.dimensions,
}))
}
}
fn runtime_with_constant_embeddings() -> KhiveRuntime {
let model = EmbeddingModel::AllMiniLmL6V2;
let runtime = KhiveRuntime::new(RuntimeConfig {
db_path: None,
embedding_model: Some(model),
packs: vec!["kg".to_string()],
..RuntimeConfig::no_embeddings()
})
.expect("in-memory runtime");
runtime.register_embedder(ConstantEmbedderProvider {
name: model.to_string(),
dimensions: model.dimensions(),
});
runtime
}
fn actor_token(actor_id: &str) -> NamespaceToken {
TokenCtor::mint_authorized(Namespace::local(), ActorRef::new("agent", actor_id))
}
#[tokio::test]
async fn id_string_passthrough_resolves_full_uuid() {
let rt = KhiveRuntime::memory().expect("in-memory runtime");
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
let entity = rt
.create_entity(
&token,
"concept",
None,
"PassthroughTarget",
None,
None,
vec![],
)
.await
.expect("create entity");
let resolution = resolve_reference(&rt, &ring, &token, &entity.id.to_string(), 5, None)
.await
.expect("resolve_reference");
assert_eq!(
resolution,
ReferenceResolution::Resolved {
id: entity.id,
confidence: 1.0
}
);
}
#[tokio::test]
async fn id_string_passthrough_never_errors_on_a_miss() {
let rt = KhiveRuntime::memory().expect("in-memory runtime");
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
let missing = Uuid::new_v4();
let resolution = resolve_reference(&rt, &ring, &token, &missing.to_string(), 5, None)
.await
.expect("must not error, only report NotFound");
assert_eq!(resolution, ReferenceResolution::NotFound);
}
#[tokio::test]
async fn ring_exact_match_resolves_without_search() {
let rt = KhiveRuntime::memory().expect("in-memory runtime");
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
let actor = token.actor();
let actor_key = format!("{}:{}", actor.kind, actor.id);
let id = Uuid::new_v4();
ring.admit(
token.namespace().as_str(),
&actor_key,
id,
Some("the old record".to_string()),
);
let resolution = resolve_reference(&rt, &ring, &token, "the old record", 5, None)
.await
.expect("resolve_reference");
assert_eq!(
resolution,
ReferenceResolution::Resolved {
id,
confidence: RING_EXACT_CONFIDENCE
}
);
}
#[tokio::test]
async fn ring_ambiguous_on_multiple_exact_matches() {
let rt = KhiveRuntime::memory().expect("in-memory runtime");
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
let actor = token.actor();
let actor_key = format!("{}:{}", actor.kind, actor.id);
let id_a = Uuid::new_v4();
let id_b = Uuid::new_v4();
ring.admit(
token.namespace().as_str(),
&actor_key,
id_a,
Some("duplicate name".to_string()),
);
ring.admit(
token.namespace().as_str(),
&actor_key,
id_b,
Some("duplicate name".to_string()),
);
let resolution = resolve_reference(&rt, &ring, &token, "duplicate name", 5, None)
.await
.expect("resolve_reference");
match resolution {
ReferenceResolution::Ambiguous { candidates } => {
assert_eq!(candidates.len(), 2);
}
other => panic!("expected Ambiguous, got {other:?}"),
}
}
#[tokio::test]
async fn no_ring_entry_and_no_search_hit_is_not_found() {
let rt = KhiveRuntime::memory().expect("in-memory runtime");
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
let resolution = resolve_reference(&rt, &ring, &token, "nothing matches this at all", 5, None)
.await
.expect("resolve_reference");
assert_eq!(resolution, ReferenceResolution::NotFound);
}
#[tokio::test]
async fn actor_isolation_blocks_cross_actor_ring_reads() {
let rt = KhiveRuntime::memory().expect("in-memory runtime");
let token_a = actor_token("actor-a");
let token_b = actor_token("actor-b");
let ring = ReferenceRing::new();
let actor_a = token_a.actor();
let actor_key_a = format!("{}:{}", actor_a.kind, actor_a.id);
let id = Uuid::new_v4();
ring.admit(
token_a.namespace().as_str(),
&actor_key_a,
id,
Some("shared-namespace-name".to_string()),
);
let resolution = resolve_reference(&rt, &ring, &token_b, "shared-namespace-name", 5, None)
.await
.expect("resolve_reference");
assert_eq!(resolution, ReferenceResolution::NotFound);
}
#[tokio::test]
async fn exact_name_stage_survives_many_newer_case_variant_decoys() {
let rt = KhiveRuntime::memory().expect("in-memory runtime");
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
let target = rt
.create_entity(&token, "concept", None, "RoLoRA", None, None, vec![])
.await
.expect("create target entity");
let decoy_cases = ["rolora", "ROLORA", "RoLoRa", "roLORA"];
for i in 0..120 {
rt.create_entity(
&token,
"concept",
None,
decoy_cases[i % decoy_cases.len()],
None,
None,
vec![],
)
.await
.expect("create decoy entity");
}
let resolution = resolve_reference(&rt, &ring, &token, "RoLoRA", 5, None)
.await
.expect("resolve_reference");
assert_eq!(
resolution,
ReferenceResolution::Resolved {
id: target.id,
confidence: EXACT_NAME_CONFIDENCE,
}
);
}
#[tokio::test]
async fn exact_name_ambiguous_decision_uses_storage_total_not_page_len() {
let rt = KhiveRuntime::memory().expect("in-memory runtime");
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
for _ in 0..11 {
rt.create_entity(&token, "concept", None, "DupeExactName", None, None, vec![])
.await
.expect("create duplicate-named entity");
}
let resolution = resolve_reference(&rt, &ring, &token, "DupeExactName", 5, None)
.await
.expect("resolve_reference");
match resolution {
ReferenceResolution::Ambiguous { candidates } => {
assert_eq!(
candidates.len(),
10,
"candidate set is a bounded 10-row sample of the 11 storage matches, \
not the complete set"
);
}
other => panic!("expected Ambiguous driven by storage total (11), got {other:?}"),
}
}
#[tokio::test]
async fn exact_name_resolves_ahead_of_competing_hybrid_matches() {
let rt = KhiveRuntime::memory().expect("in-memory runtime");
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
let target = rt
.create_entity(
&token,
"concept",
None,
"ADR-040",
Some("khive ADR-040"),
None,
vec![],
)
.await
.expect("create target entity");
for i in 0..12 {
rt.create_entity(
&token,
"concept",
None,
&format!("ADR-040 companion {i}"),
Some("ADR-040 ADR-040 ADR-040 ADR-040 ADR-040"),
None,
vec![],
)
.await
.expect("create competing entity");
}
let resolution = resolve_reference(&rt, &ring, &token, "ADR-040", 1, None)
.await
.expect("resolve_reference");
assert_eq!(
resolution,
ReferenceResolution::Resolved {
id: target.id,
confidence: EXACT_NAME_CONFIDENCE,
}
);
}
#[tokio::test]
async fn fallback_stage_bounds_non_exact_payload_to_limit() {
let rt = KhiveRuntime::memory().expect("in-memory runtime");
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
for i in 0..12 {
rt.create_entity(
&token,
"concept",
None,
&format!("Retrieval Fusion Note {i}"),
Some("khive retrieval fusion ranking note"),
None,
vec![],
)
.await
.expect("create entity");
}
let resolution = resolve_reference(
&rt,
&ring,
&token,
"khive retrieval fusion ranking",
5,
None,
)
.await
.expect("resolve_reference");
match resolution {
ReferenceResolution::Ambiguous { candidates } => {
assert_eq!(
candidates.len(),
5,
"a non-exact ref's ambiguity payload is bounded to the caller's limit"
);
}
other => panic!("expected a bounded Ambiguous sample, got {other:?}"),
}
}
#[tokio::test]
async fn fallback_stage_still_reports_ambiguous_on_genuine_tie() {
let rt = KhiveRuntime::memory().expect("in-memory runtime");
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
let a = rt
.create_entity(
&token,
"concept",
None,
"Twin Record",
Some("khive Twin Record document"),
None,
vec![],
)
.await
.expect("create entity a");
let b = rt
.create_entity(
&token,
"concept",
None,
"Twin Record",
Some("khive Twin Record document"),
None,
vec![],
)
.await
.expect("create entity b");
let resolution = resolve_reference(&rt, &ring, &token, "Twin Record", 5, None)
.await
.expect("resolve_reference");
match resolution {
ReferenceResolution::Ambiguous { candidates } => {
let ids: std::collections::HashSet<Uuid> = candidates.iter().map(|c| c.id).collect();
assert!(ids.contains(&a.id) && ids.contains(&b.id));
}
other => panic!("expected Ambiguous on a genuine name tie, got {other:?}"),
}
}
#[tokio::test]
async fn fallback_stage_resolves_high_similarity_semantic_only_candidate() {
let rt = runtime_with_constant_embeddings();
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
let entity = rt
.create_entity(&token, "concept", None, "Canine", None, None, vec![])
.await
.expect("create semantic match");
let raw_hits = rt
.vector_search(
&token,
None,
Some("domestic dog"),
5,
Some(SubstrateKind::Entity),
)
.await
.expect("vector search");
assert_eq!(raw_hits.len(), 1);
assert_eq!(raw_hits[0].subject_id, entity.id);
assert!((raw_hits[0].score.to_f64() - 1.0).abs() < 1e-6);
let hits = rt
.hybrid_search(&token, "domestic dog", None, 5, None, None, &[], None)
.await
.expect("hybrid search");
assert_eq!(hits.len(), 1);
assert_eq!(hits[0].source, SearchSource::Vector);
let resolution = resolve_reference(&rt, &ring, &token, "domestic dog", 5, None)
.await
.expect("resolve_reference");
assert_eq!(
resolution,
ReferenceResolution::Resolved {
id: entity.id,
confidence: SEARCH_RESOLVED_CONFIDENCE,
}
);
}
#[tokio::test]
async fn fallback_stage_resolves_moderate_similarity_semantic_only_candidate() {
let rt = runtime_with_constant_embeddings();
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
let dimensions = EmbeddingModel::AllMiniLmL6V2.dimensions();
let entity = rt
.create_entity(
&token,
"concept",
None,
"Moderately Similar Candidate",
None,
None,
vec![],
)
.await
.expect("create moderate-similarity entity");
let vectors = rt.vectors(&token).expect("vector store");
vectors
.delete(entity.id)
.await
.expect("delete generated vector");
let aligned = dimensions * 3 / 4;
let mut moderate_vector = vec![1.0f32; aligned];
moderate_vector.extend(vec![-1.0f32; dimensions - aligned]);
vectors
.insert(
entity.id,
SubstrateKind::Entity,
token.namespace().as_str(),
"entity.body",
vec![moderate_vector],
)
.await
.expect("insert moderate-similarity vector");
let query = "totally-nonexistent-moderate-zzz";
let raw_hits = rt
.vector_search(&token, None, Some(query), 5, Some(SubstrateKind::Entity))
.await
.expect("vector search");
assert_eq!(raw_hits.len(), 1);
assert_eq!(raw_hits[0].subject_id, entity.id);
assert!((raw_hits[0].score.to_f64() - 0.5).abs() < 1e-6);
let resolution = resolve_reference(&rt, &ring, &token, query, 5, None)
.await
.expect("resolve_reference");
assert_eq!(
resolution,
ReferenceResolution::Resolved {
id: entity.id,
confidence: SEARCH_RESOLVED_CONFIDENCE,
}
);
}
#[tokio::test]
async fn fallback_stage_drops_orthogonal_semantic_only_candidate() {
let rt = runtime_with_constant_embeddings();
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
let dimensions = EmbeddingModel::AllMiniLmL6V2.dimensions();
let entity = rt
.create_entity(
&token,
"concept",
None,
"Unrelated Orthogonal",
None,
None,
vec![],
)
.await
.expect("create unrelated entity");
let vectors = rt.vectors(&token).expect("vector store");
vectors
.delete(entity.id)
.await
.expect("delete generated vector");
let mut orthogonal_vector = vec![1.0f32; dimensions / 2];
orthogonal_vector.extend(vec![-1.0f32; dimensions - dimensions / 2]);
vectors
.insert(
entity.id,
SubstrateKind::Entity,
token.namespace().as_str(),
"entity.body",
vec![orthogonal_vector],
)
.await
.expect("insert orthogonal vector");
let raw_hits = rt
.vector_search(
&token,
None,
Some("totally-nonexistent-orthogonal-zzz"),
5,
Some(SubstrateKind::Entity),
)
.await
.expect("vector search");
assert_eq!(raw_hits.len(), 1);
assert!((raw_hits[0].score.to_f64() - 0.0).abs() < 1e-6);
let resolution = resolve_reference(
&rt,
&ring,
&token,
"totally-nonexistent-orthogonal-zzz",
5,
None,
)
.await
.expect("resolve_reference");
assert_eq!(resolution, ReferenceResolution::NotFound);
}
#[tokio::test]
async fn fallback_stage_drops_low_similarity_semantic_only_candidates() {
let rt = runtime_with_constant_embeddings();
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
let dimensions = EmbeddingModel::AllMiniLmL6V2.dimensions();
let entity = rt
.create_entity(
&token,
"concept",
None,
"Unrelated Alpha",
None,
None,
vec![],
)
.await
.expect("create unrelated entity");
let vectors = rt.vectors(&token).expect("vector store");
vectors
.delete(entity.id)
.await
.expect("delete generated vector");
let quarter = dimensions / 4;
let mut mismatched_vector = vec![1.0f32; quarter];
mismatched_vector.extend(vec![-1.0f32; dimensions - quarter]);
vectors
.insert(
entity.id,
SubstrateKind::Entity,
token.namespace().as_str(),
"entity.body",
vec![mismatched_vector],
)
.await
.expect("insert mismatched vector");
let raw_hits = rt
.vector_search(
&token,
None,
Some("totally-nonexistent-zzz"),
5,
Some(SubstrateKind::Entity),
)
.await
.expect("vector search");
assert_eq!(raw_hits.len(), 1);
assert!((raw_hits[0].score.to_f64() + 0.5).abs() < 1e-6);
let resolution = resolve_reference(&rt, &ring, &token, "totally-nonexistent-zzz", 5, None)
.await
.expect("resolve_reference");
assert_eq!(resolution, ReferenceResolution::NotFound);
}
#[tokio::test]
async fn fallback_stage_still_not_found_on_garbage() {
let rt = KhiveRuntime::memory().expect("in-memory runtime");
let token = actor_token("resolver-test");
let ring = ReferenceRing::new();
rt.create_entity(
&token,
"concept",
None,
"ADR-040",
Some("khive ADR-040"),
None,
vec![],
)
.await
.expect("create unrelated entity");
let resolution = resolve_reference(
&rt,
&ring,
&token,
"zzqxw completely unrelated garbage nonsense",
5,
None,
)
.await
.expect("resolve_reference");
assert_eq!(resolution, ReferenceResolution::NotFound);
}