wafrift_wafmodel/error.rs
1//! Error type for the WAF-decompilation engine.
2
3/// Anything that can go wrong while decompiling, mining, or hardening.
4#[derive(Debug, thiserror::Error)]
5pub enum WafModelError {
6 /// The oracle could not be queried (transport, timeout, etc.).
7 #[error("oracle query failed: {0}")]
8 Oracle(String),
9
10 /// The learner exhausted its membership-query budget before the
11 /// hypothesis stabilized. Carries the budget that was spent so the
12 /// caller can decide to raise it rather than trust a partial model.
13 #[error("learning budget exhausted after {queries} membership queries (hypothesis unstable)")]
14 BudgetExhausted {
15 /// Membership queries spent before giving up.
16 queries: u64,
17 },
18
19 /// A learned-model artifact failed to (de)serialize or its schema
20 /// version is not understood by this build.
21 #[error("model artifact error: {0}")]
22 Artifact(String),
23
24 /// A regex shipped in a Tier-B ruleset failed to compile.
25 #[error("Tier-B rule {rule} has an invalid pattern: {source}")]
26 BadRule {
27 /// The offending rule id.
28 rule: String,
29 /// The underlying regex compile error.
30 #[source]
31 source: regex::Error,
32 },
33
34 /// The equivalence oracle's UCB bandit was asked to draw a
35 /// counterexample word but the search space was empty — the
36 /// hypothesis has zero states, or the alphabet has zero symbols.
37 /// Neither is a valid input; the caller must supply a non-trivial
38 /// automaton and a non-empty alphabet.
39 #[error(
40 "UCB bandit equivalence oracle: search space is empty \
41 (state cover is empty or alphabet has zero symbols). \
42 Supply a non-trivial hypothesis and a non-empty alphabet."
43 )]
44 EmptySearchSpace,
45
46 /// The L\* observation table was found to be non-closed while
47 /// building a hypothesis. Pre-R51 this surfaced as a panic (the
48 /// `.expect("table closed ⇒ …")` call sites in build_hypothesis).
49 /// A WAF that returns non-deterministic oracle answers (load-
50 /// balanced cluster with inconsistent rule sets, mid-scan rule
51 /// reload, etc.) can push two identical prefixes to different
52 /// rows and trip this invariant. R51 pass-13 I3 (CLAUDE.md §15).
53 #[error(
54 "L* observation table is not closed at hypothesis-build time \
55 — likely caused by a non-deterministic oracle (WAF cluster, \
56 mid-scan rule reload). Retry with a stable target or raise \
57 the query budget."
58 )]
59 TableNotClosed,
60}
61
62/// Convenience alias used throughout the crate.
63pub type Result<T> = std::result::Result<T, WafModelError>;