Skip to main content

Module models

Module models 

Source
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 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.
  • 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.

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§

ContractModel
A type that models one named schema of the vendored contract.

Functions§

null_default
Decode null as the type’s default rather than as a failure.