//! Interactive worlds — `extensions/interactive-worlds.md`. //! //! Media that consumes input. A world is a deterministic, content- //! addressed artifact; everything that ever happens in it is a signed //! operation ([`op::CausalOp`]); and any op set replays to a bit-exact //! state hash on every conformant sink (**replay-equivalence**, the //! temporal generalization of the core spec's decode-equivalence). //! //! The single-player input log and the multiplayer op log are the same //! object: an input event is an op emitted by one actor. One actor's //! log is a session, a sealed log is a replay, N interleaved logs are //! a shared world. Three capabilities, one container format //! ([`container::WorldContainer`], magic `WWLD`), differing only in //! the op log's seal state. //! //! What this module standardizes: the container, the op, canonical //! ordering, causality, the simulation contract, state hashing, and //! convergence. What it deliberately does NOT standardize: a physics //! engine. Sim capabilities register separately ([`sim::Sim`]) under //! the contract that they be deterministic under the declared numeric //! profile, pure per tick, and convergent. [`sim::Kinematic0`] is the //! reference registrant the conformance corpus is built on. pub mod container; pub mod contract; pub mod feed; pub mod fixed; pub mod graph; pub mod op; pub mod receipt; pub mod replay; pub mod rng; pub mod sim; pub mod skeletal; pub mod truss; pub use container::{AssetEntry, Seal, WorldContainer, MAGIC_WWLD}; pub use contract::SimContract; pub use fixed::Fx; pub use graph::WorldState; pub use op::{mint_node_id, CausalOp, OpId}; pub use receipt::SessionReceipt; pub use replay::{ collect_checkpoints, collect_checkpoints_and_work, collect_checkpoints_sampled, run_sampled_dispatch, run_sealed_dispatch, Checkpoint, LiveWorld, Replayer, }; pub use rng::Xoshiro256pp; pub use feed::{Cell, FeedRecord, FeedState, CAP_SIM_FEED0}; pub use skeletal::{Bone, Skeletal0, CAP_SIM_SKELETAL0}; pub use sim::{Ballistic0, Kinematic0, Resolve, Sim}; pub use truss::{Truss0, TrussNode}; /// World identity (extension §7.4 / §8): BLAKE3 over the scene — the /// canonical contract bytes and tick-0 graph bytes — domain /// `wai:world-scene\x01`. Two sessions of the same world, and two /// actors who "opened the same hash", share this value. pub fn world_hash(contract_bytes: &[u8], graph_bytes: &[u8]) -> [u8; 32] { let mut h = blake3::Hasher::new(); h.update(DOMAIN_SCENE); h.update(contract_bytes); h.update(graph_bytes); *h.finalize().as_bytes() } /// Content hash of an asset (extension §4.1): `BLAKE3(DOMAIN_ASSET || /// envelope_bytes)`, computed over a **complete WAI envelope** (the /// `WAI1` magic + manifest + payload), the same discipline as /// jwp-receipts §2.1. An [`AssetEntry`]'s `hash` is this value; a sink /// fetches the envelope, recomputes the hash, and rejects a mismatch /// before decoding. Assets are presentation-only — neither this hash /// nor the asset bytes ever enter the state hash, which is what keeps /// conformance state-level while presentation streams independently. pub fn asset_content_hash(envelope_bytes: &[u8]) -> [u8; 32] { let mut h = blake3::Hasher::new(); h.update(DOMAIN_ASSET); h.update(envelope_bytes); *h.finalize().as_bytes() } /// Registered capability strings live in the central registry /// ([`crate::codecs`], SPEC.md §5 registration discipline: once /// registered, the payload format is fixed forever); re-exported here /// for locality. pub use crate::codecs::{ CAP_MESH_GLB, CAP_SPLAT_SPZ, CAP_WORLD_LIVE, CAP_WORLD_REPLAY, CAP_WORLD_SCENE, }; /// Registered deterministic numeric profiles (extension §6.2). pub const NUMERIC_FIXED64: &str = "wai.det.fixed64"; /// Registered conflict-resolution functions (extension §6.5). pub const RESOLVE_LWW: &str = "wai.world.resolve.lww"; pub const RESOLVE_SUM: &str = "wai.world.resolve.sum"; /// Domain separators. Same discipline as jwp-receipts §2.1: every hash /// and signature in this extension is domain-separated so bytes can /// never be replayed across contexts. pub const DOMAIN_OP: &[u8] = b"wai:world-op\x01"; pub const DOMAIN_NODE: &[u8] = b"wai:world-node\x01"; pub const DOMAIN_STATE: &[u8] = b"wai:world-state\x01"; pub const DOMAIN_SEAL: &[u8] = b"wai:world-seal\x01"; pub const DOMAIN_OPS_BATCH: &[u8] = b"wai:world-ops\x01"; pub const DOMAIN_SCENE: &[u8] = b"wai:world-scene\x01"; pub const DOMAIN_ASSET: &[u8] = b"wai:asset\x01"; /// Errors across the world module. Conformance is all-or-nothing /// (extension §7.2): a file that fails MUST be reported failed, never /// presented as approximately right — hence no lossy/lenient variants. #[derive(Debug)] pub enum WorldError { /// First 4 payload bytes are not `WWLD`. BadMagic, /// Byte stream ended mid-structure. Truncated, /// A required section is absent (kind in payload). MissingSection(u8), /// An Ed25519 signature failed verification. BadSignature, /// Op's actor bytes are not a valid Ed25519 public key. BadActorKey, /// A dep names an op not present in the log / not yet applied. DepMissing(OpId), /// Sealed log is not in canonical `(effect_tick, lamport, actor)` order. NotCanonicalOrder, /// Duplicate op id in a log. DuplicateOp(OpId), /// `effect_tick == 0`: tick 0 is the authored graph, ops start at 1. EffectTickZero, /// Op lands at or before a receipted (sealed) checkpoint — history /// is immutable (extension §5.6). SealedHistory { effect_tick: u64, sealed_tick: u64 }, /// Mutation kind the declared sim capability does not register. UnknownMutationKind(u16), /// Mutation payload malformed for its kind. BadMutation, /// Create-op target does not equal `mint_node_id(actor, lamport)` /// (extension §5.4 — minting is deterministic, never chosen). BadNodeMint, /// Computed state hash differs from the seal / expectation. HashMismatch { tick: u64, expected: [u8; 32], got: [u8; 32] }, /// Seal section present on a non-replay, absent on a replay, or /// its final tick disagrees with the op log. BadSeal(&'static str), /// Simulation contract JSON is malformed or names an unregistered /// profile / algorithm. BadContract(String), /// The contract's `sim` names a capability this sink does not have /// — the world is inert here (SPEC.md §4 step 6 semantics). UnknownSimCapability(String), } impl std::fmt::Display for WorldError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::BadMagic => write!(f, "payload is not a WWLD container"), Self::Truncated => write!(f, "byte stream truncated"), Self::MissingSection(k) => write!(f, "required section 0x{k:02x} missing"), Self::BadSignature => write!(f, "Ed25519 signature verification failed"), Self::BadActorKey => write!(f, "actor bytes are not a valid Ed25519 public key"), Self::DepMissing(id) => write!(f, "dep not satisfied: lamport {} of actor {}", id.lamport, hex8(&id.actor)), Self::NotCanonicalOrder => write!(f, "sealed op log not in canonical order"), Self::DuplicateOp(id) => write!(f, "duplicate op: lamport {} of actor {}", id.lamport, hex8(&id.actor)), Self::EffectTickZero => write!(f, "effect_tick 0 is reserved for the authored graph"), Self::SealedHistory { effect_tick, sealed_tick } => write!( f, "op at tick {effect_tick} lands at/before receipted checkpoint {sealed_tick}: history is immutable" ), Self::UnknownMutationKind(k) => write!(f, "mutation kind 0x{k:04x} not registered by the sim capability"), Self::BadMutation => write!(f, "mutation payload malformed for its kind"), Self::BadNodeMint => write!(f, "create target != BLAKE3-minted node id"), Self::HashMismatch { tick, .. } => write!(f, "state hash mismatch at tick {tick}"), Self::BadSeal(why) => write!(f, "bad seal: {why}"), Self::BadContract(why) => write!(f, "bad simulation contract: {why}"), Self::UnknownSimCapability(cap) => write!(f, "missing sim capability `{cap}` — world is inert at this sink"), } } } impl std::error::Error for WorldError {} fn hex8(bytes: &[u8; 32]) -> String { bytes[..4].iter().map(|b| format!("{b:02x}")).collect() }