Skip to main content

ic_backup/ops/persistence/execution_progress/
mod.rs

1//! Original retained plan/journal admission for local progress and guarded reservations.
2
3use super::{
4    AttemptJournalError, BackupLayoutGuard, OperationPlanPersistenceError, read_operation_plan,
5};
6use crate::{
7    model::{
8        artifacts::ArtifactChecksumRecord, attempt_journal::AttemptJournalRecord,
9        operation_plan::OperationPlanError,
10    },
11    policy::execution_progress::{
12        ExecutionProgressError, ExecutionProgressRequest, ExecutionProgressView, progress,
13    },
14};
15use thiserror::Error;
16
17/// Read complete original retained execution evidence without remote effects or artifact reads.
18///
19/// Requires the exact persisted plan and every original attempt journal. Missing
20/// journals never supply zero consumption. Journal locks are taken sequentially;
21/// hold no attempt guards when calling this function. The layout retains cooperating
22/// exclusion, while noncooperating byte custody remains integration-owned.
23/// This grants no fresh permission, executable call, authenticated receipt or release.
24/// # Errors
25/// Rejects missing/unsafe/changed originals, contention and invalid retained causality.
26pub fn read_execution_progress(
27    layout: &BackupLayoutGuard,
28    expected_plan: &ArtifactChecksumRecord,
29) -> Result<ExecutionProgressView, ExecutionProgressPersistenceError> {
30    read_with_current(layout, expected_plan, None)
31}
32
33pub(super) fn read_with_current(
34    layout: &BackupLayoutGuard,
35    expected_plan: &ArtifactChecksumRecord,
36    current: Option<&AttemptJournalRecord>,
37) -> Result<ExecutionProgressView, ExecutionProgressPersistenceError> {
38    let plan = read_operation_plan(layout, expected_plan)?;
39    let authorities = plan.attempt_authorities()?;
40    let journals = super::attempt_journal::read_original_journals(layout, &authorities, current)?;
41    let references: Vec<_> = journals.iter().collect();
42    Ok(progress(&ExecutionProgressRequest {
43        plan: &plan,
44        journals: &references,
45    })?)
46}
47
48/// Typed local evidence or reservation rejection; no failure resets original spending.
49#[derive(Debug, Error)]
50pub enum ExecutionProgressPersistenceError {
51    /// Exact original persisted plan cannot be admitted.
52    #[error(transparent)]
53    Plan(#[from] OperationPlanPersistenceError),
54    /// Original bulk authority derivation failed.
55    #[error(transparent)]
56    Authority(#[from] OperationPlanError),
57    /// Original journal admission or durable reservation failed.
58    #[error(transparent)]
59    Journal(#[from] AttemptJournalError),
60    /// Complete retained accounting/causality cannot be projected.
61    #[error(transparent)]
62    Policy(#[from] ExecutionProgressError),
63    /// The selected operation has a prerequisite without retained Applied evidence.
64    #[error("operation {0} has unapplied prerequisites")]
65    DependenciesUnapplied(u64),
66}
67
68#[cfg(all(test, unix))]
69mod tests;