mempill_core/application/dto.rs
1//! Public DTOs — the stable API surface consumed by all bindings.
2//!
3//! Domain types from `mempill-types` are referenced here but raw internal engine types
4//! never cross this boundary; callers only see these structs.
5
6use mempill_types::{
7 AgentId, BeliefProjection, Cardinality, ClaimRef, Confidence, Criticality, Disposition,
8 HistoryEntryStatus, LedgerEntry, ProvenanceLabel, ValidTime,
9};
10
11// ── INGEST CLAIM ──────────────────────────────────────────────────────────────
12
13/// Public write request. Maps to domain Claim at the application boundary.
14#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
15pub struct IngestClaimRequest {
16 /// The agent performing the write.
17 pub agent_id: AgentId,
18 /// Opaque key — the entity the claim is about (e.g. `"acme:ceo"`). mempill does
19 /// **not** perform entity resolution; you must use the same `subject` on write and
20 /// read. Adopt a canonical key convention and apply it consistently across both paths.
21 pub subject: String,
22 /// Opaque key — the property being asserted (e.g. `"held_by"`). Like [`Self::subject`],
23 /// it is matched verbatim; the engine cannot reconcile differently-keyed facts for you.
24 pub predicate: String,
25 /// The JSON value being asserted.
26 pub value: serde_json::Value,
27 /// Required; no default imposed here — gateway enforces ModelDerived default for model output.
28 pub provenance: ProvenanceLabel,
29 /// Caller-supplied cardinality hint; the adjudication gate may override or contest it.
30 pub cardinality: Cardinality,
31 /// None = unknown; fallback to tx_time ordering.
32 pub valid_time: Option<ValidTime>,
33 /// Confidence in the value and valid-time assertion (0.0–1.0 each).
34 pub confidence: Confidence,
35 /// Criticality class for this claim.
36 pub criticality: Criticality,
37 /// Lineage for ModelDerived claims.
38 pub derived_from: Vec<ClaimRef>,
39}
40
41/// Response from a successful claim ingest.
42#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
43pub struct IngestClaimResponse {
44 /// Stable UUID reference to the committed claim.
45 pub claim_ref: ClaimRef,
46 /// The engine's disposition for this write.
47 pub disposition: Disposition,
48 /// Populated when disposition is Contested or PendingConflict.
49 pub contested_with: Vec<ClaimRef>,
50}
51
52// ── QUERY MEMORY ──────────────────────────────────────────────────────────────
53
54/// Request to retrieve the current belief for a (subject, predicate) subject-line.
55#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
56pub struct QueryMemoryRequest {
57 /// The agent whose memory is queried.
58 pub agent_id: AgentId,
59 /// The subject of the query.
60 pub subject: String,
61 /// The predicate of the query.
62 pub predicate: String,
63 /// Optional: query as of a specific transaction time (bi-temporal as-of query).
64 pub as_of_tx_time: Option<chrono::DateTime<chrono::Utc>>,
65}
66
67/// Response from a memory query — the canonical belief projection.
68#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
69pub struct QueryMemoryResponse {
70 /// Canonical fold result; computed at read time, never persisted.
71 pub belief: BeliefProjection,
72}
73
74// ── RECONCILE ─────────────────────────────────────────────────────────────────
75
76/// Request to reconcile one or more subject lines.
77#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
78pub struct ReconcileRequest {
79 /// The agent whose subject lines are reconciled.
80 pub agent_id: AgentId,
81 /// Subject lines to reconcile. Empty = reconcile all subject lines for agent_id.
82 pub subject_lines: Vec<(String, String)>, // (subject, predicate) pairs
83}
84
85/// Response from a reconciliation pass.
86#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
87pub struct ReconcileResponse {
88 /// Per-claim disposition outcomes from the reconciliation pass.
89 pub outcomes: Vec<(ClaimRef, Disposition)>,
90 /// Number of subject lines that required oracle escalation.
91 pub oracle_escalations: u32,
92}
93
94// ── QUERY HISTORY ────────────────────────────────────────────────────────────
95
96/// Request to retrieve the full history timeline for a (subject, predicate) subject-line.
97///
98/// Returns all claims ever written to the line, ordered by the canonical ordering key
99/// (valid_time_start when confidence ≥ threshold, else tx_time). Each entry is tagged
100/// `Current` or `Superseded` based on the same canonical fold that powers `query_memory`.
101#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
102pub struct QueryHistoryRequest {
103 /// The agent whose history is queried.
104 pub agent_id: AgentId,
105 /// The subject of the history query.
106 pub subject: String,
107 /// The predicate of the history query.
108 pub predicate: String,
109}
110
111/// One slot in the history timeline for a subject-line.
112///
113/// `status` is derived from `is_live` in the canonical fold — the `Current` entry is
114/// exactly the claim that `recall` / `query_memory` would return as primary.
115#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
116pub struct HistoryEntry {
117 /// Stable reference to the underlying claim (UUID).
118 pub claim_ref: ClaimRef,
119 /// The asserted value for this claim.
120 pub value: serde_json::Value,
121 /// Start of the valid-time window, or `None` if unknown.
122 pub valid_from: Option<chrono::DateTime<chrono::Utc>>,
123 /// Effective end of the slot: equals the successor's canonical ordering key,
124 /// or `None` for the open-ended current slot.
125 pub valid_until: Option<chrono::DateTime<chrono::Utc>>,
126 /// Whether this claim is the live belief or has been superseded.
127 pub status: HistoryEntryStatus,
128 /// Human-readable provenance label (e.g. `"External/UserAsserted"`).
129 pub provenance: String,
130 /// Confidence in the claim's value (0.0–1.0).
131 pub value_confidence: f32,
132}
133
134/// Response from `query_history` — the full ordered timeline for a subject-line.
135#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
136pub struct QueryHistoryResponse {
137 /// All claims for the subject-line, ordered by canonical ordering key (oldest first).
138 pub entries: Vec<HistoryEntry>,
139}
140
141impl QueryHistoryResponse {
142 /// Convenience: returns the single `Current` entry, if any.
143 pub fn current(&self) -> Option<&HistoryEntry> {
144 self.entries.iter().find(|e| e.status == HistoryEntryStatus::Current)
145 }
146}
147
148// ── AUDIT QUERY ───────────────────────────────────────────────────────────────
149
150/// Request to query the audit ledger.
151#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
152pub struct AuditQueryRequest {
153 /// The agent whose audit ledger is queried.
154 pub agent_id: AgentId,
155 /// None = load full ledger for agent_id.
156 pub claim_ref: Option<ClaimRef>,
157 /// Filter to entries recorded at or after this transaction time.
158 pub from_tx_time: Option<chrono::DateTime<chrono::Utc>>,
159 /// Maximum number of entries to return.
160 pub limit: usize,
161}
162
163/// Response from an audit ledger query.
164#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
165pub struct AuditQueryResponse {
166 /// The matching audit ledger entries.
167 pub entries: Vec<LedgerEntry>,
168}