Expand description
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 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 thecoveragegate, at build time, where a human can decide about it. - An absent field decodes to its default. Container-level
#[serde(default)], on every model. - 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 markednon_exhaustivemakes its fields unreachable just as surely as marking the outer one would, and leaves a caller with nothing butDefault. 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
Optionthat is omitted. The partial-update bodies are the reason: the server applies the properties aPUT/PATCHbody 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 anOptionthere would be ceremony without a distinction behind it.
§What is deliberately not typed further
- Timestamps stay
String. The contract saysstring/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,verdictand 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 saystype: objectwith 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.
Re-exports§
pub use admin::DeriveRunResponse;pub use admin::ReconcileStats;pub use admin::RederiveReport;pub use admin::SeedDemoRequest;pub use admin::SeedResult;pub use admin::StatsResponse;pub use params::ExportDetail;pub use params::ExportSessionParams;pub use params::ExportSessionsParams;pub use params::PayloadDetail;pub use params::SearchSpansParams;pub use params::SessionListParams;pub use params::SessionTracesParams;pub use params::SkillScope;pub use params::SkillSort;pub use params::SkillsListParams;pub use params::SortDirection;pub use params::StatsParams;pub use params::TraceListParams;pub use params::TraceParams;pub use protocol::ErrorResponse;pub use protocol::McpError;pub use protocol::McpRequest;pub use protocol::McpResponse;pub use raw_turn::RawTurnAttribution;pub use raw_turn::RawTurnAttributionRepairRequest;pub use raw_turn::RawTurnAttributionRepairResult;pub use raw_turn::RawTurnHeaderItem;pub use raw_turn::RawTurnListResponse;pub use raw_turn::RepairPendingSession;pub use session::ModelUsage;pub use session::SessionDetailResponse;pub use session::SessionItem;pub use session::SessionListResponse;pub use session::SessionRollup;pub use session::SessionTracesResponse;pub use session::SessionUpdateRequest;pub use session::SessionUsage;pub use session::TreeTask;pub use skill::CreateSkillRequest;pub use skill::GenerateSkillRequest;pub use skill::GenerateSkillRequestHint;pub use skill::PublishSkillRequest;pub use skill::SessionSkillsResponse;pub use skill::SkillCounts;pub use skill::SkillResponse;pub use skill::SkillVersionResponse;pub use skill::SkillVersionsResponse;pub use skill::SkillsListResponse;pub use skill::UpdateSkillRequest;pub use span::SpanItem;pub use span::SpanLinkItem;pub use span::SpanSearchOutput;pub use span::SpanSearchResult;pub use trace::MainUsage;pub use trace::TraceDetail;pub use trace::TraceItem;pub use trace::TraceListResponse;pub use trace::TraceUsage;
Modules§
- admin
- Administrative and aggregate shapes: seeding, derive runs, and stats.
- coverage
- The schema-coverage gate.
- params
- Typed parameters for the sealed operations that take them.
- protocol
- Shapes that belong to a protocol rather than to the read model: the error body every non-success answer carries, and the JSON-RPC frames of the MCP endpoint.
- raw_
turn - Raw-turn shapes: the wire log behind a derivation, and its repairs.
- session
- Session shapes: the capture identity and the deriver’s projection.
- skill
- Skill shapes.
- span
- Span shapes: the observed units of work, their edges, and search hits.
- trace
- Trace shapes: one user-visible turn, its header, and its spend.
Traits§
- Contract
Model - A type that models one named schema of the vendored contract.
Functions§
- null_
default - Decode
nullas the type’s default rather than as a failure.