pub struct IntentAgent {
pub fencing_epoch: u64,
pub runs: BTreeMap<String, FoldedRecord>,
pub committed_runs: BTreeMap<String, FoldedRecord>,
}Expand description
One agent’s leased execution-intent ledger — the FoldTier::Leased
tier’s per-agent folded state (B5).
This slice delivers deterministic ledger convergence plus a durable idempotency oracle — it does NOT by itself make execution exactly-once. The exactly-once execution gate is B6’s dispatch fence (a linearizable “am I still epoch N?” check plus the durable non-fenced idempotency read before the external side effect); the fold decides who wins the ledger, not whether the effect happens.
Two distinct views live here, and confusing them causes double-execution:
committed_runsis the idempotency oracle — a fence-INDEPENDENT, keep-all maprun_id → committed record. Once a run commits, it stays here forever (a commit is a fact; no epoch bump erases it), soSyncState::committed_runis the correct “did this run already execute?” lookup. It is carried in the checkpoint and never trimmed by retention/compaction (seecrate::compact).runsis the “who holds now” view — per-agent epoch fencing applies to pending intents (a stale zombie holder’s pending is fenced), while committed/failed records are terminal-immune (never reverted to pending, never cleared by a fence raise). Read viaSyncState::intent. Do NOT useruns/intent()as the idempotency oracle — a pending fenced by a later epoch is absent here yet the run may have committed; askcommitted_runs/SyncState::committed_run.
Fencing is per AGENT, not per run (the proposal’s spec, deliberately):
a zombie’s unique post-failover pending — one the new holder never
re-ran — is fenced too (per-run fencing would let it through). fencing_epoch
is the agent’s max-seen lease epoch. committed_runs is what makes that
safe for idempotency: even after prior-epoch pendings drop from runs, the
committed fact survives keep-all.
Fields§
§fencing_epoch: u64The agent’s fencing epoch — the max lease epoch any of its intents carried. Pending intents below it are fenced (terminals are immune).
runs: BTreeMap<String, FoldedRecord>run_id key (id:<run_id>) → the “who holds now” winner (terminal-immune;
pendings fenced to fencing_epoch). NOT the idempotency oracle.
committed_runs: BTreeMap<String, FoldedRecord>run_id key → the committed record. Fence-independent, keep-all — the
durable idempotency oracle that survives epoch bumps AND compaction.
Grow-only (highest (epoch, hlc, op_id) committed record wins on a
collision); never cleared by fencing. #[serde(default)] so a state
serialized before this field parses.
Trait Implementations§
Source§impl Clone for IntentAgent
impl Clone for IntentAgent
Source§fn clone(&self) -> IntentAgent
fn clone(&self) -> IntentAgent
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for IntentAgent
impl Debug for IntentAgent
Source§impl Default for IntentAgent
impl Default for IntentAgent
Source§fn default() -> IntentAgent
fn default() -> IntentAgent
Source§impl<'de> Deserialize<'de> for IntentAgent
impl<'de> Deserialize<'de> for IntentAgent
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl PartialEq for IntentAgent
impl PartialEq for IntentAgent
Source§fn eq(&self, other: &IntentAgent) -> bool
fn eq(&self, other: &IntentAgent) -> bool
self and other values to be equal, and is used by ==.