//! Integer-exact INTERACTIVE WORLD MODEL — the byte-exact renderer for
//! `wai.world.model`: every frame is generated by integer arithmetic, so its hash is
//! the same on every machine (a float next-frame network's would not be).
//!
//! An action-conditioned next-frame model, fully integer:
//! ```text
//!   frame_0 = g_s(z_0);   z_{t+1} = clip( T( z_t ‖ action_t ) );   frame_{t+1} = g_s(z_{t+1})
//! ```
//! Both the transition `T` and the synthesis `g_s` are [`IntModel`]s (the int_hyper
//! WHM1 format); the action is folded in as `A` constant input planes, `A` being `T`'s
//! input channels less the latent's. The renderer runs through the integer operator set
//! (`extensions/integer-operators.md`): `T` and `g_s` lowered by `world/1` (§13.5,
//! informative) and loaded under `acc64` with their bounds certificates ([`ops`]), so
//! given `(T, g_s, z_0, action trace)` every frame is byte-identical on every machine,
//! and a value that could take a layer outside its exact integer range is refused
//! (`check` ranges) rather than computed. Paired with [`crate::world_model`]'s signed,
//! replay-equivalent action trace, both the trace AND the generated frames
//! hash-converge: a generative interactive world you can put in a receipt.
//!
//! The renderer is informative: `wai.world.model`'s payload is its action trace, and no
//! payload text yet binds a trace to a renderer's set. Its refusals ([`Refused`]) use the
//! integer payloads' codes: `model_mismatch` for a set that breaks `world/1`'s rules, a row
//! without one value per action plane, or a network that does not fit the latent;
//! `geometry_mismatch` for a latent that is not `C·lat·lat` values; `field_range` for a side
//! of 0, a move whose plane value leaves `i64`, or a value outside a `check` range;
//! `too_large` for a latent past `2^26` values.

use crate::int_hyper_synth::{fnv1a, IntModel, Refused};

pub use ops::{load, World};

/// The reference action set (must match the export tool): stay, +x, −x, +y, −y.
/// `(dx, dy)` are folded into the transition as constant planes (scaled to `2^afrac`).
pub const ACTIONS: [(i64, i64); 5] = [(0, 0), (1, 0), (-1, 0), (0, 1), (0, -1)];

/// Number of action planes appended to the latent for the transition (dx, dy, btn).
pub const A: usize = 3;

/// A decoded interactive clip: one HWC `u8` RGB frame per (initial + per-action) step.
pub struct WorldClip {
    pub frames: Vec<Vec<u8>>,
    pub frame_px: usize,
}

impl WorldClip {
    /// FNV-1a over one frame's RGB bytes — the per-frame portable hash.
    pub fn frame_hash(&self, i: usize) -> u64 {
        fnv1a(&self.frames[i])
    }
    /// The clip hash = FNV-1a over the concatenated per-frame hash bytes.
    pub fn clip_hash(&self) -> u64 {
        let mut all = Vec::with_capacity(self.frames.len() * 8);
        for f in &self.frames {
            all.extend_from_slice(&fnv1a(f).to_be_bytes());
        }
        fnv1a(&all)
    }
}

/// Render a clip from rows of action plane values at `2^afrac`, one value per plane of
/// `T` (§13.5's driver): the set loaded ([`load`]), then [`World::decode_planes`]. A
/// merged multi-actor log maps to one row per op (the acting agent's planes filled,
/// the others 0), so participants co-driving one world render the same frames.
pub fn decode_planes(t_model: &IntModel, gs_model: &IntModel, z0: &[i64], rows: &[Vec<i64>], c: usize, lat: usize) -> Result<WorldClip, Refused> {
    ops::decode_planes(t_model, gs_model, z0, rows, c, lat)
}

