//! Built-in matchers (PRD §4.5).
//!
//! A matcher takes a `serde_json::Value` (the response from an MCP server)
//! and an `Expectation` (the YAML-authored rule) and returns an
//! [`AssertionResult`]. Matchers do not throw on assertion failure: a
//! failed assertion is a *successful* matcher run that returned
//! `pass = false`. Errors are reserved for structural problems with the
//! matcher itself (bad regex, malformed schema, etc.).
//!
//! Each matcher is in its own submodule with its own tests so the file
//! ceiling in AGENTS.md is respected.
//!
//! ## Matchers in this module
//!
//! | Matcher | Source ticket | Notes |
//! | ------- | ------------- | ----- |
//! | [`exact`]     |  | Deep equality, field order normalized. |
//! | [`schema`]    |  | JSON Schema validation, inline or by `$ref`. |
//! | [`regex`]     |  | Regex with named capture binding. |
//! | [`contains`]  |  | Object subset / array superset. |
//! | [`snapshot`]  |  | Record under `--update-snapshots`, diff otherwise. |
//! | [`llm_judge`] |  | Model-graded pass/fail verdict from an LLM provider. |
//! | [`budgets`]   | ,  | Duration and response-token budgets. |
//! | [`headers`]   |  | Response header presence and value matchers. |
//! | [`named`]     |  | `contains-all`, `contains-any`, `icontains`, `starts-with`. |
//! | [`is_json`]   |  | String parses as JSON, optional inline schema. |
//! | [`tools_call`] |  | Value is a well-formed MCP tool call. |
//! | [`levenshtein`] |  | Bounded edit distance to a reference string. |
//! | [`is_xml`]    |  | String parses as well-formed XML, optional root. |
//! | [`is_sql`]    |  | String parses as SQL against the generic dialect. |
//! | [`similar`]   |  | Embedding cosine similarity to a reference (async). |
//! | [`cel`]       |  | Deterministic CEL boolean predicate over the value. |
//!
//! The `not:` universal negation wrapper has no module here: it
//! carries an inner matcher and the executor inverts that matcher's pass/fail
//! in one code path (see `crate::executor`). A single `not:` wrapper composes
//! over every deterministic matcher, which is why we chose it over
//! promptfoo's per-type `not-<type>` prefixes.
//!
//! ## Naming reconciliation
//!
//! An earlier draft of `schemas/v1.json` listed the matchers as `equals`,
//! `contains`, `regex`, `jsonpath`, `schema`, and `length`. The shipped code
//! never grew matchers under those names; the runner has always used
//! `exact`, `contains`, `regex`, `schema`, `snapshot`, and `llm-judge`. The
//! schema was the side that drifted, so v1.0 reconciles by adopting the
//! code names. `jsonpath` and `length` are out of scope for v1.0; if they
//! come back, they will arrive through fresh tickets, not by reviving the
//! old draft.

pub mod budgets;
pub mod catalog;
pub mod cel;
pub mod citation;
pub mod citation_fetch;
pub mod contains;
pub mod exact;
pub mod headers;
pub mod is_json;
pub mod is_sql;
pub mod is_xml;
pub mod judge_criteria;
mod judge_parse;
pub mod jury_bias;
pub mod levenshtein;
pub mod llm_judge;
pub mod llm_jury;
pub mod named;
pub mod regex;
pub mod schema;
pub mod similar;
pub mod snapshot;
pub mod tools_call;

mod result;
pub use result::{AssertionDiff, AssertionResult, MatcherKind};
