ant-types 0.1.1

Record types of the open Antares format (.ant): ids, graph, observation, evidence, belief, schema
Documentation
//! Antares-native first-class evidence.
//!
//! Evidence is a kernel concept, not a user-defined entity. Every fact
//! (Edge) may reference one or more Evidence records via `evidenced_by`,
//! and derived records may accumulate evidence from their causes.

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

use crate::author::AuthorStamp;
use crate::ids::{ProjectId, TenantId};

/// Evidence identifier (newtype over String). Distinct from VertexId
/// because evidence lives in its own storage plane.
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(transparent)]
pub struct EvidenceId(pub String);

/// A source-bound piece of supporting material: where it came from,
/// the literal content, and optional span offsets into the source.
/// The payload of an `evidence` record.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Evidence {
    /// Evidence id, unique within the scope.
    pub id: EvidenceId,
    /// Owning tenant.
    pub tenant_id: TenantId,
    /// Owning project.
    pub project_id: ProjectId,
    /// URI/path of the source artifact (e.g. "s3://antares/calls/2026-04-29.vtt"
    /// or "antares://transcripts/meeting_001"). Required.
    pub source_uri: String,
    /// What kind of source: "transcript" | "email_event" | "crm_field" | ...
    pub source_type: String,
    /// Identifier of the source event/artifact (e.g. "meeting_001",
    /// "email_001"). Required.
    pub source_id: String,
    /// The literal text/data the evidence points at. Required.
    pub content: String,
    /// Character offset of the span start in the source, inclusive.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub char_start: Option<u32>,
    /// Character offset of the span end in the source, exclusive.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub char_end: Option<u32>,
    /// Byte offset of the span start in the source, inclusive.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub byte_start: Option<u64>,
    /// Byte offset of the span end in the source, exclusive.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub byte_end: Option<u64>,
    /// Wall-clock time the source event happened or was seen.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub observed_at: Option<DateTime<Utc>>,
    /// Wall-clock time the extractor produced this record.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub extracted_at: Option<DateTime<Utc>>,
    /// Version tag of the producing extractor, verbatim.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub extractor_version: Option<String>,
    /// Confidence in `[0,1]`. `None` = treated as 1.0.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub confidence: Option<f32>,
    /// Free-form metadata. Use sparingly — first-class fields above
    /// are preferred.
    #[serde(default, skip_serializing_if = "serde_json::Value::is_null")]
    pub metadata: serde_json::Value,

    /// Which user persisted this evidence. `None` for older
    /// records and for anonymous calls.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub author: Option<AuthorStamp>,
}

impl Evidence {
    /// Shorthand constructor for tests/fixtures.
    pub fn quick(
        id: &str,
        tenant: TenantId,
        project: ProjectId,
        source_type: &str,
        source_id: &str,
        content: &str,
    ) -> Self {
        Self {
            id: EvidenceId(id.to_string()),
            tenant_id: tenant,
            project_id: project,
            source_uri: format!("antares://{source_type}/{source_id}"),
            source_type: source_type.to_string(),
            source_id: source_id.to_string(),
            content: content.to_string(),
            char_start: None,
            char_end: None,
            byte_start: None,
            byte_end: None,
            observed_at: None,
            extracted_at: None,
            extractor_version: None,
            confidence: None,
            metadata: serde_json::Value::Null,
            author: None,
        }
    }
}