use std::sync::Arc;
use mempill_core::ports::OraclePort;
use mempill_core::application::{IngestClaimRequest, QueryMemoryRequest};
use mempill_sqlite::{open_with_oracle, open_with_oracle_in_memory};
use mempill_types::{
AgentId, AdjudicationResponse, AdjudicationVerdict, BeliefStatus, Cardinality,
Confidence, Criticality, Disposition, ExternalKind, ProvenanceLabel,
};
struct TestOracle {
fixed_uuid: uuid::Uuid,
}
impl OraclePort for TestOracle {
type Error = mempill_core::noop::NoOpError;
type Handle = uuid::Uuid;
fn request_adjudication(
&self,
_agent_id: &AgentId,
_request: mempill_types::AdjudicationRequest,
) -> Result<Self::Handle, Self::Error> {
Ok(self.fixed_uuid)
}
fn handle_to_uuid(handle: &Self::Handle) -> uuid::Uuid {
*handle
}
}
fn ingest_req(agent: &AgentId, value: &str) -> IngestClaimRequest {
IngestClaimRequest {
agent_id: agent.clone(),
subject: "company".into(),
predicate: "hq".into(),
value: serde_json::json!(value),
provenance: ProvenanceLabel::External(ExternalKind::UserAsserted),
cardinality: Cardinality::Functional,
valid_time: None,
confidence: Confidence { value_confidence: 0.95, valid_time_confidence: 0.0 },
criticality: Criticality::High,
derived_from: vec![],
}
}
fn query_req(agent: &AgentId) -> QueryMemoryRequest {
QueryMemoryRequest {
agent_id: agent.clone(),
subject: "company".into(),
predicate: "hq".into(),
as_of_tx_time: None,
}
}
#[tokio::test]
async fn e2e_open_with_oracle_in_memory_affirm_resolution() {
let handle_id = uuid::Uuid::new_v4();
let oracle = Arc::new(TestOracle { fixed_uuid: handle_id });
let engine = open_with_oracle_in_memory(oracle)
.expect("open_with_oracle_in_memory must succeed");
let agent = AgentId("w7a-inmem-affirm-agent".into());
let resp_berlin = engine.ingest_claim(ingest_req(&agent, "Berlin")).await
.expect("ingest Berlin must succeed");
assert_eq!(resp_berlin.disposition, Disposition::CommittedCheap,
"first ingest must be CommittedCheap");
let resp_paris = engine.ingest_claim(ingest_req(&agent, "Paris")).await
.expect("ingest Paris must succeed");
assert_eq!(resp_paris.disposition, Disposition::QueuedForAdjudication,
"conflicting claim with oracle present must be QueuedForAdjudication");
let challenger_ref = resp_paris.claim_ref.clone();
let qr_before = engine.query_memory(query_req(&agent)).await
.expect("query before submit must succeed");
assert_eq!(qr_before.belief.status, BeliefStatus::Contested,
"BEFORE submit: belief must be Contested; got {:?}", qr_before.belief.status);
let outcome = engine.submit_adjudication(
handle_id,
AdjudicationResponse {
handle_id,
verdict: AdjudicationVerdict::Affirm,
evidence_provenance: ProvenanceLabel::External(ExternalKind::ExternalFirstHand),
},
).await.expect("Affirm submit must succeed");
assert_eq!(outcome.claim_ref, challenger_ref);
assert_eq!(outcome.disposition, Disposition::CommittedCheap,
"challenger must be CommittedCheap after Affirm");
let qr_after = engine.query_memory(query_req(&agent)).await
.expect("query after Affirm must succeed");
assert_ne!(qr_after.belief.status, BeliefStatus::Contested,
"AFTER Affirm: must NOT be Contested; got {:?}", qr_after.belief.status);
assert_ne!(qr_after.belief.status, BeliefStatus::NoBelief,
"AFTER Affirm: must NOT be NoBelief; got {:?}", qr_after.belief.status);
let primary_val = qr_after.belief.primary.as_ref()
.map(|b| b.fact.value.clone())
.unwrap_or(serde_json::Value::Null);
assert_eq!(primary_val, serde_json::json!("Paris"),
"AFTER Affirm: challenger 'Paris' must be the surfaced belief; got {primary_val:?}");
}
#[tokio::test]
async fn e2e_open_with_oracle_file_backed_smoke() {
let dir = tempfile::tempdir().expect("tempdir must succeed");
let path = dir.path().join("smoke.db");
let path_str = path.to_str().unwrap();
let handle_id = uuid::Uuid::new_v4();
let oracle = Arc::new(TestOracle { fixed_uuid: handle_id });
let engine = open_with_oracle(path_str, oracle)
.expect("open_with_oracle (file-backed) must succeed");
let agent = AgentId("w7a-file-smoke-agent".into());
let resp = engine.ingest_claim(ingest_req(&agent, "Munich")).await
.expect("ingest must succeed");
assert_eq!(resp.disposition, Disposition::CommittedCheap);
assert!(!resp.claim_ref.0.is_nil(), "claim_ref must be non-nil");
let qr = engine.query_memory(query_req(&agent)).await
.expect("query must succeed");
assert!(
matches!(qr.belief.status, BeliefStatus::Resolved | BeliefStatus::TimingUncertain),
"single claim must surface as Resolved or TimingUncertain; got {:?}", qr.belief.status
);
let val = qr.belief.primary.as_ref().map(|b| b.fact.value.clone());
assert_eq!(val, Some(serde_json::json!("Munich")));
}
#[tokio::test]
async fn e2e_open_default_in_memory_unchanged() {
let engine = mempill_sqlite::open_default_in_memory()
.expect("open_default_in_memory must succeed");
let agent = AgentId("w7a-regression-agent".into());
let resp = engine.ingest_claim(IngestClaimRequest {
agent_id: agent.clone(),
subject: "user".into(),
predicate: "lang".into(),
value: serde_json::json!("Rust"),
provenance: ProvenanceLabel::External(ExternalKind::UserAsserted),
cardinality: Cardinality::Functional,
valid_time: None,
confidence: Confidence { value_confidence: 0.99, valid_time_confidence: 0.0 },
criticality: Criticality::Low,
derived_from: vec![],
}).await.expect("ingest must succeed");
assert_eq!(resp.disposition, Disposition::CommittedCheap);
}