/// Render a clip from a single agent's moves `(dx, dy)` ([`World::decode_deltas`]): the
/// path of a merged, canonically ordered multi-actor log from
/// [`crate::world_model::replay`], which renders to one byte-exact frame sequence on every
/// machine, whatever order the ops arrived in.
pub fn decode_deltas(t_model: &IntModel, gs_model: &IntModel, z0: &[i64], deltas: &[(i64, i64)], c: usize, lat: usize) -> Result<WorldClip, Refused> {
    ops::decode_deltas(t_model, gs_model, z0, deltas, c, lat)
}

/// Render a clip from indices into [`ACTIONS`] (past its end, the last).
pub fn decode(t_model: &IntModel, gs_model: &IntModel, z0: &[i64], actions: &[usize], c: usize, lat: usize) -> Result<WorldClip, Refused> {
    ops::decode(t_model, gs_model, z0, actions, c, lat)
}

/// The direct renderer, as `wai.world.model`'s integer renderer ran before it rendered
/// through the integer operator set: `T` and `g_s` run layer by layer by
/// [`crate::int_hyper_synth::legacy::run_net`], with no check of the values they are given.
/// Test-only (feature `legacy_int`): the tests hold the renderer to it, and the two differ
/// only on the planned breaks of `extensions/integer-operators.md` §15.3.
#[cfg(any(test, feature = "legacy_int"))]
pub mod legacy {
    use super::*;
    use crate::int_hyper_synth::legacy::{decode as synth_decode, run_net};

    /// One integer transition step from an explicit set of action **planes**:
    /// `z_{t+1} = clip( T( z_t ‖ plane₀ ‖ … ‖ plane_{A-1} ) )`. Each `planes_q[k]` is a
    /// constant value (already at `2^afrac`) broadcast to one `lat·lat` input plane, so
    /// the number of planes (`A`) is whatever the model expects — `A=3` for a single
    /// agent (dx, dy, btn), `A=4` for two agents (dxA, dyA, dxB, dyB), etc. The next
    /// latent is clamped to `[-2^afrac, 2^afrac]` (the bound the model trained under).
    /// The generalized core every higher-level step path calls.
    pub fn step_planes(t_model: &IntModel, z: &[i64], planes_q: &[i64], c: usize, lat: usize) -> Vec<i64> {
        let one = 1i64 << t_model.afrac;
        let plane = lat * lat;
        let na = planes_q.len();
        let mut inp = Vec::with_capacity((c + na) * plane);
        inp.extend_from_slice(z);
        for &v in planes_q {
            inp.extend(std::iter::repeat_n(v, plane));
        }
        let (mut zn, _, _, _) = run_net(t_model, &inp, c + na, lat, lat);
        for v in &mut zn {
            *v = (*v).clamp(-one, one);
        }
        zn
    }

    /// One integer transition step from raw `(dx, dy)` deltas (single agent, `A=3`).
    pub fn step_delta(t_model: &IntModel, z: &[i64], dx: i64, dy: i64, c: usize, lat: usize) -> Vec<i64> {
        let one = 1i64 << t_model.afrac;
        step_planes(t_model, z, &[dx * one, dy * one, 0], c, lat)
    }

    /// One integer transition step from an action index into [`ACTIONS`].
    pub fn step(t_model: &IntModel, z: &[i64], action: usize, c: usize, lat: usize) -> Vec<i64> {
        let (dx, dy) = ACTIONS[action.min(ACTIONS.len() - 1)];
        step_delta(t_model, z, dx, dy, c, lat)
    }

