Skip to main content

tapes_client/core/models/
raw_turn.rs

1//! Raw-turn shapes: the wire log behind a derivation, and its repairs.
2//!
3//! The raw layer is immutable. What can be corrected is the *attribution*
4//! projected over it, which is why the repair shapes describe a replacement
5//! projection rather than an edit.
6
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9
10use super::ContractModel;
11
12/// One wire-log row: what crossed the wire (or arrived as a transcript push),
13/// without the payload blobs.
14///
15/// Models the contract's `RawTurnHeaderItem` schema.
16#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
17#[serde(default)]
18#[non_exhaustive]
19pub struct RawTurnHeaderItem {
20    /// The contract's `agent_name`.
21    pub agent_name: String,
22
23    /// The contract's `id`.
24    pub id: i64,
25
26    /// The contract's `meta`.
27    pub meta: Value,
28
29    /// The contract's `provider`.
30    pub provider: String,
31
32    /// How many verbatim upstream response bytes the raw layer retained for
33    /// this turn, as they arrived on the wire and before any reduction; 0
34    /// when none were kept.
35    pub raw_response_bytes: i64,
36
37    /// True when the turn's verbatim response existed but was not retained —
38    /// it exceeded the 8 MiB ingest cap or the producer withheld it — so
39    /// `raw_response_bytes == 0` with this set is a fidelity gap, not a turn
40    /// that never had verbatim bytes.
41    pub raw_response_dropped: bool,
42
43    /// The contract's `received_at`, an RFC 3339 timestamp.
44    pub received_at: String,
45
46    /// The request size the capture adapter recorded at capture time
47    /// (`meta.request_bytes`), not a measurement of the stored payload; 0
48    /// when the producer did not report one.
49    pub request_bytes: i64,
50
51    /// The contract's `request_id`.
52    pub request_id: String,
53
54    /// The response size the capture adapter recorded at capture time
55    /// (`meta.response_bytes`), not a measurement of the stored payload; 0
56    /// when the producer did not report one.
57    pub response_bytes: i64,
58
59    /// The contract's `source`.
60    pub source: String,
61}
62
63impl ContractModel for RawTurnHeaderItem {
64    const SCHEMA: &'static str = "RawTurnHeaderItem";
65}
66
67/// One page of a session's wire log, in raw turn id order.
68///
69/// Models the contract's `RawTurnListResponse` schema.
70#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
71#[serde(default)]
72#[non_exhaustive]
73pub struct RawTurnListResponse {
74    /// The contract's `items`.
75    #[serde(deserialize_with = "super::null_default")]
76    pub items: Vec<RawTurnHeaderItem>,
77
78    /// Continues the walk from the last raw turn of this page (pass it as
79    /// `cursor`). Empty once the page reached the session's last raw turn.
80    #[serde(deserialize_with = "super::null_default")]
81    pub next_cursor: String,
82}
83
84impl ContractModel for RawTurnListResponse {
85    const SCHEMA: &'static str = "RawTurnListResponse";
86}
87
88impl RawTurnListResponse {
89    /// This listing as one page of the crate's pagination convention.
90    ///
91    /// The envelope is `items` plus `next_cursor`, which is exactly
92    /// [`crate::page::Page`] — so a caller walking a wire log reaches the
93    /// same loop, the same three spellings of "no more pages", and the same
94    /// guard against a server that repeats a cursor as every other listing.
95    #[must_use]
96    pub fn into_page(self) -> crate::page::Page<RawTurnHeaderItem> {
97        crate::page::Page {
98            items: self.items,
99            next_cursor: Some(self.next_cursor),
100        }
101    }
102}
103
104/// The effective, repairable attribution projected over an immutable raw
105/// turn.
106///
107/// Models the contract's `RawTurnAttribution` schema.
108#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
109#[serde(default)]
110#[non_exhaustive]
111pub struct RawTurnAttribution {
112    /// The contract's `harness_id`.
113    pub harness_id: String,
114
115    /// The contract's `harness_session_id`.
116    pub harness_session_id: String,
117
118    /// The contract's `parent_harness_session_id`.
119    pub parent_harness_session_id: String,
120
121    /// The contract's `raw_turn_id`.
122    pub raw_turn_id: i64,
123
124    /// The contract's `thread_id`.
125    pub thread_id: String,
126}
127
128impl ContractModel for RawTurnAttribution {
129    const SCHEMA: &'static str = "RawTurnAttribution";
130}
131
132/// Selects exactly one raw row and supplies a complete replacement
133/// attribution.
134///
135/// Models the contract's `RawTurnAttributionRepairRequest` schema.
136/// default.
137#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
138#[serde(default)]
139pub struct RawTurnAttributionRepairRequest {
140    /// The contract's `harness_id`.
141    pub harness_id: String,
142
143    /// The contract's `harness_session_id`.
144    pub harness_session_id: String,
145
146    /// The contract's `paper_proxy_request_id`.
147    pub paper_proxy_request_id: String,
148
149    /// The contract's `parent_harness_session_id`.
150    pub parent_harness_session_id: String,
151
152    /// The contract's `raw_turn_id`.
153    pub raw_turn_id: i64,
154
155    /// The contract's `reason`.
156    pub reason: String,
157
158    /// The contract's `thread_id`.
159    pub thread_id: String,
160}
161
162impl ContractModel for RawTurnAttributionRepairRequest {
163    const SCHEMA: &'static str = "RawTurnAttributionRepairRequest";
164}
165
166/// What an attribution repair changed, and what it left to converge.
167///
168/// Models the contract's `RawTurnAttributionRepairResult` schema.
169/// default.
170#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
171#[serde(default)]
172#[non_exhaustive]
173pub struct RawTurnAttributionRepairResult {
174    /// The contract's `effective`.
175    #[serde(deserialize_with = "super::null_default")]
176    pub effective: RawTurnAttribution,
177
178    /// The contract's `previous`.
179    #[serde(deserialize_with = "super::null_default")]
180    pub previous: RawTurnAttribution,
181
182    /// ProjectionsPending lists the sessions whose synchronous rebuild failed
183    /// after the correction committed.
184    #[serde(deserialize_with = "super::null_default")]
185    pub projections_pending: Vec<RepairPendingSession>,
186
187    /// The contract's `recorded`.
188    pub recorded: bool,
189
190    /// SourceCleanupPending reports that the best-effort removal of the
191    /// emptied previous-session row failed after the correction and both
192    /// projection rebuilds applied.
193    pub source_cleanup_pending: bool,
194}
195
196impl ContractModel for RawTurnAttributionRepairResult {
197    const SCHEMA: &'static str = "RawTurnAttributionRepairResult";
198}
199
200/// One harness session whose projection rebuild did not complete
201/// synchronously during a repair.
202///
203/// Models the contract's `RepairPendingSession` schema.
204#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
205#[serde(default)]
206#[non_exhaustive]
207pub struct RepairPendingSession {
208    /// The contract's `harness_id`.
209    pub harness_id: String,
210
211    /// The contract's `harness_session_id`.
212    pub harness_session_id: String,
213}
214
215impl ContractModel for RepairPendingSession {
216    const SCHEMA: &'static str = "RepairPendingSession";
217}