Skip to main content

kamaji_proto/
lib.rs

1//! `kamaji-proto` — Yubaba ↔ Kamaji wire protocol.
2//!
3//! Wire shape:
4//!
5//! ```text
6//! [u32 LE length][postcard-encoded payload]
7//! ```
8//!
9//! The crate has no I/O. Callers (yubaba, kamaji) own the
10//! [`tokio::net::UnixStream`](https://docs.rs/tokio/latest/tokio/net/struct.UnixStream.html)
11//! and push/pull framed bytes through [`encode_frame`] / [`decode_frame`].
12//!
13//! Payload fields carrying a structure that *accretes* — the workload spec, the
14//! workload entries, the node capabilities — are encoded as a length-prefixed
15//! JSON blob inside that frame rather than inline (R896-F2). A peer one field
16//! behind skips a field it does not know instead of misreading every byte after
17//! it. See [`tolerant`] for the bound on which fields get this and why the frame
18//! and the greeting deliberately do not.
19//!
20//! Both directions are versioned via [`ProtocolVersion`]; peers exchange
21//! [`YubabaToKamaji::Hello`] / [`KamajiToYubaba::Welcome`] at connection start.
22//! The handshake is **exact equality, not negotiation**: kamaji refuses any
23//! version that is not its own `CURRENT` (`kamaji-bin/src/server.rs`). This
24//! paragraph used to claim the receiver "picks the highest version it supports
25//! that the sender also offers" — it never did, and every operational note in
26//! the tree (`scripts/hotship.sh`, R876) describes the refusal instead. Corrected
27//! under R896-S1, because roll-safety reasoning was being done from the wrong
28//! sentence.
29//!
30//! @arch:see(.yah/docs/working/W154-yubaba-dual-runtime.md)
31//!
32//! @yah:relay(R896, "Evolvable kamaji wire envelope: stop the schema migrating into annotations")
33//! @yah:at(2026-09-11T22:26:53Z)
34//! @yah:assignee(agent:user-custom-char-gul2)
35//! @yah:next("From the 2026-09-11 yubaba/kamaji architecture review (chat session:d6fc1d54): the positional-postcard wire makes every WorkloadSpec field change a fleet-wide coordinated roll (R885-T6's three-node bump), so new schema-shaped facts now land in annotations instead of fields — yah.limits.*, yah.durability.*, yah.placement.* — a stringly second WorkloadSpec that bypasses the JSON schema, TS export and serde validation, with R885-T6's handoff naming the cost driver outright (\"annotation not field, because a field costs exactly the wire bump\"). Substrate MARKERS (yah.exec, yah.sandbox) are correct as annotations and stay. This track exists to make single-node hotships able to cross a field change, which is what keeps the chaos-survivability property cheap permanently.")
36//! @arch:see(oss/yah-base/crates/workload-spec/src/lib.rs)
37
38pub mod codec;
39pub mod digest;
40pub mod messages;
41pub mod tolerant;
42pub mod version;
43
44pub use codec::{decode_frame, encode_frame, Error, MAX_FRAME_BYTES};
45pub use digest::{spec_digest, SpecDigest};
46pub use messages::{
47    AckKind, DrainBudget, DrainOutcome, DrainPhase, ErrorCode, ExitStatus, KamajiToYubaba,
48    LogRecord, LogStreamTag, MeshAssignment, MicroVmHealth, NodeCapabilities, ProbeStatus,
49    RequestId, WireguardPeer, WorkloadEntry, WorkloadId, WorkloadState, YubabaToKamaji,
50};
51pub use version::ProtocolVersion;