Skip to main content

Crate smix_error

Crate smix_error 

Source
Expand description

§smix-error

Crates.io docs.rs License

AI-readable structured failure type for iOS-Simulator automation: ExpectationFailure carries the selector that failed, the top-10 visible elements at the failure moment, Levenshtein-based “Did you mean …?” suggestions, an optional hint, and an optional device-log tail — and renders all of it via to_prompt() as a multi-line block a coding agent can paste back as a user message and act on without further context.

This crate exists because every iOS-automation library has its own flavor of assertion failed, and most of them throw away the failure context that a downstream LLM needs to fix the test. smix-error is designed so the failure object itself can be the prompt.

§Quickstart

use smix_error::{ExpectationFailure, FailureCode, FailureInit, build_suggestions};
use smix_screen::{ElementSummary, Rect, Role};

let visible_elements = vec![
    ElementSummary {
        role: Some(Role::Button), name: Some("Log in".into()),
        id: Some("btn-login".into()), text: None,
        bounds: Rect { x: 0.0, y: 0.0, w: 100.0, h: 40.0 }, enabled: true,
    },
    // ...
];

let suggestions = build_suggestions(Some("Login"), &visible_elements);

let failure = ExpectationFailure::new(FailureInit {
    code: Some(FailureCode::ElementNotFound),
    message: "element not found: { text: \"Login\" }".into(),
    visible_elements,
    suggestions,
    hint: Some(
        "matched 0 nodes in the current a11y tree; check selector or wait for the screen to settle".into(),
    ),
    ..Default::default()
});

println!("{}", failure.to_prompt());
// FAIL [ELEMENT_NOT_FOUND]: element not found: { text: "Login" }
//   suggestions:
//     - Did you mean "Log in"? (similarity 0.83, field name)
//   visible elements (top 1):
//     - button name="Log in" id="btn-login"
//   hint: matched 0 nodes in the current a11y tree; check selector or wait for the screen to settle

§Why “AI-readable” matters

When a test fails and an LLM is the test author, the failure object arrives back at the LLM as a user message. If the failure says only “ELEMENT_NOT_FOUND” the LLM has to send another tool call to fetch the screen state — costing latency, tokens, and often the user’s patience.

ExpectationFailure::to_prompt() packs all the context — selector that failed, visible elements, suggestions from edit-distance matching, optional hint, optional device-log tail — into one self-contained block. Coding agents can iterate on it immediately.

§Components

SymbolRole
FailureCode9-variant enum: ElementNotFound / NotVisible / NotEnabled / Ambiguous / Timeout / AssertionFailed / AppNotRunning / SimulatorNotBooted / DriverError
ExpectationFailureStructured failure with 8 fields, implements Display + std::error::Error
FailureInitErgonomic builder; default-derived
Falseok: false discriminator newtype (serde wire shape)
to_prompt()AI-readable rendering — caps visible elements at 10, device log at 200 lines
build_suggestions(target, visible)Top-3 “Did you mean …?” suggestions, Levenshtein-based, score > 0.5
similarity(a, b)[0, 1] normalized string similarity
edit_distance(a, b)Wagner-Fischer Levenshtein distance

§When to reach for this

Use casePick
Need a failure type that LLM agents can act on directlysmix-error
Want “Did you mean …?” suggestions from a visible-element listsmix-error
Need a fast Levenshtein distancestrsim or smix-error (free with the rest)
Generic std::error::Error for a non-automation domainuse thiserror directly

§Scope

  • ✅ Implements std::error::Error + Display (Display = to_prompt)
  • ✅ JSON wire shape: {ok: false, code, message, selector, suggestions, visibleElements, hint, screenshot, deviceLog}
  • result_large_err clippy lint workspace-allowed (the rich context is deliberate; boxing the error would defeat the AI-readable design)
  • ❌ No I/O, no async
  • ❌ No assertions / matchers (use smix-sdk for assert_visible / assert_enabled / etc.)

§License

Dual-licensed under either:

at your option. smix-error — ExpectationFailure + FailureCode + AI-readable to_prompt() + build_suggestions (stone, cold path).

build_suggestions behavior: threshold > 0.5, top 3, sort by score descending → field (name > text) → DFS index ascending.

§Why a separate stone

SDK / driver / runner-client all throw / catch ExpectationFailure. As the canonical failure type it must live in a leaf crate that everyone can depend on. Failure messages MUST be AI-readable — to_prompt() is the canonical render.

Structs§

ExpectationFailure
Structured failure thrown by SDK matchers and driver calls. Shape is AI-feed-back-ready.
FailureInit
Builder/Init form for ergonomic construction.
False
Newtype around false — used as the ExpectationFailure::ok discriminator. Serializes/deserializes as the JSON literal false.

Enums§

FailureCode
All failure codes smix surfaces back to the SDK / MCP / CLI (SCREAMING_SNAKE_CASE wire).

Functions§

build_suggestions
Generate “Did you mean …?” suggestions from the current visible element list. Contract: threshold > 0.5, top 3, score desc → field (name > text) → DFS index asc.
edit_distance
Levenshtein edit distance (Wagner-Fischer).
similarity
Normalized [0, 1] string similarity. 1 = identical, 0 = completely different.