open-standards/wai/wai-rs/tests/live_room.rs
Transaction Science ab23c8ab6b live rooms: AI participants are marked in their grant, and chat and reactions state their origin
live-events §4.4 and §4.5: a chat and a reaction may state an origin after their last
field (1 human, 2 machine, 3 machine-reviewed, with the model's digest for 2 and 3), as a
caption does. live-rooms §4.4: the grant attribute `ai` names the model that acts for an AI
participant; §9.2 step 6 refuses its chat, reaction or caption that does not state origin 2
or 3 with that model (`ai_unmarked`), and a relay does not forward one. Both corpora gain
vectors (additions only); both second implementations read the new fields.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-21 05:17:43 -04:00

63 lines
2.9 KiB
Rust

//! `wai.live.room` (extensions/live-rooms.md): the committed corpus
//! `live-conformance/rooms/vectors.json` regenerates byte for byte from its fixed seeds,
//! every vector in it gets the outcome it states, it refuses with every reason the
//! extension adds, and the extension's §11 lists exactly those reasons.
#![cfg(feature = "live_room")]
use std::collections::BTreeSet;
use std::path::PathBuf;
use wai::live_room::{corpus, Reason};
fn wai_dir() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..")
}
fn committed() -> String {
std::fs::read_to_string(wai_dir().join("live-conformance/rooms/vectors.json")).expect("the committed corpus")
}
#[test]
fn the_committed_corpus_regenerates_from_its_seeds() {
assert!(committed() == corpus::generate(), "live-conformance/rooms/vectors.json differs from `wai_live_room_vectors gen`");
}
#[test]
fn every_vector_gets_its_stated_outcome() {
let fails = corpus::verify(&committed());
assert!(fails.is_empty(), "{}", fails.join("\n"));
}
/// Every reason this extension adds has a vector, a proof (§10.5) or a request of `seek`
/// (§10.6) refused with it, and the corpus has the room shapes §12 names, accepted.
#[test]
fn the_corpus_covers_every_reason_and_room() {
let doc: serde_json::Value = serde_json::from_str(&committed()).unwrap();
let vectors = doc["vectors"].as_array().unwrap();
let proofs = doc["proofs"].as_array().unwrap();
let seek = doc["seek"].as_array().unwrap();
let reasons: BTreeSet<&str> = vectors.iter().chain(proofs).chain(seek).filter_map(|v| v["reason"].as_str()).collect();
for r in Reason::ALL {
assert!(reasons.contains(r.code()), "nothing in the corpus is refused with {r}");
}
for name in ["lesson", "broadcast", "takeover", "redundant_failover", "promote_viewer", "dvr", "ai_participant"] {
let v = vectors.iter().find(|v| v["name"] == name).unwrap_or_else(|| panic!("no vector {name}"));
assert_eq!(v["outcome"], "accept", "{name}");
}
let outcomes: BTreeSet<&str> = seek.iter().filter_map(|c| c["outcome"].as_str()).collect();
assert_eq!(outcomes, BTreeSet::from(["refuse", "serve"]), "seek has requests served and refused");
}
/// §11 of the extension lists exactly the codes `Reason::ALL` has, each once, in order.
#[test]
fn the_extension_lists_the_reasons() {
let text = std::fs::read_to_string(wai_dir().join("extensions/live-rooms.md")).expect("the extension");
let at = text.find("\n## 11. Reasons").expect("a §11");
let end = text[at + 1..].find("\n## ").map_or(text.len(), |e| at + 1 + e);
let listed: Vec<String> = text[at..end]
.lines()
.filter(|l| l.starts_with("| `"))
.filter_map(|l| l.split('`').nth(1).map(String::from))
.collect();
let want: Vec<String> = Reason::ALL.iter().map(|r| r.code().to_string()).collect();
assert_eq!(listed, want, "§11's table and Reason::ALL differ");
}