#![cfg(feature = "ultra-tests")]
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use ftts_core::audio::WavWriter;
fn emit_skip(test: &str, reason: &str) {
eprintln!(
"receipt: {{\"test\":\"{test}\",\"outcome\":\"skipped\",\"reason\":\"{reason}\",\
\"contract\":\"Metamorphic/voice-hash-stability\",\"seam\":\"enroll.voice_pack\"}}"
);
}
fn model_path() -> Option<PathBuf> {
let mut candidates: Vec<PathBuf> = Vec::new();
if let Ok(dir) = std::env::var("FTTS_MODEL_DIR") {
candidates.push(PathBuf::from(dir));
}
#[allow(deprecated)]
let home = std::env::home_dir();
if let Some(home) = home {
candidates.push(home.join(".cache/franken_tts/model"));
}
candidates
.push(Path::new(env!("CARGO_MANIFEST_DIR")).join("../../docs/truth-pack/snapshots/hf"));
candidates.into_iter().find_map(|root| {
[
"vocab.json",
"merges.txt",
"tokenizer_config.json",
"speech_tokenizer/model.safetensors",
]
.iter()
.all(|required| root.join(required).is_file())
.then(|| {
[
root.join("qwen3-tts-12hz-0.6b-base.fttsq"),
root.join("model.safetensors"),
]
.into_iter()
.find(|candidate| candidate.is_file())
})
.flatten()
})
}
fn scratch_dir(label: &str) -> PathBuf {
let dir = std::env::temp_dir().join(format!(
"ftts-enroll-determinism-{label}-{}-{}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map_or(0, |d| d.as_nanos())
));
std::fs::create_dir_all(&dir).expect("scratch dir");
dir
}
fn write_reference_wav(path: &std::path::Path, seconds: usize, seed: u64) {
let sample_rate = ftts_core::audio::SAMPLE_RATE_HZ as usize;
let samples: Vec<f32> = (0..sample_rate * seconds)
.map(|index| {
let t = index as f32 / sample_rate as f32;
let base = (seed as f32 * 13.7) + 90.0;
let wobble = (2.0 * std::f32::consts::PI * 3.0 * t).sin() * 12.0;
let f0 = base + wobble;
let phase = 2.0 * std::f32::consts::PI * f0 * t;
let carrier = 0.35 * phase.sin()
+ 0.18 * (2.0 * phase).sin()
+ 0.09 * (3.0 * phase).sin()
+ 0.04 * ((index % 97) as f32 / 97.0 - 0.5);
let envelope = (2.0 * std::f32::consts::PI * 2.5 * t).sin().powi(2);
carrier * envelope
})
.collect();
let file = std::fs::File::create(path).expect("reference wav");
let mut writer = WavWriter::new(file, ftts_core::audio::SAMPLE_RATE_HZ).expect("wav writer");
writer.write_samples(&samples).expect("write samples");
writer.finish().expect("finish wav");
}
fn enroll(reference: &std::path::Path, output: &std::path::Path, model: &Path) {
let output = Command::new(env!("CARGO_BIN_EXE_ftts"))
.args([
"enroll",
reference.to_str().expect("utf8 reference"),
"-o",
output.to_str().expect("utf8 output"),
"--no-denoise",
"--mode",
"quick",
"--consent-attest",
"--model",
model.to_str().expect("utf8 model"),
])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.expect("ftts spawns");
assert!(
output.status.success(),
"enroll failed with {} for {}: {}",
output.status,
reference.display(),
String::from_utf8_lossy(&output.stderr)
);
}
#[test]
fn identical_reference_enrolls_byte_identical_voice_bytes() {
const TEST: &str = "identical_reference_enrolls_byte_identical_voice_bytes";
let Some(model) = model_path() else {
emit_skip(TEST, "model not present");
return;
};
let scratch = scratch_dir("same");
let reference = scratch.join("reference.wav");
write_reference_wav(&reference, 4, 11);
let first = scratch.join("first.ftvoice");
let second = scratch.join("second.ftvoice");
enroll(&reference, &first, &model);
enroll(&reference, &second, &model);
let first_bytes = std::fs::read(&first).expect("first voice pack");
let second_bytes = std::fs::read(&second).expect("second voice pack");
let first_pack = ftts_artifacts::voice::parse_voice_pack(&first_bytes)
.expect("first enrollment must be a valid voice pack");
let second_pack = ftts_artifacts::voice::parse_voice_pack(&second_bytes)
.expect("second enrollment must be a valid voice pack");
assert_eq!(
first_pack.embedding.len(),
ftts_artifacts::voice::SPEAKER_EMBEDDING_LEN,
"enrolled pack does not carry a complete speaker embedding"
);
assert_eq!(first_pack.embedding, second_pack.embedding);
assert_eq!(
first_bytes, second_bytes,
"identical reference produced DIFFERENT voice bytes — nondeterminism leaked into \
the enrollment pipeline (decode, cleanup, mel, encoder, or serialization)"
);
let other = scratch.join("other.wav");
write_reference_wav(&other, 4, 19);
let third = scratch.join("third.ftvoice");
enroll(&other, &third, &model);
let third_bytes = std::fs::read(&third).expect("third voice pack");
let third_pack = ftts_artifacts::voice::parse_voice_pack(&third_bytes)
.expect("third enrollment must be a valid voice pack");
assert_ne!(
first_pack.embedding, third_pack.embedding,
"different references produced IDENTICAL embeddings; the equality check above \
would have been vacuous"
);
eprintln!(
"receipt: {{\"test\":\"{TEST}\",\"outcome\":\"passed\",\"bytes\":{},\"note\":\
\"two-process enroll of one wav is byte-stable; distinct wav diverges\"}}",
first_bytes.len()
);
}