Skip to main content

ic_backup/ops/persistence/operation_plan/
mod.rs

1//! Immutable bounded operation plan publication and original local intent admission.
2
3use super::{BackupLayoutGuard, JournalLockError, PersistenceError, immutable_record};
4use crate::model::{
5    artifacts::ArtifactChecksumRecord,
6    operation_plan::{MAX_OPERATION_PLAN_BYTES, OperationPlanRecord},
7};
8use thiserror::Error;
9
10/// Durably create fixed `operation-plan.json` without replacing prior evidence.
11///
12/// The embedded inventory/graph are the declaration's original bindings; separate
13/// retained inventory/graph files are not adopted or rewritten by this operation.
14///
15/// # Errors
16/// Rejects excessive canonical bytes, unsafe/existing entries, replaced roots and IO/locks.
17pub fn create_operation_plan(
18    layout: &BackupLayoutGuard,
19    record: &OperationPlanRecord,
20) -> Result<(), OperationPlanPersistenceError> {
21    immutable_record::create(
22        layout,
23        "operation-plan.json",
24        MAX_OPERATION_PLAN_BYTES,
25        record,
26    )
27}
28
29pub(super) fn create_encoded(
30    layout: &BackupLayoutGuard,
31    bytes: &[u8],
32) -> Result<(), OperationPlanPersistenceError> {
33    immutable_record::create_encoded_record(layout, "operation-plan.json", bytes)
34}
35
36/// Admit bounded validated local plan under its exact original expected intent digest.
37///
38/// Lost creation responses reconcile through this exact local read. This observes
39/// no remote authority, does not create/reset journals and grants no dispatch permit.
40///
41/// # Errors
42/// Rejects unsafe/missing/oversized/invalid declarations, digest mismatch and ownership failures.
43pub fn read_operation_plan(
44    layout: &BackupLayoutGuard,
45    expected: &ArtifactChecksumRecord,
46) -> Result<OperationPlanRecord, OperationPlanPersistenceError> {
47    immutable_record::read_with(
48        layout,
49        "operation-plan.json",
50        MAX_OPERATION_PLAN_BYTES,
51        |record: &OperationPlanRecord| {
52            if &record.digest() != expected {
53                return Err(OperationPlanPersistenceError::DigestMismatch);
54            }
55            Ok(())
56        },
57    )
58}
59
60/// Typed original operation-plan identity or bounded immutable local admission failure.
61#[derive(Debug, Error)]
62pub enum OperationPlanPersistenceError {
63    /// Retained declaration differs from the exact original selected intent digest.
64    #[error("operation plan digest mismatch")]
65    DigestMismatch,
66    /// Cooperating layout/journal ownership failed.
67    #[error(transparent)]
68    Lock(#[from] JournalLockError),
69    /// Bounded JSON, model admission or durable filesystem access failed.
70    #[error(transparent)]
71    Persistence(#[from] PersistenceError),
72}
73
74#[cfg(all(test, unix))]
75mod tests;