traverse-runtime 0.9.0

Core execution engine for the Traverse capability runtime.
Documentation
use traverse_contracts::ExecutionTarget;
use traverse_registry::{
    ModelCandidateEvaluation, ModelCandidateReadiness, ModelCandidateRejectionCode,
    ModelResolutionEvidence, ModelResolutionPhase, SelectedModelCandidate,
};
use traverse_runtime::trace::{
    PrivateTraceEntry, PublicTraceEntry, TraceOutcome, TraceStore, new_trace_id_and_time,
};

fn make_public(capability_id: &str) -> PublicTraceEntry {
    let (id, time) = new_trace_id_and_time();
    PublicTraceEntry::new(
        id,
        capability_id.to_string(),
        "cloud".to_string(),
        TraceOutcome::Success,
        42,
        time,
    )
}

fn make_private(trace_id: &str) -> PrivateTraceEntry {
    PrivateTraceEntry::new(
        trace_id.to_string(),
        "raw input bytes",
        "raw output bytes",
        42,
    )
}

#[test]
fn public_trace_entry_has_all_cloudevents_fields() {
    let entry = make_public("content.comments.create-comment-draft");
    assert!(!entry.id.is_empty(), "id must be non-empty");
    assert!(!entry.source.is_empty(), "source must be non-empty");
    assert!(!entry.event_type.is_empty(), "event_type must be non-empty");
    assert!(
        !entry.datacontenttype.is_empty(),
        "datacontenttype must be non-empty"
    );
    assert!(!entry.time.is_empty(), "time must be non-empty");
}

#[test]
fn public_trace_entry_source_contains_capability_id() {
    let entry = make_public("my.cap.id");
    assert!(
        entry.source.contains("my.cap.id"),
        "source '{}' should contain capability id",
        entry.source
    );
    assert_eq!(entry.event_type, "dev.traverse.execution.completed");
    assert_eq!(entry.datacontenttype, "application/json");
}

#[test]
fn private_entry_hashes_are_sha256_hex() {
    let (id, _) = new_trace_id_and_time();
    let priv_entry = make_private(&id);
    // SHA-256 produces a 64-character hex string
    assert_eq!(
        priv_entry.inputs_hash.len(),
        64,
        "inputs_hash must be 64 hex chars"
    );
    assert_eq!(
        priv_entry.outputs_hash.len(),
        64,
        "outputs_hash must be 64 hex chars"
    );
    assert!(
        priv_entry
            .inputs_hash
            .chars()
            .all(|c| c.is_ascii_hexdigit()),
        "inputs_hash must be hex"
    );
    assert!(
        priv_entry
            .outputs_hash
            .chars()
            .all(|c| c.is_ascii_hexdigit()),
        "outputs_hash must be hex"
    );
}

#[test]
fn no_raw_input_in_any_trace_field() {
    let raw = "super-secret-input-data";
    let (id, time) = new_trace_id_and_time();
    let public = PublicTraceEntry::new(
        id.clone(),
        "cap.id".to_string(),
        "cloud".to_string(),
        TraceOutcome::Success,
        1,
        time,
    );
    let private = PrivateTraceEntry::new(id.clone(), raw, "output", 1);

    // Raw value must not appear in any field
    let serialized = serde_json::to_string(&public).unwrap_or_default();
    assert!(
        !serialized.contains(raw),
        "raw input must not appear in public trace"
    );
    assert!(
        !private.inputs_hash.contains(raw),
        "raw input must not appear in private hash field"
    );
}

#[test]
fn public_trace_entry_exposes_redacted_model_resolution_evidence() {
    let mut public = make_public("traverse.inference.generate");
    public.model_resolution.push(model_resolution_evidence());

    let serialized = serde_json::to_string(&public).unwrap_or_default();

    assert!(serialized.contains("model_resolution"));
    assert!(serialized.contains("ollama.local.generate"));
    assert!(serialized.contains("llama3.2:3b"));
    assert!(!serialized.contains("private prompt"));
    assert!(!serialized.contains("raw source text"));
    assert!(!serialized.contains("sk-local-secret"));
}

