open-standards/wai/wai-rs/tests/semantic_path.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

166 lines
6.2 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! The perceptual / generative-semantic path, tested WITHOUT any heavy model.
//!
//! The wire format, the conformance metric, and the verify loop are pure Rust
//! and fully exercised here with mock generator + embedder. The only part that
//! needs a real CLIP ONNX is `OnnxClip::embed`, which is covered by its own
//! (skipped-if-absent) test and not required for these.
#![cfg(feature = "semantic")]
use std::cell::Cell;
use wai::container::{Conditioning, Manifest, ModelRequirement, Wai};
use wai::semantic::{
cosine_sim, regenerate_verified, SemanticEmbedder, Frame, SemanticError, SemanticGenerator,
SemanticPackage,
};
fn pkg_from(emb: &[f32]) -> SemanticPackage {
SemanticPackage::from_embedding(emb, b"thumb-jpeg".to_vec(), b"edges-png".to_vec(), "tag")
}
fn envelope(pkg: &SemanticPackage, min_sim: Option<f32>) -> Wai {
envelope_m(pkg, min_sim, None)
}
fn envelope_m(pkg: &SemanticPackage, min_sim: Option<f32>, sim_metric: Option<String>) -> Wai {
let mut requirement = ModelRequirement::new("wai.semantic.clip");
requirement.min_sim = min_sim;
requirement.sim_metric = sim_metric;
let manifest = Manifest::new("image", "improve", requirement, Conditioning::new("semantic_package_v1"))
.with_target(serde_json::json!({"w": 8, "h": 8}));
Wai::new(manifest, pkg.pack())
}
/// A generator that returns a fixed 1×1 frame — the protocol doesn't care what
/// pixels come back, only how they score.
struct FixedGen;
impl SemanticGenerator for FixedGen {
fn regenerate(&self, _pkg: &SemanticPackage, _w: u32, _h: u32) -> Result<Frame, SemanticError> {
Ok(Frame { width: 1, height: 1, rgb: vec![0, 0, 0] })
}
}
/// An embedder that always returns a fixed embedding, regardless of the frame.
struct Echo(Vec<f32>);
impl SemanticEmbedder for Echo {
fn embed(&self, _f: &Frame) -> Result<Vec<f32>, SemanticError> {
Ok(self.0.clone())
}
}
#[test]
fn package_round_trips_byte_faithfully() {
let pkg = pkg_from(&[1.0, 0.0, 0.0, 0.0]);
let bytes = pkg.pack();
let back = SemanticPackage::unpack(&bytes).expect("unpack");
assert_eq!(pkg, back, "semantic package must survive pack/unpack");
assert_eq!(back.thumb_jpeg, b"thumb-jpeg");
assert_eq!(back.edges_png, b"edges-png");
assert_eq!(back.tag, "tag");
// The quantized clip vector dequantizes to the original direction.
assert!(cosine_sim(&back.clip(), &[1.0, 0.0, 0.0, 0.0]) > 0.999);
}
#[test]
fn unpack_rejects_truncation_without_panic() {
assert!(SemanticPackage::unpack(&[]).is_err());
// length prefix says 5 bytes, only 2 follow
assert!(SemanticPackage::unpack(&[5, 0, 0, 0, 1, 2]).is_err());
}
#[test]
fn clip_sim_is_a_cosine() {
assert!((cosine_sim(&[1.0, 0.0], &[1.0, 0.0]) - 1.0).abs() < 1e-6); // identical
assert!(cosine_sim(&[1.0, 0.0], &[0.0, 1.0]).abs() < 1e-6); // orthogonal
assert!((cosine_sim(&[1.0, 0.0], &[-1.0, 0.0]) + 1.0).abs() < 1e-6); // opposite
// Scale-invariant: magnitude doesn't matter, direction does.
assert!((cosine_sim(&[3.0, 0.0], &[9.0, 0.0]) - 1.0).abs() < 1e-6);
}
#[test]
fn conformance_passes_when_similar() {
let pkg = pkg_from(&[1.0, 0.0, 0.0, 0.0]);
let env = envelope(&pkg, Some(0.9));
let res = regenerate_verified(&env, &FixedGen, &Echo(vec![1.0, 0.0, 0.0, 0.0]), 8, 8, 1)
.expect("verify");
assert!(res.conformed, "sim {} should clear 0.9", res.similarity);
assert!(res.similarity > 0.99);
}
#[test]
fn conformance_fails_when_dissimilar() {
let pkg = pkg_from(&[1.0, 0.0, 0.0, 0.0]);
let env = envelope(&pkg, Some(0.5));
// Embedder returns an orthogonal vector → similarity ~0, below threshold.
let res = regenerate_verified(&env, &FixedGen, &Echo(vec![0.0, 1.0, 0.0, 0.0]), 8, 8, 1)
.expect("verify");
assert!(!res.conformed, "orthogonal output must not conform (sim {})", res.similarity);
}
/// An embedder whose output ramps from orthogonal toward the target across
/// calls, so best-of-K should strictly beat a single attempt.
struct RampEmbedder {
target: Vec<f32>,
ortho: Vec<f32>,
calls: Cell<usize>,
total: usize,
}
impl SemanticEmbedder for RampEmbedder {
fn embed(&self, _f: &Frame) -> Result<Vec<f32>, SemanticError> {
let i = self.calls.get();
self.calls.set(i + 1);
let t = (i as f32 + 1.0) / self.total as f32; // 1/total .. 1.0
let v = self
.target
.iter()
.zip(&self.ortho)
.map(|(a, b)| t * a + (1.0 - t) * b)
.collect();
Ok(v)
}
}
#[test]
fn best_of_k_beats_single_attempt() {
let pkg = pkg_from(&[1.0, 0.0, 0.0, 0.0]);
let env = envelope(&pkg, Some(0.0));
let single = regenerate_verified(
&env, &FixedGen,
&RampEmbedder { target: vec![1.0, 0.0, 0.0, 0.0], ortho: vec![0.0, 1.0, 0.0, 0.0],
calls: Cell::new(0), total: 4 },
8, 8, 1,
).unwrap();
let best = regenerate_verified(
&env, &FixedGen,
&RampEmbedder { target: vec![1.0, 0.0, 0.0, 0.0], ortho: vec![0.0, 1.0, 0.0, 0.0],
calls: Cell::new(0), total: 4 },
8, 8, 4,
).unwrap();
assert!(best.similarity > single.similarity,
"best-of-4 ({}) should beat best-of-1 ({})", best.similarity, single.similarity);
assert!(best.similarity > 0.999, "last ramp step reaches the target");
}
#[test]
fn sim_metric_is_named_and_carried_through() {
let pkg = pkg_from(&[1.0, 0.0, 0.0, 0.0]);
let target = vec![1.0, 0.0, 0.0, 0.0];
// Unset metric → "clip" by convention, and that shows up in the result.
let def = envelope(&pkg, Some(0.0));
assert_eq!(def.sim_metric(), "clip");
let r = regenerate_verified(&def, &FixedGen, &Echo(target.clone()), 8, 8, 1).unwrap();
assert_eq!(r.metric, "clip");
// A declared metric (e.g. DreamSim space) is named and carried through —
// the sink must score with a matching embedder for the result to mean
// anything; the protocol just records which space was used.
let ds = envelope_m(&pkg, Some(0.0), Some("dreamsim".into()));
assert_eq!(ds.sim_metric(), "dreamsim");
let r2 = regenerate_verified(&ds, &FixedGen, &Echo(target), 8, 8, 1).unwrap();
assert_eq!(r2.metric, "dreamsim");
}