The crates shared by the Resonate server implementations
(resonate-on-kafka, resonate-on-s3).
The implementation repos consume these crates by relative path, so this repo must be checked out as a SIBLING of the implementations:
<workspace>/
├── resonate-common/ (this repo)
├── resonate-egress/
├── resonate-sansio/
├── resonate-on-kafka/
└── resonate-on-s3/
Clone them next to each other and cargo test works in every repo. Everything here is the
substrate-neutral, spec-derived part — the code both servers must agree on
byte-for-byte because it is checked against the same oracle:
crates/protocol(resonate-protocol) — the CONTRACT: the request/response vocabulary and the externally observable records (promise, task, schedule). This is the only layer clients ever see, and the boundary the conformance oracle checks. Featureschedulesadds theCronEvaltrait for servers that implement the schedule subsystem (the event-sourced server enables it; the document-model server answers 501 and builds without it).crates/wire(resonate-wire) — the{kind, data}JSON codec between the spec's envelope andRequest/Response. Response data byte-matches the spec oracle'swire.go. Includes the strict fence-action decoding (unknown action kinds are 400, never defaulted).crates/invariant(resonate-invariant) — theinvariant!/violation!macros: abort-on-violation in production (unrescuable bycatch_unwind), featureunwindflips to panic for#[should_panic]tests.crates/lincheck(resonate-lincheck) — an implementation-independent linearizability checker over the contract: histories ofRequest/Responseops with real-time windows, where a lost-response op is PENDING and the search places it (it landed) or omits it (it did not). Each implementation plugs in its own pure handlers via theSeqModeltrait — state stays opaque behind an associated type, so no internal shapes leak into this crate. Wired into the kafka kernel's DST (crash-ambiguity law over every seeded history) and s3's machine tests (phantom-op placement overmachine::decide).
What deliberately does NOT live here: the handlers AND the internal object
model (object.rs: PromiseObject, TaskObject, Workflow, plus the
to_record/project projections). Internal state representation is
implementation territory — each server carries its own copy, and any
implementation may represent state completely differently, owing the world
only record-level conformance at the protocol boundary (enforced by the
external oracle, not by shared code). Likewise the handlers: the two
servers are different dialects of the same Dafny model — event-sourced
decide vs direct-mutation Load-Modify-Store — kept behaviorally identical
by transcription discipline, not by shared code.
Consumed by path dependency from each sibling workspace. The s3 workspace
renames the packages back to their local names (wire, invariant) via
package = keys, so no source changes were needed there.