open-standards/wai/wai-rs/tests/generate.rs
Transaction Science 22928147f3 wai: the parameter-set pin, component identity, pin-aware selection
SPEC §3.1 defines the pin a manifest carries (conditioning.prior, and a
WAI2 rendition's prior): id, sha256, determinism, and the optional form,
tier and supersedes. The digest covers the whole parameter set. A set of
several files is pinned through its listing, the new registered prior
form wai.prior.set. A sink verifies the pin before it decodes, reports a
refusal with one of an ordered set of snake_case reasons, and decodes
only from the set it verified. Tier is a closed vocabulary; supersedes is
informative.

A pin that does not resolve makes its capability unsupported for that
envelope: SPEC §4 dispatch continues at the fallback, §7.1 selection at
the next rendition, and an inert envelope's error names the reasons. A
rendition entry may carry id, sha256 and, on a companion,
companion_of_id. SPEC §7 gains a Digests subsection, and §8 says how a
MINOR revision adds an optional member.

In wai-rs: the manifest types are #[non_exhaustive] with builders; a new
pin module verifies pins in memory and on disk; Wai::dispatch_verified,
WaiMulti::pick and primary check pins and component digests; every
neural decoder reads through ParamSource; a codec-free `ffi` feature
carries the C envelope surface with wai_envelope_select and
wai_neural_decode_ex. wai-web wraps wai::container. New vectors: the
int_mlicpp set-form twin and the pin-conformance corpus with an
independent Python verifier, plus sha256.json sidecars for the vectors
of capabilities that decode against a parameter set.

Squashed from wai/stream-a-parameter-set-identity onto link 12. Conflicts
are resolved to keep both sides; the integration commits that follow
make the two streams agree.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 05:51:50 -04:00

54 lines
2.4 KiB
Rust

//! `wai.generate.spectral` — **generation-equivalence**: a deterministic integer
//! generator produces byte-identical bytes on every machine from the same
//! `(model, prompt, seed, steps)`, so its hash is portable (the create-side of
//! "conformance is a hash"). Committed vector under `tests/vectors/generate/`;
//! never skips.
#![cfg(feature = "generate")]
use std::path::PathBuf;
use wai::generate::{fnv1a, generate, SpectralModel};
#[path = "support/sha256_sidecar.rs"]
mod sha256_sidecar;
fn dir() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/vectors/generate")
}
fn jload(name: &str) -> serde_json::Value {
serde_json::from_slice(&std::fs::read(dir().join(name)).unwrap()).unwrap()
}
fn hash(rgb: &[u8]) -> String {
format!("{:016x}", fnv1a(rgb))
}
#[test]
fn generation_is_deterministic_and_pinned() {
let m = SpectralModel::from_value(&jload("generate_spectral_model.json"));
let pin = jload("generate.json");
let (prompt, seed, steps, h, w) = (
pin["prompt"].as_str().unwrap(),
pin["seed"].as_u64().unwrap(),
pin["steps"].as_u64().unwrap() as usize,
pin["h"].as_u64().unwrap() as usize,
pin["w"].as_u64().unwrap() as usize,
);
// 1. PIN: the committed (prompt, seed, steps) reproduces the committed hash,
// byte-for-byte — the portable receipt of a generated image.
let rgb = generate(&m, prompt, seed, steps, h, w);
assert_eq!(rgb.len(), h * w * 3);
let got = hash(&rgb);
println!("generate.spectral: {h}x{w} '{prompt}' seed={seed} steps={steps} -> fnv1a {got}");
assert_eq!(got, pin["rgb_hash"].as_str().unwrap(), "pinned generation must reproduce the committed hash");
sha256_sidecar::one(&dir(), "generate", "RGB8: rows top to bottom, pixels left to right, R, G, B bytes", &rgb);
// 2. DETERMINISM: regenerating the same inputs is byte-identical.
assert_eq!(generate(&m, prompt, seed, steps, h, w), rgb, "regeneration must be byte-identical");
// 3. SENSITIVITY: a different prompt or seed draws a different image (the
// generation is conditioned, not constant).
assert_ne!(hash(&generate(&m, "a different prompt", seed, steps, h, w)), got, "prompt must change the output");
assert_ne!(hash(&generate(&m, prompt, seed ^ 1, steps, h, w)), got, "seed must change the output");
assert_ne!(hash(&generate(&m, prompt, seed, steps + 1, h, w)), got, "steps must change the output");
}