//! Explicit real local speech proof; excluded from ordinary structural checks. use anyhow::{ensure, Context, Result}; use searchi_speech::{Device, SpeechWorker, MAX_SAMPLES}; use std::{ fs, path::{Path, PathBuf}, time::{SystemTime, UNIX_EPOCH}, }; fn required(name: &str) -> Result { std::env::var_os(name) .map(PathBuf::from) .with_context(|| format!("Set {name} for actual CPU speech proof")) } struct OwnedFixture(PathBuf); impl Drop for OwnedFixture { fn drop(&mut self) { let _ = fs::remove_dir_all(&self.0); } } fn link_or_copy(source: &Path, target: &Path) -> Result<()> { if fs::hard_link(source, target).is_err() { fs::copy(source, target)?; } Ok(()) } #[test] #[ignore = "Requires actual pinned native worker/models and a verified speech PCM fixture; CPU only"] fn actual_speech_reuses_contexts_and_supports_unicode_runtime_and_model_paths() -> Result<()> { let worker = required("SEARCHI_TEST_SPEECH_WORKER")?; let base = required("SEARCHI_TEST_SPEECH_BASE")?; let vad = required("SEARCHI_TEST_SPEECH_VAD")?; let pcm_file = required("SEARCHI_TEST_SPEECH_PCM")?; ensure!( fs::metadata(&pcm_file)?.len() <= MAX_SAMPLES as u64 * 4, "Proof PCM exceeds limit" ); let bytes = fs::read(pcm_file)?; ensure!( !bytes.is_empty() && bytes.len() % 4 == 0, "Invalid proof PCM bytes" ); let pcm: Vec = bytes .as_chunks::<4>() .0 .iter() .map(|b| f32::from_le_bytes(*b)) .collect(); let unique = SystemTime::now().duration_since(UNIX_EPOCH)?.as_nanos(); let fixture = OwnedFixture(std::env::temp_dir().join(format!( "searchi-sprachtest-München-測試-🚀-{}-{unique}", std::process::id() ))); fs::create_dir(&fixture.0)?; let runtime = fixture.0.join("Laufzeit-測試-🚀"); fs::create_dir(&runtime)?; let inventory = worker .parent() .context("Worker directory missing")? .join("runtime-manifest.json"); let manifest: serde_json::Value = serde_json::from_slice(&fs::read(&inventory)?)?; for record in manifest["files"] .as_array() .context("Missing runtime files")? { let name = record["path"].as_str().context("Invalid inventory name")?; ensure!( !name.contains(['/', '\\', ':']) && name != "..", "Unsafe fixture artifact name" ); fs::copy(worker.parent().unwrap().join(name), runtime.join(name))?; } fs::copy(inventory, runtime.join("runtime-manifest.json"))?; let unicode_base = fixture.0.join("Modell-München-測試-🚀.bin"); let unicode_vad = fixture.0.join("Sprache-測試-🚀.bin"); link_or_copy(&base, &unicode_base)?; link_or_copy(&vad, &unicode_vad)?; ensure!( std::env::var("SEARCHI_FORCE_CPU").ok().as_deref() == Some("1"), "Actual VM inference proof requires forced CPU" ); let mut client = SpeechWorker::load( &runtime.join(worker.file_name().unwrap()), &unicode_base, &unicode_vad, Device::Auto, )?; let first = client.transcribe(&pcm, 16000)?; ensure!( !first.passages.is_empty(), "Actual speech fixture produced no passages" ); let second = client.transcribe(&pcm, 16000)?; ensure!( first.passages == second.passages, "Warm speech result differs" ); ensure!( second.metrics.load_ms == 0.0, "Persistent contexts unexpectedly reloaded" ); for passage in first.passages { ensure!( passage.start_ms <= passage.end_ms && passage.end_ms as usize <= pcm.len() / 16, "Native passage outside source window" ); } println!( "actual CPU speech: first={:?}; warm={:?}", first.metrics, second.metrics ); Ok(()) }