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}