reasoninglayer 1.0.3

Rust client SDK for the Reasoning Layer API
Documentation
//! Term (record) DTOs — the tagged `ValueDto` CRUD representation.

use std::collections::BTreeMap;
use std::collections::HashMap;

use serde::{Deserialize, Serialize};

use super::values::ValueDto;

// ─── Term state / witnesses ───────────────────────────────────────────────────

/// Validation state of a term.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TermState {
    /// All type witnesses are satisfied.
    Complete,
    /// Some witnesses are suspended (missing information).
    Residuated,
    /// The sort has no witness requirements.
    NoWitnesses,
}

/// Proof that a term satisfies a type witness.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WitnessProofDto {
    /// Witness UUID.
    pub witness_id: String,
    /// Variable bindings that satisfy the witness.
    #[serde(default)]
    pub bindings: BTreeMap<String, String>,
    /// Certainty of the proof.
    pub certainty: f64,
}

/// A residuated (suspended) type witness.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResidualWitnessDto {
    /// Witness UUID.
    pub witness_id: String,
    /// Partial bindings found so far.
    #[serde(default)]
    pub partial_bindings: BTreeMap<String, String>,
    /// What would trigger re-evaluation.
    pub trigger: String,
}

/// A witness instantiation showing how a witness was satisfied.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WitnessInstantiationDto {
    pub witness_id: String,
    #[serde(default)]
    pub bindings: BTreeMap<String, String>,
    pub confidence: f64,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub explanation: Option<String>,
}

/// A residuation record for a witness that could not be satisfied yet.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResiduationDto {
    pub witness_id: String,
    #[serde(default)]
    pub partial_bindings: BTreeMap<String, String>,
    pub trigger: String,
}

// ─── TermDto ──────────────────────────────────────────────────────────────────

/// Summary information for a referenced term.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ReferencedTermSummary {
    /// Human-readable display name.
    pub display_name: String,
    /// Sort name of the referenced term.
    pub sort_name: String,
}

/// A Psi-term (feature structure) in the tagged value format.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct TermDto {
    /// Term UUID.
    pub id: String,
    /// Sort UUID.
    pub sort_id: String,
    /// Tenant UUID.
    pub tenant_id: String,
    /// Owner user UUID.
    pub owner_id: String,
    /// Named features with tagged values.
    pub features: BTreeMap<String, ValueDto>,
    /// Resolved sort name (server-provided on GET).
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sort_name: Option<String>,
    /// Computed display name (server-provided on GET).
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub display_name: Option<String>,
    /// Summaries of referenced terms.
    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
    pub referenced_terms: HashMap<String, ReferencedTermSummary>,
}

/// Response wrapper for term CRUD operations — wraps [`TermDto`] with witness validation state.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TermResponse {
    /// The underlying term.
    pub term: TermDto,
    /// Validation state.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub state: Option<TermState>,
    /// Proofs of satisfied witnesses.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub witness_proofs: Vec<WitnessProofDto>,
    /// Residuated witnesses awaiting more information.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub residual_witnesses: Vec<ResidualWitnessDto>,
}

// ─── Requests ─────────────────────────────────────────────────────────────────

/// Request to create a new term.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateTermRequest {
    /// Sort UUID.
    pub sort_id: String,
    /// Owner user UUID.
    pub owner_id: String,
    /// Named features with tagged values.
    pub features: BTreeMap<String, ValueDto>,
}

/// Request to update an existing term.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateTermRequest {
    /// Updated features.
    pub features: BTreeMap<String, ValueDto>,
}

/// Request to bulk-create terms.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BulkAddTermsRequest {
    /// Terms to create.
    pub terms: Vec<CreateTermRequest>,
}

/// Response from clearing all terms for a tenant.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClearTermsResponse {
    pub message: String,
    pub terms_cleared: u64,
}

/// Response from bulk term creation.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BulkAddTermsResponse {
    /// UUIDs of the created terms, in the same order as the request.
    pub term_ids: Vec<String>,
    /// Total processing time in ms.
    pub processing_time_ms: u128,
}

/// Response from witness-validated term operations.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidatedTermResponse {
    pub valid: bool,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub term: Option<TermDto>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub failure_reason: Option<String>,
    #[serde(default)]
    pub witnesses_satisfied: Vec<WitnessInstantiationDto>,
    #[serde(default)]
    pub witnesses_residuated: Vec<ResiduationDto>,
}

/// Response from witness-validated unification.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidatedUnifyResponse {
    pub success: bool,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub unified_term: Option<TermDto>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub glb_sort_id: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub failure_reason: Option<String>,
    pub duration_us: u64,
    #[serde(default)]
    pub witnesses_satisfied: Vec<WitnessInstantiationDto>,
    #[serde(default)]
    pub witnesses_residuated: Vec<ResiduationDto>,
}