use crate::core::RunId;
use crate::journal::{AgentIdentity, Divergence};
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct Verdict {
pub run: RunId,
pub recorded: Option<AgentIdentity>,
pub candidate: Option<AgentIdentity>,
pub finding: Finding,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum Finding {
Verified { outcome: String },
Diverged(Divergence),
OutcomeDiffers { recorded: String, replayed: String },
CannotReplay(CannotReplay),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum CannotReplay {
Erased,
KeyAbsent,
CanonicalizationChanged { recorded: u16, implemented: u16 },
EntryPointRemoved { capability: String },
NotConcluded,
EndedByAnAct { outcome: String },
}
impl Verdict {
#[must_use]
pub const fn is_verified(&self) -> bool {
matches!(self.finding, Finding::Verified { .. })
}
#[must_use]
pub const fn is_diverged(&self) -> bool {
matches!(
self.finding,
Finding::Diverged(_) | Finding::OutcomeDiffers { .. }
)
}
#[must_use]
pub fn same_revision(&self) -> bool {
match (&self.recorded, &self.candidate) {
(Some(a), Some(b)) => a.digest == b.digest,
(None, None) => true,
_ => false,
}
}
}
impl std::fmt::Display for CannotReplay {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Erased => f.write_str("erased — its payloads are sealed to a destroyed key"),
Self::KeyAbsent => f.write_str(
"key absent — its payloads are sealed and this plane holds no key ring; nothing \
is known to be erased",
),
Self::CanonicalizationChanged {
recorded,
implemented,
} => write!(
f,
"canonicalization changed — recorded under rule {recorded}, this build \
implements {implemented}"
),
Self::EntryPointRemoved { capability } => write!(
f,
"entry point removed — nothing here provides `{capability}`, which the run \
executed"
),
Self::NotConcluded => {
f.write_str("not concluded — the run has no recorded ending to verify")
}
Self::EndedByAnAct { outcome } => write!(
f,
"ended by an act — the run is `{outcome}`, which its own steps did not decide"
),
}
}
}
fn revision(f: &mut std::fmt::Formatter<'_>, who: &str, r: &AgentIdentity) -> std::fmt::Result {
writeln!(f, " {who}: {} {} {}", r.name, r.version, r.digest)
}
impl std::fmt::Display for Verdict {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let headline = match &self.finding {
Finding::Verified { outcome } if self.same_revision() => {
format!("verified — the recorded `{outcome}` ending was reproduced")
}
Finding::Verified { outcome } => format!(
"verified — no divergence on this run under a different declaration; the \
recorded `{outcome}` ending was reproduced"
),
Finding::Diverged(_) => "diverged".to_owned(),
Finding::OutcomeDiffers { recorded, replayed } => format!(
"diverged — every effect matched, and the run ended `{replayed}` where it \
recorded `{recorded}`"
),
Finding::CannotReplay(why) => format!("cannot replay: {why}"),
};
writeln!(f, "run {} — {headline}", self.run)?;
match &self.recorded {
Some(r) => revision(f, "recorded", r)?,
None => writeln!(f, " recorded: no declaration (a coded skill)")?,
}
match (&self.candidate, &self.recorded) {
(Some(c), _) => {
revision(f, "candidate", c)?;
writeln!(
f,
" ({})",
if self.same_revision() {
"same digest"
} else {
"different digest"
}
)?;
}
(None, Some(r)) => writeln!(
f,
" candidate: this plane holds no declaration named `{}`",
r.name
)?,
(None, None) => {}
}
if let Finding::Diverged(d) = &self.finding {
let kind = d.kind.as_deref().unwrap_or("an effect");
let key = |k: Option<crate::core::EffectKey>| {
k.map_or_else(|| "none".to_owned(), |k| k.to_string())
};
writeln!(
f,
" first divergence: step {}, {} phase, `{kind}` — history {}, this build {}",
d.step,
d.phase.as_str(),
key(d.recorded),
key(d.recomputed),
)?;
writeln!(f, " {}", d.detail)?;
}
Ok(())
}
}