open-standards/wai/wai-rs/src/world/mod.rs
Transaction Science 7636314a0e wai: linear film — wai.film.linear, a sealed camera-on-rails world
The taxonomy's #1 commercial wedge (animation / CGI film) was the last 🟡
with the substrate already built. A film is a sealed wai.world.replay +
a keyframed camera track + a frame schedule: ship the world that generates
the imagery, not the pixels. The sink renders the frames at its own
resolution/rate/quality — lever 3 (instructions-at-the-sink) for the
synthesizable slice of "video". Whole films travel in ~1 KB.

- film feature (reuses the world engine + Fx floor + blake3): the WFLM
  container (contract + embedded WWLD + camera track) and the deterministic
  reconstruct contract. Conformance = film-equivalence: per-frame
  BLAKE3(world_state_hash(frame_tick) || interpolated camera pose) is
  bit-identical on every machine. It composes the embedded world's
  replay-equivalence (inherited unchanged) with the camera track in the
  wai.det.fixed64 floor; the render (pixels) stays the sink's, exactly as
  the worlds renderer / audio-scene HRTF.
- World engine gains one general primitive: collect_checkpoints_sampled /
  run_sampled_dispatch — read the state hash at an arbitrary frame cadence,
  independent of the contract's checkpoint cadence (a renderer samples the
  timeline at its own frame rate). Additive; world corpus still green.
- FilmReceipt (per-frame Merkle leaves, the splat4d shape) + a wai_meter
  .wflm branch that brackets a real frame-reconstruction burst and emits
  MEASURED joules.
- Registered (wai.film.linear, tiered Lossless — film-equivalence is exact);
  corpus film-conformance/ + wai_film_vectors gen|verify (dolly, two-shot,
  crane-up), wired into the four-platform conformance matrix.
- Promoted to extensions/linear-film.md + SPEC §5 temporal row; taxonomy
  animation-film → ✅; README + CHANGELOG. Honest scope: the size win is for
  films GENERATED from a world (animation/CGI/motion-graphics); live-action
  capture is irreducible samples and stays wai.video.*.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-16 09:06:28 -04:00

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, 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()
}