use amberfork_align::{DiffParams, LexicalCost, diff};
use amberfork_model::Run;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum RunVerdict {
Recovered,
NotRecovered,
Inconclusive,
}
pub(crate) fn classify_recovery(
good: &Run,
reexecuted: &Run,
origin: usize,
params: &DiffParams,
) -> RunVerdict {
if reexecuted.steps.len() <= origin {
return RunVerdict::Inconclusive;
}
let Ok(result) = diff(good, reexecuted, &LexicalCost, params) else {
return RunVerdict::Inconclusive;
};
if result.fork.is_some() {
RunVerdict::NotRecovered
} else {
RunVerdict::Recovered
}
}
#[cfg(test)]
mod tests {
use super::*;
use amberfork_model::{Run, test_support};
fn run(id: &str, steps: &[(&str, &str)]) -> Run {
let steps = steps
.iter()
.enumerate()
.map(|(idx, (name, out))| test_support::step(idx, *name).text_output(*out).build())
.collect();
test_support::run(id, steps).build()
}
#[test]
fn a_rerun_that_converges_with_good_is_recovered() {
let good = run("good", &[("plan", "p"), ("search", "s"), ("answer", "a")]);
let reexecuted = run("reexec", &[("plan", "p"), ("search", "s"), ("answer", "a")]);
assert_eq!(
classify_recovery(&good, &reexecuted, 1, &DiffParams::default()),
RunVerdict::Recovered
);
}
#[test]
fn a_rerun_that_still_diverges_after_the_patch_is_not_recovered() {
let good = run(
"good",
&[
("plan", "p"),
("search", "s"),
("read", "r"),
("answer", "a"),
],
);
let reexecuted = run(
"reexec",
&[
("plan", "p"),
("search", "s"),
("flail", "x"),
("flail-again", "y"),
],
);
assert_eq!(
classify_recovery(&good, &reexecuted, 1, &DiffParams::default()),
RunVerdict::NotRecovered
);
}
#[test]
fn a_rerun_too_short_to_reach_the_patch_is_inconclusive() {
let good = run("good", &[("plan", "p"), ("search", "s"), ("read", "r")]);
let reexecuted = run("reexec", &[("plan", "p"), ("search", "s")]);
assert_eq!(
classify_recovery(&good, &reexecuted, 2, &DiffParams::default()),
RunVerdict::Inconclusive
);
}
#[test]
fn an_empty_rerun_is_inconclusive() {
let good = run("good", &[("plan", "p"), ("answer", "a")]);
let reexecuted = run("reexec", &[]);
assert_eq!(
classify_recovery(&good, &reexecuted, 0, &DiffParams::default()),
RunVerdict::Inconclusive
);
}
}