    /// Decode an interactive world clip from a list of `(dx, dy)` deltas: from `z0`,
    /// render `g_s(z0)`, then for each delta advance the integer transition and render.
    /// The convergence path — a **merged, canonically-ordered multi-actor** action log
    /// (from [`crate::world_model::replay`]) decodes to one byte-exact frame sequence on
    /// every machine, regardless of network arrival order. Pure i64.
    pub fn decode_deltas(t_model: &IntModel, gs_model: &IntModel, z0: &[i64], deltas: &[(i64, i64)], c: usize, lat: usize) -> WorldClip {
        let mut z = z0.to_vec();
        let (f0, frame_px, _) = synth_decode(gs_model, &z, c, lat, lat);
        let mut frames = Vec::with_capacity(deltas.len() + 1);
        frames.push(f0);
        for &(dx, dy) in deltas {
            z = step_delta(t_model, &z, dx, dy, c, lat);
            let (f, _, _) = synth_decode(gs_model, &z, c, lat, lat);
            frames.push(f);
        }
        WorldClip { frames, frame_px }
    }

    /// Decode an interactive world clip from an explicit sequence of action **plane**
    /// rows (each row `planes_q` at `2^afrac`, length = the model's `A`). The general
    /// path — single- or multi-agent. A merged multi-actor log maps to one plane row per
    /// op (the acting agent's slot filled, others zero), so two participants co-drive one
    /// world and every peer renders the IDENTICAL frames. Pure i64.
    pub fn decode_planes(t_model: &IntModel, gs_model: &IntModel, z0: &[i64], rows: &[Vec<i64>], c: usize, lat: usize) -> WorldClip {
        let mut z = z0.to_vec();
        let (f0, frame_px, _) = synth_decode(gs_model, &z, c, lat, lat);
        let mut frames = Vec::with_capacity(rows.len() + 1);
        frames.push(f0);
        for row in rows {
            z = step_planes(t_model, &z, row, c, lat);
            let (f, _, _) = synth_decode(gs_model, &z, c, lat, lat);
            frames.push(f);
        }
        WorldClip { frames, frame_px }
    }

    /// Decode an interactive world clip from action indices (single-actor convenience).
    pub fn decode(t_model: &IntModel, gs_model: &IntModel, z0: &[i64], actions: &[usize], c: usize, lat: usize) -> WorldClip {
        let deltas: Vec<(i64, i64)> = actions.iter().map(|&a| ACTIONS[a.min(ACTIONS.len() - 1)]).collect();
        decode_deltas(t_model, gs_model, z0, &deltas, c, lat)
    }

    /// The direct renderer with the direct guard the other integer decoders ran
    /// ([`crate::int_hyper_synth::legacy::run_net_checked`]): before each layer of `T` and
    /// of `g_s`, the values present are checked against the bounds of that layer's
    /// arithmetic, and a layer that could leave the exact integer range is not run. The
    /// direct renderer itself never checked; this is what the `check` ranges of `world/1`
    /// restate (`extensions/integer-operators.md` §13.2), and what the tests hold the
    /// renderer through the operator set to. Test-only (`legacy_int`).
    #[cfg(any(test, feature = "legacy_int"))]
    pub mod checked {
        use super::*;
        use crate::int_hyper_synth::legacy::run_net_checked;
        use crate::int_hyper_synth::legacy::to_rgb8;

        /// Where the guard refused: the network (`"T"` or `"g_s"`), the step (0 for frame
        /// 0, `k` for the `k`-th row's transition and the frame after it), the layer whose
        /// check failed, and whether that check was about the values (`out_of_range`) or
        /// about the layer itself.
        #[derive(Debug, Clone, Copy, PartialEq, Eq)]
        pub struct Refusal {
            pub net: &'static str,
            pub step: usize,
            pub layer: usize,
            pub out_of_range: bool,
        }

