1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
//! The sealed contract's response and request shapes, as Rust types.
//!
//! # Why the crate holds these at all
//!
//! [`crate::decode`] takes no view on what a response decodes into, and that
//! was right while nothing in this crate knew the shape of an answer. It is
//! wrong once the shape is *sealed*: `SessionItem` is not a consumer's opinion,
//! it is a published contract vendored into this crate byte-for-byte. Every
//! consumer that modelled it separately was maintaining a private copy of a
//! shared fact — and private copies of a shared fact drift silently, which is
//! the failure this whole crate exists to end.
//!
//! So the typed surface is the **default**: [`crate::core::CoreClient`]'s named
//! methods return these types. The generic seam stays exactly where it was —
//! [`crate::core::CoreClient::call`] is still generic in its response type, and
//! [`crate::decode::typed`] still decodes into whatever a caller names. That is
//! the escape hatch, and it is the right tool for the fidelity operations: an
//! archive written from a typed decode is an archive of the fields this build
//! happened to know about.
//!
//! # The decoding rules, and why each one is what it is
//!
//! The contract's schemas declare almost no required properties: the server
//! omits an empty field rather than sending it. Every rule below follows from
//! that, and from one more: **an additive server change must never break a
//! consumer.**
//!
//! - **Unknown fields pass silently.** No `deny_unknown_fields`, anywhere. A
//! field this build has never heard of is a newer server, not a malformed
//! response, and refusing the document would turn a routine deploy into an
//! outage for every older client. What catches the addition instead is the
//! [`coverage`] gate, at build time, where a human can decide about it.
//! - **An absent field decodes to its default.** Container-level
//! `#[serde(default)]`, on every model — except where the contract marks a
//! property `required`, which today is exactly one field
//! ([`StandaloneTraceDetail::session_id`]). There the model defaults every
//! *other* field and leaves that one strict, so a document missing the
//! guarantee the schema publishes is refused rather than read as `""`.
//! - **A null in a composite position decodes to its default too.** A nil map,
//! slice, or struct pointer that is not omitted arrives as `null`, and a
//! model that errored on one would let a single empty projection blank an
//! entire page. Scalars stay strict: the contract declares no nullable
//! scalar, so a null in one is a real disagreement worth surfacing.
//! - **Response models are `#[non_exhaustive]`, request models are not.** A
//! response is the server's to grow; a request body is the caller's to build,
//! and a body nobody outside this crate could construct would be useless.
//! This holds for the *components* of a request body too — an inner struct
//! marked `non_exhaustive` makes its fields unreachable just as surely as
//! marking the outer one would, and leaves a caller with nothing but
//! `Default`. A test outside the crate constructs every request body by
//! struct literal, which is the only place the marker's effect is visible.
//! - **A request field whose absence means something is an [`Option`] that is
//! omitted.** The partial-update bodies are the reason: the server applies
//! the properties a `PUT`/`PATCH` body carries and leaves the rest alone, so
//! a model that always serialized every field would turn every one-field
//! update into a wipe of the others. `#[serde(skip_serializing_if =
//! "Option::is_none")]` is what makes an unset field genuinely absent from
//! the bytes rather than present and empty. Where absence carries no
//! distinct meaning — a create body, whose fields land on a fresh record —
//! the field stays plain, because an `Option` there would be ceremony
//! without a distinction behind it.
//!
//! # What is deliberately not typed further
//!
//! - **Timestamps stay `String`.** The contract says `string`/`date-time`, and
//! parsing one into a datetime type would make an unparseable value a decode
//! failure at the *response* level — one odd timestamp blanking a whole page
//! — in exchange for a convenience every consumer can add itself.
//! - **Enumerable strings stay `String`.** `status`, `kind`, `call_kind`,
//! `verdict` and their kin are declared as plain strings; the document names
//! no closed set. A Rust enum here would invent a contract the server never
//! made, and would fail exactly when the server added a variant.
//! - **Opaque objects stay [`serde_json::Value`].** Where the contract says
//! `type: object` with no properties — a span's content blocks, a raw turn's
//! metadata — there is nothing to model, and inventing a shape would be the
//! drift this module exists to prevent.
//!
//! # The gate
//!
//! [`coverage`] walks the vendored document's schemas and holds these types to
//! them: every schema is modelled or deliberately allow-listed, every property
//! survives a round trip through its model, and the decoding rules above are
//! asserted rather than assumed. A contract bump that adds a field fails the
//! build, the same way one that adds an operation fails [`crate::core::coverage`].
use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
/// A type that models one named schema of the vendored contract.
///
/// The association is what makes the [`coverage`] gate possible: without a
/// declared schema name, "is every response schema modelled?" would be a
/// question only a human could answer, and the answer would rot. It is also the
/// documentation a reader wants — which published shape *is* this type.
/// Decode `null` as the type's default rather than as a failure.
///
/// Applied to every composite field — see the module docs for why a null
/// arrives at all, and why scalars deliberately do not get this treatment.
///
/// # Errors
///
/// Propagates the underlying decode failure for anything that is neither
/// `null` nor a valid value of the field's type.