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}