Some checks failed
joule-moq-web browser client / joule-moq-web · does this change touch it (push) Successful in 8m12s
WAI operation catalogue / does this change touch it (push) Successful in 8m3s
wai-app and Create / wai-app · does this change touch it (push) Successful in 8m7s
joule-moq-room room service / joule-moq-room · does this change touch it (push) Successful in 8m21s
joule-moq-remote host agent / joule-moq-remote · does this change touch it (push) Successful in 8m24s
wai-audit collector and player integration / does this change touch it (push) Successful in 8m6s
wai-key-proxy / does this change touch it (push) Successful in 7m59s
wai-fleet service / does this change touch it (push) Successful in 8m2s
wai-quantum studio and desktop / does this change touch it (push) Successful in 1m40s
wai-ledger service / does this change touch it (push) Successful in 1m42s
wai-quantum for JavaScript / does this change touch it (push) Successful in 1m43s
wai-sink-android native sink library / does this change touch it (push) Successful in 1m41s
WAI Studio / does this change touch it (push) Successful in 1m40s
wai-sink-swift native sink package / does this change touch it (push) Successful in 1m41s
joule-moq-remote host agent / joule-moq-remote, every target (macos) (push) Successful in 46s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 1m40s
wai-fleet service / service · macos (push) Successful in 47s
wai-app and Create / wai-app · Create, browser end-to-end (macos) (push) Successful in 5m44s
wai-ledger service / service · macos (push) Successful in 50s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 4m37s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Has been cancelled
wai-app and Create / wai-app · tests, clippy, the line language's verifier (linux) (push) Has been cancelled
wai-fleet service / service · linux (push) Has been cancelled
joule-moq-web browser client / joule-moq-web · browser end-to-end (macos) (push) Has been cancelled
wai-ledger service / service · linux (push) Has been cancelled
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Has been cancelled
WAI Studio / Studio in WebKit · linux (push) Has been cancelled
WAI Studio / Studio in Chromium and Firefox · macos (push) Has been cancelled
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 7m9s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 10m50s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 10m5s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 8s
wai-quantum energy-landscape jobs / does this change touch it (push) Successful in 8s
wai-audit collector and player integration / collector · linux (push) Successful in 1m50s
wai-key-proxy / proxy · linux (push) Successful in 1m37s
wai-quantum energy-landscape jobs / the same bits · macos (push) Successful in 3m28s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 9m6s
wai-quantum studio and desktop / studio · browser (push) Successful in 7m10s
wai-quantum for JavaScript / javascript · linux (push) Successful in 6m42s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 9m10s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 2m38s
wai-quantum energy-landscape jobs / the module under wasm32-wasip2 (wasmtime) (push) Successful in 2m38s
wai-quantum energy-landscape jobs / native against WebAssembly, over many seeds (push) Successful in 5m0s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 7m33s
wai-quantum energy-landscape jobs / reader, kernels, answers and the stated result · linux, release (push) Successful in 17m45s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (push) Successful in 1m42s
joule-moq-room room service / joule-moq-room, every target (push) Successful in 4m49s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 4m25s
wai-quantum energy-landscape jobs / the same bits · linux-arm64 (push) Successful in 7m38s
synthesis §7.10 registers the second marking layer for speech and other audio: the same 8-byte payload and BCH code as tent64, the same marking and detection records and failure codes (audio states rate, channels and length), embedded by a pinned integer derivation in the band energies of the mono mix and read key-free after trims, rate and level changes and the codecs §7.10.7 measures. robustness-evidence registers audio corpora, ten pinned transforms of sound and the lossy codecs as measured transforms, whose records are stated. Reference in wai-rs (synthesis::mark::audio, audio_mark, robustness::audio, wai_audio_mark_vectors), second implementation in _wai_audio_mark.py with audio_mark_verify.py, corpus in live-conformance/audio-mark/ with records measured on generated voices and music and on recorded speech named by digest. Co-Authored-By: Claude Opus 5.5 <[email protected]>
152 lines
6.5 KiB
Rust
152 lines
6.5 KiB
Rust
//! The audio scheme of the second marking layer, `wai-mark:band64` (extensions/synthesis.md
|
||
//! §7.10), and its corpus `live-conformance/audio-mark/`: every generated file regenerates byte
|
||
//! for byte and no other file but the measured records is there; every embedding, detection,
|
||
//! case and record gets what it states; §7.10.1's definition, §7.10.3's shuffle and §7.10.6's
|
||
//! bound are the reference's; and §7.10.7's tables are the measurements' and its claims attacks
|
||
//! every measurement shows survived.
|
||
|
||
use serde_json::Value;
|
||
use std::collections::BTreeMap;
|
||
use std::path::PathBuf;
|
||
use wai::audio_mark::corpus;
|
||
use wai::synthesis::mark::audio as band;
|
||
|
||
fn wai_dir() -> PathBuf {
|
||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..")
|
||
}
|
||
|
||
fn tree(root: &PathBuf) -> BTreeMap<String, Vec<u8>> {
|
||
let mut out = BTreeMap::new();
|
||
let mut stack = vec![root.clone()];
|
||
while let Some(d) = stack.pop() {
|
||
for e in std::fs::read_dir(&d).expect("the corpus directory") {
|
||
let p = e.expect("an entry").path();
|
||
if p.is_dir() {
|
||
stack.push(p);
|
||
continue;
|
||
}
|
||
let rel = p.strip_prefix(root).expect("under the root").to_string_lossy().replace('\\', "/");
|
||
if rel != "README.md" {
|
||
out.insert(rel, std::fs::read(&p).expect("a file"));
|
||
}
|
||
}
|
||
}
|
||
out
|
||
}
|
||
|
||
fn committed() -> BTreeMap<String, Vec<u8>> {
|
||
tree(&wai_dir().join("live-conformance/audio-mark"))
|
||
}
|
||
|
||
fn section(text: &str, head: &str) -> String {
|
||
let at = text.find(&format!("\n{head}")).unwrap_or_else(|| panic!("a section {head}"));
|
||
let level = head.chars().take_while(|c| *c == '#').count();
|
||
let end = text[at + 1..]
|
||
.match_indices("\n#")
|
||
.find(|(i, _)| text[at + 1 + i + 1..].chars().take_while(|c| *c == '#').count() <= level)
|
||
.map_or(text.len(), |(i, _)| at + 1 + i);
|
||
text[at..end].to_string()
|
||
}
|
||
|
||
fn fold(s: &str) -> String {
|
||
s.split_whitespace().collect::<Vec<_>>().join(" ")
|
||
}
|
||
|
||
fn synthesis() -> String {
|
||
std::fs::read_to_string(wai_dir().join("extensions/synthesis.md")).expect("synthesis.md")
|
||
}
|
||
|
||
#[test]
|
||
fn the_committed_corpus_regenerates_from_its_seeds() {
|
||
let generated: BTreeMap<String, Vec<u8>> = corpus::generate().into_iter().collect();
|
||
let files = committed();
|
||
for k in generated.keys() {
|
||
assert!(files.get(k) == generated.get(k), "{k} differs from its regeneration, or is missing");
|
||
}
|
||
for k in files.keys() {
|
||
assert!(generated.contains_key(k) || k.starts_with("robustness/measured/"), "{k} is not generated");
|
||
}
|
||
}
|
||
|
||
#[test]
|
||
fn every_vector_case_and_record_gets_what_it_states() {
|
||
let fails = corpus::verify(&committed());
|
||
assert!(fails.is_empty(), "{fails:#?}");
|
||
}
|
||
|
||
#[test]
|
||
fn the_extension_states_the_references_definition_shuffle_and_bound() {
|
||
let s = synthesis();
|
||
let def = section(&s, "#### 7.10.1 ");
|
||
let block = def.split("```").nth(1).expect("the definition's block");
|
||
let joined: String = block.lines().map(str::trim).collect();
|
||
assert_eq!(joined, band::definition_text(), "§7.10.1's definition is the reference's");
|
||
let digest: String = band::digest().iter().map(|b| format!("{b:02x}")).collect();
|
||
assert!(fold(&def).contains(&format!("its digest is `{digest}`")), "§7.10.1 states the digest");
|
||
let lay = band::layout();
|
||
let head = format!("π begins {}, {}, {}, {}", lay.perm[0], lay.perm[1], lay.perm[2], lay.perm[3]);
|
||
assert!(fold(§ion(&s, "#### 7.10.3 ")).contains(&head), "§7.10.3 states the shuffle's first entries");
|
||
let bound = corpus::false_positive_log2(corpus::ATTEMPTS);
|
||
assert!(fold(§ion(&s, "#### 7.10.6 ")).contains(&format!("2^−{}", bound.trim_start_matches('-'))), "§7.10.6 states {bound}");
|
||
}
|
||
|
||
/// §7.10.7's tables, by their first data column's header: attack → column → cell.
|
||
fn tables(s: &str) -> BTreeMap<String, BTreeMap<String, BTreeMap<String, String>>> {
|
||
let mut out: BTreeMap<String, BTreeMap<String, BTreeMap<String, String>>> = BTreeMap::new();
|
||
let mut head: Option<Vec<String>> = None;
|
||
for line in s.lines() {
|
||
let cells: Vec<String> = line.trim().trim_matches('|').split('|').map(|c| c.trim().trim_matches('`').to_string()).collect();
|
||
if line.starts_with("| attack") {
|
||
out.entry(cells[1].clone()).or_default();
|
||
head = Some(cells);
|
||
} else if let (Some(h), true) = (&head, line.starts_with("| `")) {
|
||
let row: BTreeMap<String, String> = h[1..].iter().cloned().zip(cells[1..].iter().cloned()).collect();
|
||
out.get_mut(&h[1]).expect("a table").insert(cells[0].clone(), row);
|
||
} else if !line.starts_with('|') {
|
||
head = None;
|
||
}
|
||
}
|
||
out
|
||
}
|
||
|
||
#[test]
|
||
fn the_tables_are_the_measurements_and_the_claims_were_survived() {
|
||
let files = committed();
|
||
let mut rows: BTreeMap<(String, String), Value> = BTreeMap::new();
|
||
let mut add = |b: &[u8]| {
|
||
let v: Value = serde_json::from_slice(b).expect("a measurement");
|
||
for r in v["table"].as_array().expect("a table") {
|
||
rows.insert((r["attack"].as_str().unwrap_or("").into(), r["set"].as_str().unwrap_or("").into()), r.clone());
|
||
}
|
||
};
|
||
add(&files["battery-band64.json"]);
|
||
for (k, b) in &files {
|
||
if k.starts_with("robustness/measured/measurement-") {
|
||
add(b);
|
||
}
|
||
}
|
||
let text = section(&synthesis(), "#### 7.10.7 ");
|
||
let t = tables(&text);
|
||
assert!(t.contains_key("voice"), "§7.10.7 has the pinned attacks' table");
|
||
for table in t.values() {
|
||
for (attack, cells) in table {
|
||
for (col, cell) in cells {
|
||
let r = rows.get(&(attack.clone(), col.clone())).unwrap_or_else(|| panic!("no measurement of {attack} on {col}"));
|
||
let mut want = format!("{} / {}", r["survived"], r["items"]);
|
||
if r["survived"].as_u64() != Some(0) {
|
||
want += &format!(" ({})", r["errors_max"]);
|
||
}
|
||
assert_eq!(cell, &want, "§7.10.7 {attack}, {col}");
|
||
}
|
||
}
|
||
}
|
||
let f = fold(&text);
|
||
let claims = f.split("**claims to survive** ").nth(1).and_then(|x| x.split('.').next()).expect("§7.10.7's claims");
|
||
for a in claims.split('`').skip(1).step_by(2) {
|
||
let sets: Vec<&Value> = rows.iter().filter(|((at, _), _)| at == a).map(|(_, r)| r).collect();
|
||
assert!(!sets.is_empty(), "{a} is measured");
|
||
for r in sets {
|
||
assert!(r["survived"] == r["items"] && r["false_positives"] == 0, "§7.10.7 claims {a}, which {} did not survive", r["set"]);
|
||
}
|
||
}
|
||
}
|