        /// [`super::decode_planes`], with each network run by `run_net_checked`.
        pub fn decode_planes(t_model: &IntModel, gs_model: &IntModel, z0: &[i64], rows: &[Vec<i64>], c: usize, lat: usize) -> Result<WorldClip, Refusal> {
            let at = |net, step| move |r: crate::int_hyper_synth::NetRefusal| Refusal { net, step, layer: r.layer, out_of_range: r.out_of_range };
            let render = |z: &[i64], step: usize| -> Result<(Vec<u8>, usize), Refusal> {
                let (x, oc, oh, ow) = run_net_checked(gs_model, z, c, lat, lat).map_err(at("g_s", step))?;
                Ok((to_rgb8(&x, oc, oh, ow, gs_model.afrac), oh))
            };
            let one = 1i64 << t_model.afrac;
            let plane = lat * lat;
            let mut z = z0.to_vec();
            let (f0, frame_px) = render(&z, 0)?;
            let mut frames = vec![f0];
            for (k, row) in rows.iter().enumerate() {
                let mut inp = z;
                for &v in row {
                    inp.extend(std::iter::repeat_n(v, plane));
                }
                let (mut zn, ..) = run_net_checked(t_model, &inp, c + row.len(), lat, lat).map_err(at("T", k + 1))?;
                for v in &mut zn {
                    *v = (*v).clamp(-one, one);
                }
                z = zn;
                frames.push(render(&z, k + 1)?.0);
            }
            Ok(WorldClip { frames, frame_px })
        }
    }
}

/// The renderer through the integer operator set (`extensions/integer-operators.md`):
/// the transition `T` and the synthesis `g_s` lowered by `world/1` (§13.5, informative;
/// §13.2 for each network's layers), each loaded under `acc64` with its bounds
/// certificate ([`crate::int_ops`]).
pub mod ops {
    use super::*;
    use crate::int_hyper_synth::{refused, RefusalKind, Refused, MAX_TENSOR};
    use wai_ops::{Code, Graph, Loaded, Refusal, Tensor};

    /// A refusal of the operator set as the renderer reports it: a value outside a `check`
    /// range is `field_range`; the other codes keep their names (integer-payloads §8).
    fn kind(r: Refusal, what: &'static str) -> Refused {
        let k = match r.code {
            Code::FieldRange => RefusalKind::FieldRange,
            Code::TooLarge => RefusalKind::TooLarge,
            Code::GeometryMismatch => RefusalKind::GeometryMismatch,
            Code::StreamExhausted => RefusalKind::StreamExhausted,
            Code::StreamNoncanonical => RefusalKind::StreamNoncanonical,
            Code::ModelMismatch => RefusalKind::ModelMismatch,
        };
        refused(k, what)
    }

    const SET: &str = "T and g_s do not lower by world/1 to integer-operator graphs that load under acc64";

    /// Both networks in the form `wai-ops` lowers them from ([`crate::int_ops::whm1_net`]),
    /// and `C` as the lowering takes it.
    fn nets(t: &IntModel, g_s: &IntModel, c: usize) -> Result<(wai_ops::lower::Net, wai_ops::lower::Net, u32), Refused> {
        let c = u32::try_from(c).map_err(|_| refused(RefusalKind::ModelMismatch, SET))?;
        let tn = crate::int_ops::whm1_net(t).map_err(|r| kind(r, SET))?;
        Ok((tn, crate::int_ops::whm1_net(g_s).map_err(|r| kind(r, SET))?, c))
    }

    /// The set's two graphs, `T` then `g_s` (with the RGB8 step), as `world/1` writes them
    /// from the models this crate parsed, for a latent of `c` channels
    /// ([`wai_ops::lower::world_net`]).
    pub fn lower(t: &IntModel, g_s: &IntModel, c: usize) -> Result<(Graph, Graph), Refused> {
        let (tn, gn, c) = nets(t, g_s, c)?;
        let mut roles = wai_ops::lower::world_net(&tn, &gn, c).map_err(|r| kind(r, SET))?.roles.into_iter().map(|(_, g)| g);
        match (roles.next(), roles.next()) {
            (Some(tg), Some(gg)) => Ok((tg, gg)),
            _ => Err(refused(RefusalKind::ModelMismatch, SET)),
        }
    }

