rustev_eval/
acquisition_replay.rs1use rustev_contract::Document;
3use rustev_contract::acquisition::AcquisitionPage;
4use rustev_contract::acquisition_record::AcquisitionResult;
5use rustev_contract::ids::AcquisitionRequestId;
6use rustev_contract::judgment::Unresolved;
7use rustev_contract::replay::{AcquisitionSupply, ItemLocation};
8use rustev_contract::run::RunRecord;
9use rustev_core::evaluate::Evaluation;
10
11use crate::replay::{Incomparable, Inconsistency};
12
13#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct MissingAcquisition {
16 pub step: String,
17 pub tier: u32,
18 pub page: u32,
19 pub request: AcquisitionRequestId,
20}
21
22#[derive(Debug, Clone)]
23pub(crate) enum PageValue {
24 Page(AcquisitionPage),
25 Reason(Unresolved),
26}
27
28fn bad(index: usize, what: Inconsistency) -> Incomparable {
29 Incomparable::Inconsistent {
30 location: ItemLocation::AcquisitionPage(index),
31 what,
32 }
33}
34
35pub(crate) fn supply_page(
36 ev: &mut Evaluation<'_>,
37 entry: &AcquisitionSupply,
38 value: &PageValue,
39 run: &RunRecord,
40 index: usize,
41) -> Result<(), Incomparable> {
42 let pending = ev
43 .pending_acquisitions()
44 .into_iter()
45 .find(|p| p.step == entry.step && p.tier_index == entry.tier && p.page_index == entry.page)
46 .ok_or_else(|| bad(index, Inconsistency::NotPending))?;
47 if pending.request_id != entry.request {
48 return Err(bad(index, Inconsistency::RequestIdentity));
49 }
50 let record = run
51 .acquisitions
52 .iter()
53 .flatten()
54 .find(|p| p.step == entry.step && p.tier == entry.tier && p.page == entry.page)
55 .ok_or_else(|| bad(index, Inconsistency::NotInRun))?;
56 if record.request != entry.request {
57 return Err(bad(index, Inconsistency::RequestIdentity));
58 }
59 if record.attempts.last().map(|a| &a.attempt_id) != entry.attempt_id.as_ref() {
60 return Err(bad(index, Inconsistency::Origin));
61 }
62 match (value, &record.result) {
63 (PageValue::Page(page), AcquisitionResult::Page) => {
64 let bytes = page
65 .record_canonical()
66 .map_err(|_| bad(index, Inconsistency::NoRecordForm))?;
67 if page.request != pending.request_id {
68 return Err(bad(index, Inconsistency::RequestIdentity));
69 }
70 ev.supply_page(&entry.step, entry.tier, entry.page, &bytes)
71 }
72 (PageValue::Reason(reason), AcquisitionResult::Failed(recorded)) if reason == recorded => {
73 ev.supply_acquisition_failure(&entry.step, entry.tier, entry.page, reason.clone())
74 }
75 _ => return Err(bad(index, Inconsistency::Value)),
76 }
77 .map_err(|_| bad(index, Inconsistency::OutputRefused))
78}
79
80pub(crate) fn fill_missing(
81 ev: &mut Evaluation<'_>,
82 entries: &[AcquisitionSupply],
83 missing: &mut Vec<MissingAcquisition>,
84) -> Result<(), Incomparable> {
85 loop {
86 let absent = ev.pending_acquisitions().into_iter().find(|p| {
87 !entries
88 .iter()
89 .any(|e| e.step == p.step && e.tier == p.tier_index && e.page == p.page_index)
90 });
91 let Some(p) = absent else {
92 return Ok(());
93 };
94 ev.supply_acquisition_failure(
95 &p.step,
96 p.tier_index,
97 p.page_index,
98 Unresolved::MissingEvidence {
99 fields: vec![p.step.clone()],
100 },
101 )
102 .map_err(|_| bad(0, Inconsistency::NotPending))?;
106 missing.push(MissingAcquisition {
107 step: p.step,
108 tier: p.tier_index,
109 page: p.page_index,
110 request: p.request_id,
111 });
112 }
113}