#[test]
fn get_trace_without_private_flag_returns_public_only() -> Result<(), String> {
    let mut store = TraceStore::new();
    let pub_entry = make_public("cap.a");
    let trace_id = pub_entry.id.clone();
    let priv_entry = make_private(&trace_id);
    store.insert(pub_entry, Some(priv_entry));

    let (public, private) = store
        .get(&trace_id)
        .ok_or_else(|| "trace must exist".to_string())?;
    assert_eq!(public.capability_id, "cap.a");
    // Caller decides whether to expose private; store returns it — caller opts in
    // Here we verify the store returns the private entry and the test caller chooses not to expose it
    let _ = private; // available but not exposed to caller without opt-in flag
    Ok(())
}

#[test]
fn get_trace_with_private_flag_returns_both_tiers() -> Result<(), String> {
    let mut store = TraceStore::new();
    let pub_entry = make_public("cap.b");
    let trace_id = pub_entry.id.clone();
    let priv_entry = make_private(&trace_id);
    store.insert(pub_entry, Some(priv_entry));

    let (public, private) = store
        .get(&trace_id)
        .ok_or_else(|| "trace must exist".to_string())?;
    assert_eq!(public.capability_id, "cap.b");
    assert!(private.is_some(), "private tier must be present");
    let priv_ref = private.ok_or_else(|| "private tier must be present".to_string())?;
    assert_eq!(priv_ref.trace_id, trace_id);
    Ok(())
}

#[test]
fn get_trace_with_no_private_tier_returns_none() -> Result<(), String> {
    let mut store = TraceStore::new();
    let pub_entry = make_public("cap.c");
    let trace_id = pub_entry.id.clone();
    store.insert(pub_entry, None);

    let (_, private) = store
        .get(&trace_id)
        .ok_or_else(|| "trace must exist".to_string())?;
    assert!(private.is_none());
    Ok(())
}

#[test]
fn list_traces_filtered_by_capability_id() {
    let mut store = TraceStore::new();
    store.insert(make_public("cap.x"), None);
    store.insert(make_public("cap.x"), None);
    store.insert(make_public("cap.y"), None);

    let x_results = store.list_public(Some("cap.x"));
    assert_eq!(x_results.len(), 2);
    let y_results = store.list_public(Some("cap.y"));
    assert_eq!(y_results.len(), 1);
    let all_results = store.list_public(None);
    assert_eq!(all_results.len(), 3);
}

#[test]
fn unknown_trace_id_returns_none() {
    let store = TraceStore::new();
    assert!(store.get("nonexistent-id").is_none());
}

fn model_resolution_evidence() -> ModelResolutionEvidence {
    ModelResolutionEvidence {
        phase: ModelResolutionPhase::Execution,
        interface_id: "traverse.inference.generate".to_string(),
        requested_interface_id: "traverse.inference.generate".to_string(),
        requested_placement: ExecutionTarget::Local,
        selected: Some(SelectedModelCandidate {
            candidate_id: "ollama-llama-3-2".to_string(),
            provider_capability_id: "traverse.inference.generate".to_string(),
            provider_implementation_id: "ollama.local.generate".to_string(),
            model_identifier: "llama3.2:3b".to_string(),
            placement_target: ExecutionTarget::Local,
            priority: 10,
            selection_reason: "selected highest-priority passing candidate".to_string(),
        }),
        candidates: vec![ModelCandidateEvaluation {
            candidate_id: "ollama-llama-3-2".to_string(),
            provider_capability_id: "traverse.inference.generate".to_string(),
            provider_implementation_id: "ollama.local.generate".to_string(),
            model_identifier: "llama3.2:3b".to_string(),
            placement_target: ExecutionTarget::Local,
            priority: 10,
            readiness: ModelCandidateReadiness::Ready,
            rejection_code: Option::<ModelCandidateRejectionCode>::None,
            reason: "candidate passed availability, interface, placement, and context checks"
                .to_string(),
            manifest_order: 0,
        }],
        failure_code: Option::<ModelCandidateRejectionCode>::None,
    }
}