From ca07ec339d2d922913e8a40b41558f68e53862dd Mon Sep 17 00:00:00 2001 From: CodeGhost21 <164498022+CodeGhost21@users.noreply.github.com> Date: Wed, 13 May 2026 23:22:19 +0530 Subject: [PATCH] fix(observability): skip Sentry for local-AI " binary not found" errors (OPENHUMAN-TAURI-9N) (#1669) --- src/core/observability.rs | 74 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/core/observability.rs b/src/core/observability.rs index 0f5e3c79a..521a6db9f 100644 --- a/src/core/observability.rs +++ b/src/core/observability.rs @@ -41,6 +41,7 @@ pub enum ExpectedErrorKind { ApiKeyMissing, NetworkUnreachable, TransientUpstreamHttp, + LocalAiBinaryMissing, } pub fn expected_error_kind(message: &str) -> Option { @@ -57,6 +58,9 @@ pub fn expected_error_kind(message: &str) -> Option { if is_transient_upstream_http_message(&lower) { return Some(ExpectedErrorKind::TransientUpstreamHttp); } + if lower.contains("binary not found") { + return Some(ExpectedErrorKind::LocalAiBinaryMissing); + } None } @@ -187,6 +191,21 @@ fn report_expected_message(kind: ExpectedErrorKind, message: &str, domain: &str, "[observability] {domain}.{operation} skipped transient upstream HTTP error: {message}" ); } + ExpectedErrorKind::LocalAiBinaryMissing => { + // User-state condition: piper / whisper.cpp / Ollama binary + // isn't installed on this host. The error message itself is + // the user-facing instruction ("Set PIPER_BIN or install + // piper.") — Sentry has nothing to act on, since we can't + // install the binary for them. OPENHUMAN-TAURI-9N is the + // canonical instance: `local_ai_tts` fails immediately + // (elapsed_ms=1) on a Windows host without piper installed. + tracing::info!( + domain = domain, + operation = operation, + error = %message, + "[observability] {domain}.{operation} skipped expected local-ai binary-missing error: {message}" + ); + } } } @@ -431,6 +450,61 @@ mod tests { ); } + #[test] + fn classifies_local_ai_binary_missing_errors() { + // OPENHUMAN-TAURI-9N: `local_ai_tts` returns this exact string + // from `service::speech::tts` when piper isn't on PATH or + // `PIPER_BIN` isn't set. + assert_eq!( + expected_error_kind("piper binary not found. Set PIPER_BIN or install piper."), + Some(ExpectedErrorKind::LocalAiBinaryMissing) + ); + // Sibling shapes from the same service area share the anchor and + // must classify the same way — the user-facing remediation is + // identical (install / configure the binary). + assert_eq!( + expected_error_kind( + "whisper.cpp binary not found. Set WHISPER_BIN or install whisper-cli." + ), + Some(ExpectedErrorKind::LocalAiBinaryMissing) + ); + assert_eq!( + expected_error_kind( + "Ollama binary not found at '/usr/local/bin/ollama'. Provide a valid path to the ollama executable." + ), + Some(ExpectedErrorKind::LocalAiBinaryMissing) + ); + assert_eq!( + expected_error_kind("Ollama installed but binary not found on system"), + Some(ExpectedErrorKind::LocalAiBinaryMissing) + ); + // Wrapped by the RPC dispatcher in production: + // `"rpc.invoke_method failed: piper binary not found. …"`. + // The classifier is substring-based, so caller context must not + // defeat it. + assert_eq!( + expected_error_kind( + "rpc.invoke_method failed: piper binary not found. Set PIPER_BIN or install piper." + ), + Some(ExpectedErrorKind::LocalAiBinaryMissing) + ); + } + + #[test] + fn does_not_classify_unrelated_messages_as_binary_missing() { + // Pin the anchor: messages that talk about binaries in a + // different context (download failures, version mismatches) + // must not be silenced. + assert_eq!( + expected_error_kind("piper binary failed to spawn: permission denied"), + None + ); + assert_eq!( + expected_error_kind("whisper.cpp returned empty transcript"), + None + ); + } + #[test] fn report_error_does_not_panic_with_many_tags() { let err = anyhow::anyhow!("multi-tag");