assay_core/errors/
mod.rs

1pub mod diagnostic;
2pub mod similarity;
3
4pub use diagnostic::Diagnostic;
5
6/// Helper to map common anyhow errors to structured Diagnostics
7pub fn try_map_error(err: &anyhow::Error) -> Option<Diagnostic> {
8    // 1) First, try to downcast if it's already a Diagnostic
9    if let Some(diag) = err.downcast_ref::<Diagnostic>() {
10        return Some(diag.clone());
11    }
12
13    let msg = err.to_string();
14
15    // Mapping embedded dimension mismatch
16    // "embedding dims mismatch" is a string we expect from runners/providers
17    // Ideally providers return typed errors, but string matching is pragmatic for v0.3.x
18    if msg.contains("embedding dims mismatch") || msg.contains("dimension mismatch") {
19        // We could try to parse "expected A, got B" if the message format is stable
20        // For now, actionable generic advice
21        return Some(
22            Diagnostic::new(
23                diagnostic::codes::E_EMB_DIMS,
24                "Embedding dimensions mismatch",
25            )
26            .with_context(serde_json::json!({ "raw_error": msg }))
27            .with_fix_step("Run: assay trace precompute-embeddings --trace <file> ...")
28            .with_fix_step(
29                "Ensure the same embedding model is used for baseline and candidate runs",
30            ),
31        );
32    }
33
34    // Baseline mismatch
35    if msg.contains("Baseline mismatch") || (msg.contains("baseline") && msg.contains("schema")) {
36        return Some(
37            Diagnostic::new(
38                diagnostic::codes::E_BASE_MISMATCH,
39                "Baseline incompatbile with current run",
40            )
41            .with_context(serde_json::json!({ "raw_error": msg }))
42            .with_fix_step("Regenerate baseline on main branch: assay ci --export-baseline ...")
43            .with_fix_step("Check that your config suite name matches the baseline suite"),
44        );
45    }
46
47    None
48}
49
50use std::fmt::{Display, Formatter};
51
52#[derive(Debug)]
53pub struct ConfigError(pub String);
54
55impl Display for ConfigError {
56    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
57        write!(f, "ConfigError: {}", self.0)
58    }
59}
60impl std::error::Error for ConfigError {}