use crate::contract::recovery::{QuarantineRecord, RecoveryClassification};
use crate::sim::{fold, seed_from_env, Prng, FNV_OFFSET};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum CrashBoundary {
PlanSealed,
EffectInFlight,
ArtifactCommittedPreReport,
ReportWrittenPreFsync,
}
impl CrashBoundary {
fn token(self) -> u64 {
match self {
CrashBoundary::PlanSealed => 0xB0_01,
CrashBoundary::EffectInFlight => 0xB0_02,
CrashBoundary::ArtifactCommittedPreReport => 0xB0_03,
CrashBoundary::ReportWrittenPreFsync => 0xB0_04,
}
}
fn label(self) -> &'static str {
match self {
CrashBoundary::PlanSealed => "plan-sealed",
CrashBoundary::EffectInFlight => "effect-in-flight",
CrashBoundary::ArtifactCommittedPreReport => "artifact-committed-pre-report",
CrashBoundary::ReportWrittenPreFsync => "report-written-pre-fsync",
}
}
}
#[must_use]
pub fn all_crash_boundaries() -> Vec<CrashBoundary> {
vec![
CrashBoundary::PlanSealed,
CrashBoundary::EffectInFlight,
CrashBoundary::ArtifactCommittedPreReport,
CrashBoundary::ReportWrittenPreFsync,
]
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum ReconClass {
Completed,
RolledBack,
CanonicalRefusal,
}
impl From<RecoveryClassification> for ReconClass {
fn from(c: RecoveryClassification) -> Self {
match c {
RecoveryClassification::Completed => ReconClass::Completed,
RecoveryClassification::RolledBack => ReconClass::RolledBack,
RecoveryClassification::CanonicalRefusal => ReconClass::CanonicalRefusal,
}
}
}
impl ReconClass {
fn token(self) -> u64 {
match self {
ReconClass::Completed => 0xC0_01,
ReconClass::RolledBack => 0xC0_02,
ReconClass::CanonicalRefusal => 0xC0_03,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ReconViolation {
LostCommittedArtifact {
boundary: &'static str,
},
UndeadBoundary {
boundary: &'static str,
},
LiveOrphanAfterRollback {
boundary: &'static str,
orphan: String,
},
NonCanonicalReopen {
boundary: &'static str,
detail: String,
},
}
impl std::fmt::Display for ReconViolation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::LostCommittedArtifact { boundary } => write!(
f,
"lost committed artifact at crash boundary `{boundary}` (sacred-window violation)"
),
Self::UndeadBoundary { boundary } => write!(
f,
"undead boundary at `{boundary}`: classified Completed with no sealed report"
),
Self::LiveOrphanAfterRollback { boundary, orphan } => write!(
f,
"live orphan `{orphan}` survived rollback at crash boundary `{boundary}`"
),
Self::NonCanonicalReopen { boundary, detail } => {
write!(f, "non-canonical reopen at `{boundary}`: {detail}")
}
}
}
}
#[derive(Clone, Debug)]
struct CrashState {
plan_sealed: bool,
artifact_committed: bool,
report_sealed: bool,
report_torn: bool,
orphans: Vec<QuarantineRecord>,
}
fn crash_state(boundary: CrashBoundary, prng: &mut Prng) -> CrashState {
let orphan_id = prng.next_u64() % 0x1_0000;
let orphans = vec![QuarantineRecord {
kind: "process".to_string(),
reference: format!("pid:{orphan_id}"),
}];
match boundary {
CrashBoundary::PlanSealed => CrashState {
plan_sealed: true,
artifact_committed: false,
report_sealed: false,
report_torn: false,
orphans,
},
CrashBoundary::EffectInFlight => CrashState {
plan_sealed: true,
artifact_committed: false,
report_sealed: false,
report_torn: false,
orphans,
},
CrashBoundary::ArtifactCommittedPreReport => CrashState {
plan_sealed: true,
artifact_committed: true,
report_sealed: false,
report_torn: false,
orphans,
},
CrashBoundary::ReportWrittenPreFsync => CrashState {
plan_sealed: true,
artifact_committed: false,
report_sealed: false,
report_torn: true,
orphans,
},
}
}
struct Reconciled {
class: RecoveryClassification,
swept: Vec<QuarantineRecord>,
remaining: Vec<QuarantineRecord>,
}
fn reconcile(state: &CrashState) -> Reconciled {
if !state.plan_sealed {
return Reconciled {
class: RecoveryClassification::RolledBack,
swept: Vec::new(),
remaining: Vec::new(),
};
}
if state.report_sealed && !state.report_torn {
return Reconciled {
class: RecoveryClassification::Completed,
swept: Vec::new(),
remaining: Vec::new(),
};
}
if state.report_torn || state.artifact_committed {
return Reconciled {
class: RecoveryClassification::CanonicalRefusal,
swept: Vec::new(),
remaining: Vec::new(),
};
}
Reconciled {
class: RecoveryClassification::RolledBack,
swept: state.orphans.clone(),
remaining: Vec::new(),
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ReconCell {
pub boundary: String,
pub class: ReconClass,
pub digest: u64,
pub swept: usize,
}
pub fn run_cell(seed: u64, boundary: CrashBoundary) -> Result<ReconCell, ReconViolation> {
let mut prng = Prng::new(fold(fold(FNV_OFFSET, seed), boundary.token()));
let state = crash_state(boundary, &mut prng);
let outcome = reconcile(&state);
let class: ReconClass = outcome.class.into();
if state.artifact_committed && matches!(class, ReconClass::RolledBack | ReconClass::Completed) {
return Err(ReconViolation::LostCommittedArtifact {
boundary: boundary.label(),
});
}
if matches!(class, ReconClass::Completed)
&& !(state.plan_sealed && state.report_sealed && !state.report_torn)
{
return Err(ReconViolation::UndeadBoundary {
boundary: boundary.label(),
});
}
if matches!(class, ReconClass::RolledBack) {
if let Some(orphan) = outcome.remaining.first() {
return Err(ReconViolation::LiveOrphanAfterRollback {
boundary: boundary.label(),
orphan: orphan.reference.clone(),
});
}
}
let mut digest = fold(fold(FNV_OFFSET, seed), boundary.token());
digest = fold(digest, class.token());
digest = fold(digest, outcome.swept.len() as u64);
Ok(ReconCell {
boundary: boundary.label().to_string(),
class,
digest,
swept: outcome.swept.len(),
})
}
pub fn run_reconciliation_matrix(seed: u64) -> Result<Vec<ReconCell>, String> {
all_crash_boundaries()
.into_iter()
.map(|boundary| {
run_cell(seed, boundary)
.map_err(|v| format!("reconciliation violation (seed={seed}): {v}"))
})
.collect()
}
#[must_use]
pub fn reconciliation_replay_seed(default: u64) -> u64 {
seed_from_env(default)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_boundary_recovers_legally() -> Result<(), String> {
for boundary in all_crash_boundaries() {
run_cell(0x5EED_C301, boundary)
.map_err(|v| format!("boundary {boundary:?} must recover legally: {v}"))?;
}
Ok(())
}
#[test]
fn same_seed_boundary_is_deterministic() -> Result<(), String> {
for boundary in all_crash_boundaries() {
let a = run_cell(0x5EED_C302, boundary).map_err(|v| v.to_string())?;
let b = run_cell(0x5EED_C302, boundary).map_err(|v| v.to_string())?;
assert_eq!(
a, b,
"PROPERTY: identical (seed, boundary={boundary:?}) recovers identically"
);
}
Ok(())
}
#[test]
fn sacred_window_refuses_never_loses() -> Result<(), String> {
let cell = run_cell(0x5EED_C303, CrashBoundary::ArtifactCommittedPreReport)
.map_err(|v| v.to_string())?;
assert_eq!(
cell.class,
ReconClass::CanonicalRefusal,
"a committed artifact with no sealed report must be a typed refusal, never lost"
);
Ok(())
}
#[test]
fn production_reconcile_agrees_with_the_oracle() {
use crate::contract::ids::{ArtifactId, AttemptId, BoundaryPlanHash};
use crate::contract::recovery::{
reconcile as production_reconcile, ArtifactReality, RecoveryProbe, RunView,
};
fn production_inputs(state: &CrashState) -> (RunView, RecoveryProbe) {
let mut view = RunView::new(AttemptId([0u8; 32]), BoundaryPlanHash([0u8; 32]));
view.started = state.plan_sealed; view.reported = state.report_sealed && !state.report_torn;
let mut probe = RecoveryProbe {
orphans: state.orphans.clone(),
torn_report: state.report_torn,
..Default::default()
};
if state.artifact_committed {
probe.artifacts.insert(
ArtifactId([7u8; 32]),
ArtifactReality {
promoted_bytes_present: true,
..Default::default()
},
);
}
(view, probe)
}
for boundary in all_crash_boundaries() {
let mut prng = Prng::new(fold(fold(FNV_OFFSET, 0x5EED_C304), boundary.token()));
let state = crash_state(boundary, &mut prng);
let oracle: ReconClass = super::reconcile(&state).class.into();
let (view, probe) = production_inputs(&state);
let production: ReconClass = production_reconcile(&view, &probe)
.classification()
.expect("every sealed-plan boundary records a classification")
.into();
assert_eq!(
production, oracle,
"PROPERTY (§13 LAW): production reconcile must match the oracle at boundary {boundary:?}"
);
}
}
}