    /// The set as the renderer holds it: `T` and `g_s` lowered by `world/1` and loaded
    /// under `acc64`, with the latent's channel count `C` and the number of action planes
    /// `A`, which is `T`'s input channel count less `C` (§13.5).
    pub struct World {
        pub(super) t: Loaded,
        pub(super) g_s: Loaded,
        pub(super) c: usize,
        pub(super) a: usize,
        pub(super) afrac: u32,
    }

    impl World {
        /// `T`'s graph, loaded.
        pub fn t(&self) -> &Loaded {
            &self.t
        }
        /// `g_s`'s graph (ending with the RGB8 step), loaded.
        pub fn g_s(&self) -> &Loaded {
            &self.g_s
        }
        /// `C`, the latent's channel count.
        pub fn channels(&self) -> usize {
            self.c
        }
        /// `A`, the action planes a row carries: `T`'s input channels less `C`.
        pub fn planes(&self) -> usize {
            self.a
        }
        /// The fixed-point scale both networks share.
        pub fn afrac(&self) -> u32 {
            self.afrac
        }

        /// A row carries one value per action plane (§13.5's load checks, `model_mismatch`).
        fn row_ok(&self, row: &[i64]) -> Result<(), Refused> {
            if row.len() != self.a {
                return Err(refused(RefusalKind::ModelMismatch, "a row does not carry one value per action plane of T"));
            }
            Ok(())
        }

        /// The elements of a latent `[C, lat, lat]`: a side of 0 is `field_range`, and a
        /// latent past [`MAX_TENSOR`] elements `too_large`.
        fn latent_len(&self, lat: usize) -> Result<usize, Refused> {
            if lat == 0 {
                return Err(refused(RefusalKind::FieldRange, "the latent's side is zero"));
            }
            let n = self.c.checked_mul(lat).and_then(|v| v.checked_mul(lat)).filter(|&n| n <= MAX_TENSOR);
            n.ok_or(refused(RefusalKind::TooLarge, "the latent exceeds 2^26 elements"))
        }

        /// The latent `z` as a tensor `[C, lat, lat]` ([`World::latent_len`]); `z` of
        /// another length is `geometry_mismatch`.
        fn latent(&self, z: &[i64], lat: usize) -> Result<Tensor, Refused> {
            if z.len() != self.latent_len(lat)? {
                return Err(refused(RefusalKind::GeometryMismatch, "the latent is not C·lat·lat values"));
            }
            // C and lat are within 2^26, so each fits u32.
            Ok(Tensor::new(self.c as u32, lat as u32, lat as u32, z.to_vec()))
        }

        /// The frame a latent `[C, lat, lat]` gives, `(channels, h, w)`, planned before
        /// any value is read (`extensions/integer-operators.md` §4): `T` planned on that
        /// shape must give it back, so that every transition reads what the one before it
        /// wrote; then `g_s` must plan on it. A network that does not (it reads another
        /// channel count, a size passes a cap, or a layer leaves no output) does not fit the
        /// latent: `model_mismatch`, as a set that does not fit a payload's shapes is.
        pub fn plan(&self, lat: usize) -> Result<(usize, usize, usize), Refused> {
            use wai_ops::plan::run_plan;
            self.latent_len(lat)?;
            let shape = [(self.c as u64, lat as u64, lat as u64)];
            let t = self.t.graph();
            let misfit = |what| move |_| refused(RefusalKind::ModelMismatch, what);
            let hw = run_plan(t, &shape, &vec![0; self.a]).map_err(misfit("T does not plan on the latent's shape"))?;
            let o = t.outputs[0] as usize;
            if (t.tensors[o].channels as u64, hw[o].0, hw[o].1) != shape[0] {
                return Err(refused(RefusalKind::ModelMismatch, "T does not give the latent's shape back"));
            }
            let g = self.g_s.graph();
            let hw = run_plan(g, &shape, &[]).map_err(misfit("g_s does not plan on the latent's shape"))?;
            let o = g.outputs[0] as usize;
            Ok((g.tensors[o].channels as usize, hw[o].0 as usize, hw[o].1 as usize))
        }

