Commit the WAI standard source: a content + capability-dispatch standard
whose thesis is "carries whatever it can reconstruct, verifies whatever
it carries." Source only — large vendored/model assets and build output
are gitignored.
Reconstruct classes (each: spec + conformance corpus + in-tab browser
sink that re-derives the corpus hash, one wai.det.fixed64 fixed-point
floor, one *-equivalence apiece):
- interactive worlds (replay-equivalence) + 3 sim registrants,
multiplayer over a relay, session receipts, glTF + real SPZ assets
- spatial audio (mixdown-equivalence)
- haptics (sample-equivalence)
- state-feeds (replay-equivalence, non-physics sim)
- avatars / digital humans (pose-equivalence) + telepresence over the relay
- volumetric / 4D splats (frame-state-equivalence) + WebGPU EWA render,
real-SPZ-derived clip
Verify half (lever 4):
- asset provenance: a signed, energy-accounted lineage for opaque
captured content WAI does not reconstruct; tamper-evident, in-tab.
Cross-cutting: JWP receipt profiles per class; a native energy meter
(IOReport via macmon, no sudo) emitting receipts with REAL measured
joules; the learned-image/neural codec family and JPEG AI entropy port
from earlier work.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
182 lines
8.3 KiB
Rust
182 lines
8.3 KiB
Rust
//! 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, 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()
|
|
}
|