//! types.rs — shared types for the inference daemon use serde::{Deserialize, Serialize}; use tokio::sync::oneshot; /// A single (claim, chunk) verification request. /// `responder` routes the result back to the caller without polling. pub struct VerifyRequest { pub input_ids: Vec, pub attention_mask: Vec, pub token_type_ids: Vec, pub chunk_id: String, // canonical ID of the retrieved source chunk pub claim_text: String, // exact LLM-generated claim string pub responder: oneshot::Sender, } /// Response returned through the oneshot channel. #[derive(Debug, Clone)] pub struct VerifyResponse { pub entailment_score: f32, // softmax P(Entailment) pub label: Verdict, pub attestation_hash: [u8; 32], // BLAKE3 hash of the serialised attestation } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum Verdict { Entailment, Neutral, Contradiction, } impl Verdict { pub fn from_score(score: f32, threshold: f32) -> Self { if score >= threshold { Verdict::Entailment } else { Verdict::Contradiction // scores below threshold are rejected } } } /// Deterministically serialisable attestation record. /// bincode serialises this to a canonical byte string before BLAKE3 hashing. #[derive(Debug, Serialize, Deserialize)] pub struct EntailmentAttestation { pub timestamp_ns: u64, pub chunk_id: String, pub claim_text: String, pub entailment_score: f32, pub verdict: String, pub model_signature: String, // e.g. "deberta-v3-fp16-v1.2" pub threshold: f32, } impl EntailmentAttestation { /// Serialise deterministically with bincode and compute BLAKE3 hash. pub fn seal(&self) -> ([u8; 32], Vec) { let payload = bincode::serialize(self) .expect("bincode serialisation is infallible for flat structs"); let hash: [u8; 32] = *blake3::hash(&payload).as_bytes(); (hash, payload) } } /// Daemon configuration loaded from config/daemon.json. #[derive(Debug, Clone, Deserialize)] pub struct DaemonConfig { pub model_path: String, pub trt_cache_dir: String, pub threshold: f32, // entailment rejection threshold from calibrate.py pub max_batch_size: usize, pub flush_interval_ms: u64, pub model_signature: String, pub http_port: u16, pub ledger_path: String, // WORM ledger file path } impl Default for DaemonConfig { fn default() -> Self { Self { model_path: "./onnx/cross_encoder_opt_fp16.onnx".into(), trt_cache_dir: "./trt_cache".into(), threshold: 0.85, max_batch_size: 32, flush_interval_ms: 5, model_signature: "deberta-v3-fp16-v1.2".into(), http_port: 8080, ledger_path: "./ledger/audit_chain.db".into(), } } }