        /// `T(z)` with `row`'s values as its scalars, then the clamp to `[−2^afrac,
        /// 2^afrac]` that ends `T`'s graph. A value outside a `check` range is `field_range`.
        fn run_t(&self, z: Tensor, row: &[i64]) -> Result<Tensor, Refused> {
            let shape = (z.c, z.h, z.w);
            let out = crate::int_ops::run1(&self.t, z, row).map_err(|r| kind(r, "a latent or plane value is outside a check range of T"))?;
            if (out.c, out.h, out.w) != shape {
                return Err(refused(RefusalKind::ModelMismatch, "T does not give the latent's shape back"));
            }
            Ok(out)
        }

        /// `g_s(z)`, which ends with the RGB8 step, as row-major HWC bytes, with the
        /// frame's height and width. A value outside a `check` range is `field_range`.
        fn run_g(&self, z: Tensor) -> Result<(Vec<u8>, usize, usize), Refused> {
            let out = crate::int_ops::run1(&self.g_s, z, &[]).map_err(|r| kind(r, "a latent value is outside a check range of g_s"))?;
            let (c, h, w) = (out.c as usize, out.h as usize, out.w as usize);
            let plane = h * w;
            let mut hwc = vec![0u8; c * plane];
            for (k, &v) in out.data.iter().enumerate() {
                hwc[(k % plane) * c + k / plane] = v as u8;
            }
            Ok((hwc, h, w))
        }

        /// One transition: `z` (`[C, lat, lat]`) becomes `T(z)`, with `row`'s values, one per
        /// action plane at `2^afrac`, as `T`'s scalars (§13.5).
        pub fn step(&self, z: &[i64], row: &[i64], lat: usize) -> Result<Vec<i64>, Refused> {
            self.row_ok(row)?;
            let x = self.latent(z, lat)?;
            Ok(self.run_t(x, row)?.data)
        }

        /// [`World::step`] for a single agent's move `(dx, dy)` ([`World::move_row`]).
        pub fn step_delta(&self, z: &[i64], dx: i64, dy: i64, lat: usize) -> Result<Vec<i64>, Refused> {
            let row = self.move_row(dx, dy)?;
            self.step(z, &row, lat)
        }

        /// [`World::step_delta`] for an index into [`ACTIONS`] (past its end, the last).
        pub fn step_action(&self, z: &[i64], action: usize, lat: usize) -> Result<Vec<i64>, Refused> {
            let (dx, dy) = ACTIONS[action.min(ACTIONS.len() - 1)];
            self.step_delta(z, dx, dy, lat)
        }

        /// One frame: `g_s(z)` as row-major HWC bytes, with its height and width.
        pub fn render(&self, z: &[i64], lat: usize) -> Result<(Vec<u8>, usize, usize), Refused> {
            let x = self.latent(z, lat)?;
            self.run_g(x)
        }

        /// The row of a single agent's move `(dx, dy)` (§13.5): `dequantize(dx, afrac, 0)`,
        /// `dequantize(dy, afrac, 0)` and 0. A set whose `A` is not 3 takes no such row
        /// (`model_mismatch`), and a move whose value leaves `i64` is `field_range`.
        pub fn move_row(&self, dx: i64, dy: i64) -> Result<Vec<i64>, Refused> {
            if self.a != 3 {
                return Err(refused(RefusalKind::ModelMismatch, "a single agent's move is a row of three planes, and T takes another count"));
            }
            let q = |d: i64| wai_ops::stage::dequantize(d, self.afrac, 0).map_err(|_| refused(RefusalKind::FieldRange, "a move's plane value leaves i64"));
            Ok(vec![q(dx)?, q(dy)?, 0])
        }

