Skip to main content

agent_effects_store/
late.rs

1//! Supplementary observations that cannot change authoritative effect state.
2
3use std::time::SystemTime;
4
5use serde::{Deserialize, Serialize};
6
7use crate::{EffectId, EffectRecord, Lease, WorkerId};
8
9/// What a worker observed after it could no longer record an authoritative result.
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
11#[serde(rename_all = "snake_case")]
12pub enum LateOutcome {
13    /// The action returned success; this is not remote verification.
14    Succeeded,
15    /// The action returned an error; this does not prove non-application.
16    Failed,
17    /// The action panicked or was cancelled; its outcome is uncertain.
18    Interrupted,
19}
20
21/// Append-only, untrusted evidence for operator reconciliation.
22///
23/// No input, output, response body, credential, or error message is retained.
24/// Neither this observation nor its timestamps authorize a state transition.
25#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
26pub struct LateObservation {
27    /// Unique observation id, used for idempotent append and pagination.
28    pub id: EffectId,
29    /// The effect this evidence concerns.
30    pub effect_id: EffectId,
31    /// The reporting worker.
32    pub worker: WorkerId,
33    /// The original fencing epoch, not the current holder's epoch.
34    pub lease_epoch: u64,
35    /// The action attempt, starting at 1.
36    pub attempt: u32,
37    /// Start timestamp originally persisted by the store, if available.
38    pub attempt_started_at: Option<SystemTime>,
39    /// The reporting worker's observation time; not a lease clock authority.
40    pub observed_at: SystemTime,
41    /// What the worker saw, without sensitive response data.
42    pub outcome: LateOutcome,
43}
44
45impl LateObservation {
46    /// Builds supplementary evidence about one attempted action.
47    pub fn new(
48        record: &EffectRecord,
49        lease: &Lease,
50        outcome: LateOutcome,
51        observed_at: SystemTime,
52    ) -> Self {
53        Self {
54            id: EffectId::new(),
55            effect_id: record.id,
56            worker: lease.owner.clone(),
57            lease_epoch: lease.epoch,
58            attempt: record.attempt_count,
59            attempt_started_at: record.attempt_started_at,
60            observed_at,
61            outcome,
62        }
63    }
64}