1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use sim_kernel::{Expr, Symbol};
use sim_value::build::entry;
/// ASK failure data that can be fed back to a model as repair context.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AskFailure {
/// The returned content could not be decoded by the declared codec.
Decode {
/// Declared return codec.
codec: Symbol,
/// Decode diagnostic.
message: String,
},
/// The decoded value failed the declared return Shape.
Shape {
/// Expected shape descriptor.
expected: String,
/// Shape diagnostics.
diagnostics: Vec<String>,
},
}
impl AskFailure {
/// Projects this failure into data suitable for fenced repair context.
pub fn to_expr(&self) -> Expr {
match self {
Self::Decode { codec, message } => Expr::Map(vec![
entry(
"kind",
Expr::Symbol(Symbol::qualified("bridge", "DecodeFailure")),
),
entry("codec", Expr::Symbol(codec.clone())),
entry("message", Expr::String(message.clone())),
]),
Self::Shape {
expected,
diagnostics,
} => Expr::Map(vec![
entry(
"kind",
Expr::Symbol(Symbol::qualified("bridge", "ShapeFailure")),
),
entry("expected", Expr::String(expected.clone())),
entry(
"diagnostics",
Expr::Vector(diagnostics.iter().cloned().map(Expr::String).collect()),
),
]),
}
}
pub(crate) fn message(&self) -> String {
match self {
Self::Decode { codec, message } => {
format!("decode with {codec} failed: {message}")
}
Self::Shape {
expected,
diagnostics,
} => {
let actual = if diagnostics.is_empty() {
"no diagnostics".to_owned()
} else {
diagnostics.join("; ")
};
format!("shape {expected} rejected answer: {actual}")
}
}
}
}
/// Bounded ASK repair policy.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RepairPolicy {
/// Maximum retry count. Values above 2 are clamped.
pub max_retries: u8,
}
impl RepairPolicy {
/// Builds a repair policy, clamping retries to the BRIDGE maximum.
pub fn new(max_retries: u8) -> Self {
Self {
max_retries: max_retries.min(2),
}
}
pub(crate) fn retries(self) -> u8 {
self.max_retries.min(2)
}
}
impl Default for RepairPolicy {
fn default() -> Self {
Self::new(1)
}
}