        /// A clip (§13.5's driver): frame 0 is `g_s(z_0)`; for each row in order, `z`
        /// becomes `T(z)` with the row's values as the scalars, and the next frame is
        /// `g_s(z)`. Before the first frame: every row carries `A` values
        /// (`model_mismatch`), `z_0` is `[C, lat, lat]`, and both graphs plan on it
        /// ([`World::plan`]).
        pub fn decode_planes(&self, z0: &[i64], rows: &[Vec<i64>], lat: usize) -> Result<WorldClip, Refused> {
            for row in rows {
                self.row_ok(row)?;
            }
            let mut z = self.latent(z0, lat)?;
            self.plan(lat)?;
            let (mut frames, mut frame_px) = (Vec::with_capacity(rows.len() + 1), 0);
            for k in 0..=rows.len() {
                if k > 0 {
                    z = self.run_t(z, &rows[k - 1])?;
                }
                // The last frame takes the latent, which no transition reads after it.
                let x = if k == rows.len() { std::mem::replace(&mut z, Tensor::new(0, 0, 0, Vec::new())) } else { z.clone() };
                let (f, h, _) = self.run_g(x)?;
                if k == 0 {
                    frame_px = h;
                }
                frames.push(f);
            }
            Ok(WorldClip { frames, frame_px })
        }

        /// [`World::decode_planes`] for a single agent's moves, each a row
        /// ([`World::move_row`]).
        pub fn decode_deltas(&self, z0: &[i64], deltas: &[(i64, i64)], lat: usize) -> Result<WorldClip, Refused> {
            let rows = deltas.iter().map(|&(dx, dy)| self.move_row(dx, dy)).collect::<Result<Vec<_>, _>>()?;
            self.decode_planes(z0, &rows, lat)
        }
    }

    /// [`World::decode_planes`] of the set `T`, `g_s` for a latent of `c` channels, loaded
    /// first ([`load`]).
    pub fn decode_planes(t: &IntModel, g_s: &IntModel, z0: &[i64], rows: &[Vec<i64>], c: usize, lat: usize) -> Result<WorldClip, Refused> {
        load(t, g_s, c)?.decode_planes(z0, rows, lat)
    }

    /// [`World::decode_deltas`] of the set, loaded first ([`load`]).
    pub fn decode_deltas(t: &IntModel, g_s: &IntModel, z0: &[i64], deltas: &[(i64, i64)], c: usize, lat: usize) -> Result<WorldClip, Refused> {
        load(t, g_s, c)?.decode_deltas(z0, deltas, lat)
    }

    /// [`decode_deltas`] for indices into [`ACTIONS`] (past its end, the last).
    pub fn decode(t: &IntModel, g_s: &IntModel, z0: &[i64], actions: &[usize], c: usize, lat: usize) -> Result<WorldClip, Refused> {
        let deltas: Vec<(i64, i64)> = actions.iter().map(|&a| ACTIONS[a.min(ACTIONS.len() - 1)]).collect();
        decode_deltas(t, g_s, z0, &deltas, c, lat)
    }

    /// The load checks of `world/1` (§13.5, `model_mismatch`): both networks' `afrac` in
    /// `1..=30` and equal, `A ≥ 1`, and each network's rules (§13.2); then `T`, then `g_s`,
    /// lowered and loaded under `acc64` ([`wai_ops::lower::world_net_loaded`]: the result of
    /// loading the lowered graphs' bytes, without writing and parsing them again).
    pub fn load(t: &IntModel, g_s: &IntModel, c: usize) -> Result<World, Refused> {
        let (tn, gn, c32) = nets(t, g_s, c)?;
        let (tl, gl) = wai_ops::lower::world_net_loaded(tn, gn, c32, crate::int_ops::PROFILE).map_err(|r| kind(r, SET))?;
        let a = tl.graph().scalars.len();
        Ok(World { t: tl, g_s: gl, c, a, afrac: t.afrac })
    }
}
