foundation capa

foundation-decisioning

Temporal modeling, idempotency keys, and decision tracking

Temporal modeling, idempotency keys, and decision tracking

Tierfoundation
Roleunclassified (baselined)
Pathcrates/foundation/decisioning
Edition2021
Targetsfoundation_decisioning, idempotency_store, idempotency_store_pg
Public items75 across 6 modules
Tests57

What it is for

# foundation-decisioning

Temporal modeling, idempotency keys, and audit-grade decision tracking.

Core Concepts

Idempotency: a fenced register, NOT exactly-once

IdempotencyStore atomically claims a key before an external effect and replays the first result on a duplicate, so a retry never double-fires and always returns the original outcome. It is honestly an idempotency register with fenced ownership + replay, NOT an exactly-once effect library crate: the crash gap (the effect commits, then the process dies before complete) is unclosable here. True exactly-once needs downstream idempotency, a transactional outbox, atomic mutation-plus-complete in one database, or external-operation-id reconciliation. See store for the full contract.

Example

use foundation_decisioning::{Decision, IdempotencyKey, IdempotencyState, actions};
use serde_json::json;
use uuid::Uuid;

// Idempotency key for deduplication
let mut key = IdempotencyKey::new("basket_commit", "basket-123");
key.start_processing();
// ... do work ...
key.mark_succeeded(json!({"order_id": "order-456"}));

// Decision record for audit trail
let decision = Decision::builder()
.actor(Uuid::new_v4())
.target("loans.Application", "app-789")
.action(actions::APPROVE)
.snapshot(json!({"credit_score": 750}))
.outcome(json!({"loan_id": "loan-101"}))
.build();

Capabilities

actions (other)

Standard decision action constants.

Item
pub const COMMIT: & str
pub const APPROVE: & str
pub const REJECT: & str
pub const REVERSE: & str
pub const CANCEL: & str
pub const SUBMIT: & str
pub const RETURN: & str
pub const ESCALATE: & str
pub const DELEGATE: & str
pub const OVERRIDE: & str
pub const WAIVE: & str
pub const FINALIZE: & str

Decision

Decision model for audit-grade decision tracking.

Item
pub struct Decision
Decision :: fn builder() -> DecisionBuilder
Decision :: fn effective_at(& self) -> DateTime <Utc>
Decision :: fn recorded_at(& self) -> DateTime <Utc>
Decision :: fn id(& self) -> Uuid

DecisionBuilder

Decision model for audit-grade decision tracking.

Item
pub struct DecisionBuilder
DecisionBuilder :: fn new() -> Self
DecisionBuilder :: fn effective_at(mut self, timestamp : DateTime <Utc>) -> Self
DecisionBuilder :: fn actor(mut self, id : Uuid) -> Self
DecisionBuilder :: fn on_behalf_of(mut self, id : Uuid) -> Self
DecisionBuilder :: fn authority_context(mut self, context : JsonValue) -> Self
DecisionBuilder :: fn target(mut self, target_type : impl Into <String>, target_id : impl Into <String>) -> Self
DecisionBuilder :: fn action(mut self, action : impl Into <String>) -> Self
DecisionBuilder :: fn snapshot(mut self, snapshot : JsonValue) -> Self
DecisionBuilder :: fn outcome(mut self, outcome : JsonValue) -> Self
DecisionBuilder :: fn build(self) -> Decision

DecisioningError

Error types for decisioning.

Item
pub enum DecisioningError

IdempotencyKey:IdempotencyKey

Idempotency key for preventing duplicate operations.

Item
pub struct IdempotencyKey

IdempotencyKey:cached

Idempotency key for preventing duplicate operations.

Item
IdempotencyKey :: fn cached_response(& self) -> Option <& JsonValue>

IdempotencyKey:expires

Idempotency key for preventing duplicate operations.

Item
IdempotencyKey :: fn expires_in(mut self, duration : Duration) -> Self
IdempotencyKey :: fn expires_at(mut self, timestamp : DateTime <Utc>) -> Self

IdempotencyKey:id

Idempotency key for preventing duplicate operations.

Item
IdempotencyKey :: fn id(& self) -> Uuid

IdempotencyKey:is

Idempotency key for preventing duplicate operations.

Item
IdempotencyKey :: fn is_stale_lock(& self, timeout : Duration) -> bool
IdempotencyKey :: fn is_expired(& self) -> bool
IdempotencyKey :: fn is_terminal_cached(& self) -> bool
IdempotencyKey :: fn is_reclaimable_at(& self, timeout : Duration, now : DateTime <Utc>) -> bool

IdempotencyKey:mark

Idempotency key for preventing duplicate operations.

Item
IdempotencyKey :: fn mark_succeeded(& mut self, response : JsonValue)
IdempotencyKey :: fn mark_succeeded_with_result(& mut self, response : JsonValue, result_type : impl Into <String>, result_id : impl Into <String>,)
IdempotencyKey :: fn mark_failed(& mut self, code : impl Into <String>, message : impl Into <String>)

IdempotencyKey:new

Idempotency key for preventing duplicate operations.

Item
IdempotencyKey :: fn new(scope : impl Into <String>, key : impl Into <String>) -> Self

IdempotencyKey:reset

Idempotency key for preventing duplicate operations.

Item
IdempotencyKey :: fn reset_for_retry(& mut self)

IdempotencyKey:start

Idempotency key for preventing duplicate operations.

Item
IdempotencyKey :: fn start_processing(& mut self)

IdempotencyKey:with

Idempotency key for preventing duplicate operations.

Item
IdempotencyKey :: fn with_request_hash(mut self, hash : impl Into <String>) -> Self

IdempotencyState

Idempotency key for preventing duplicate operations.

Item
pub enum IdempotencyState
IdempotencyState :: fn as_str(& self) -> & 'static str
IdempotencyState :: fn parse(s : & str) -> Option <Self>
IdempotencyState :: fn allows_retry(& self) -> bool
IdempotencyState :: fn is_terminal(& self) -> bool
IdempotencyState :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result

OutcomeClass

Idempotency key for preventing duplicate operations.

Item
pub enum OutcomeClass
OutcomeClass :: fn as_str(self) -> & 'static str
OutcomeClass :: fn parse(s : & str) -> Option <Self>
OutcomeClass :: fn is_cacheable(self) -> bool

RecoveryPolicy

Idempotency key for preventing duplicate operations.

Item
pub enum RecoveryPolicy
RecoveryPolicy :: fn as_str(self) -> & 'static str
RecoveryPolicy :: fn parse(s : & str) -> Option <Self>

store (other)

Fenced idempotency register with replay (harvest of the corpus-wide

Item
pub const DEFAULT_STALE_SECONDS: i64

ClaimOutcome

Fenced idempotency register with replay (harvest of the corpus-wide

Item
pub enum ClaimOutcome

ClaimTicket

Fenced idempotency register with replay (harvest of the corpus-wide

Item
pub struct ClaimTicket
ClaimTicket :: fn scope(& self) -> & str
ClaimTicket :: fn key(& self) -> & str
ClaimTicket :: fn claim_token(& self) -> Uuid

ConflictDecision

Fenced idempotency register with replay (harvest of the corpus-wide

Item
pub enum ConflictDecision
fn classify_conflict(existing : & IdempotencyKey, incoming_request_hash : Option <& str>, policy : RecoveryPolicy, timeout : Duration, now : DateTime <Utc>,) -> Result <ConflictDecision, DecisioningError>

IdempotencyStore

Fenced idempotency register with replay (harvest of the corpus-wide

Item
pub struct IdempotencyStore
IdempotencyStore :: fn new(pool : PgPool) -> Self
IdempotencyStore :: fn with_stale_after(mut self, timeout : Duration) -> Self
IdempotencyStore :: async fn claim(& self, scope : & str, key : & str, request_hash : Option <& str>, policy : RecoveryPolicy,) -> Result <ClaimOutcome, DecisioningError>
IdempotencyStore :: async fn complete(& self, ticket : & ClaimTicket, outcome_class : OutcomeClass, response : Option <& JsonValue>,) -> Result <(), DecisioningError>
IdempotencyStore :: async fn reclaim_stale(& self, scope : & str, timeout : Duration,) -> Result <ReclaimReport, DecisioningError>

ReclaimReport

Fenced idempotency register with replay (harvest of the corpus-wide

Item
pub struct ReclaimReport

EffectiveDated

Temporal modeling traits.

Item
pub trait EffectiveDated

TimeSemantics

Temporal modeling traits.

Item
pub trait TimeSemantics

How to use it

From this crate's own rustdoc:

use foundation_decisioning::{Decision, IdempotencyKey, IdempotencyState, actions};
use serde_json::json;
use uuid::Uuid;

// Idempotency key for deduplication
let mut key = IdempotencyKey::new("basket_commit", "basket-123");
key.start_processing();
// ... do work ...
key.mark_succeeded(json!({"order_id": "order-456"}));

// Decision record for audit trail
let decision = Decision::builder()
    .actor(Uuid::new_v4())
    .target("loans.Application", "app-789")
    .action(actions::APPROVE)
    .snapshot(json!({"credit_score": 750}))
    .outcome(json!({"loan_id": "loan-101"}))
    .build();

Module structure

foundation_decisioning

flowchart TD
  n_foundation_decisioning["foundation_decisioning"]
  n_foundation_decisioning --> n_actions["actions"]
  n_foundation_decisioning --> n_decision["decision"]
  n_foundation_decisioning --> n_error["error"]
  n_foundation_decisioning --> n_idempotency["idempotency"]
  n_foundation_decisioning --> n_store["store"]
  n_foundation_decisioning --> n_temporal["temporal"]

Public surface

`actions`

ItemWhat it is
pub const COMMIT: & strCommit/finalize something.
pub const APPROVE: & strApprove a request.
pub const REJECT: & strReject a request.
pub const REVERSE: & strReverse a previous decision.
pub const CANCEL: & strCancel something.
pub const SUBMIT: & strSubmit for review.
pub const RETURN: & strReturn for version.
pub const ESCALATE: & strEscalate to higher authority.
pub const DELEGATE: & strDelegate to another person.
pub const OVERRIDE: & strOverride a rule or limit.
pub const WAIVE: & strWaive a requirement.
pub const FINALIZE: & strFinalize/close.

`decision`

ItemWhat it is
pub struct DecisionAn audit-grade decision record
Decision :: fn builder() -> DecisionBuilderCreate a new decision builder.
Decision :: fn effective_at(& self) -> DateTime <Utc>
Decision :: fn recorded_at(& self) -> DateTime <Utc>
Decision :: fn id(& self) -> Uuid
pub struct DecisionBuilderBuilder for Decision.
DecisionBuilder :: fn new() -> SelfCreate a new builder.
DecisionBuilder :: fn effective_at(mut self, timestamp : DateTime <Utc>) -> SelfSet when the decision was made (defaults to now).
DecisionBuilder :: fn actor(mut self, id : Uuid) -> SelfSet the actor who made the decision.
DecisionBuilder :: fn on_behalf_of(mut self, id : Uuid) -> SelfSet delegation (decision made on behalf of another user).
DecisionBuilder :: fn authority_context(mut self, context : JsonValue) -> SelfSet authority context (role snapshot at decision time).
DecisionBuilder :: fn target(mut self, target_type : impl Into <String>, target_id : impl Into <String>) -> SelfSet the target object.
DecisionBuilder :: fn action(mut self, action : impl Into <String>) -> SelfSet the action.
DecisionBuilder :: fn snapshot(mut self, snapshot : JsonValue) -> SelfSet the evidence snapshot.
DecisionBuilder :: fn outcome(mut self, outcome : JsonValue) -> SelfSet the outcome/result.
DecisionBuilder :: fn build(self) -> DecisionBuild the decision

`error`

ItemWhat it is
pub enum DecisioningErrorErrors that can occur in decisioning operations.

`idempotency`

ItemWhat it is
pub enum IdempotencyStateState of an idempotency key.
IdempotencyState :: fn as_str(& self) -> & 'static strGet the string representation.
IdempotencyState :: fn parse(s : & str) -> Option <Self>Parse from string.
IdempotencyState :: fn allows_retry(& self) -> boolCheck if this state allows retry.
IdempotencyState :: fn is_terminal(& self) -> boolCheck if this state indicates completion.
IdempotencyState :: fn fmt(& self, f : & mut std::fmt::Formatter <'_>) -> std::fmt::Result
pub enum RecoveryPolicyHow a stale or interrupted claim may be recovered
RecoveryPolicy :: fn as_str(self) -> & 'static strDatabase string form.
RecoveryPolicy :: fn parse(s : & str) -> Option <Self>Parse the database string form.
pub enum OutcomeClassTerminal outcome classification, recorded at completion
OutcomeClass :: fn as_str(self) -> & 'static strDatabase string form.
OutcomeClass :: fn parse(s : & str) -> Option <Self>Parse the database string form.
OutcomeClass :: fn is_cacheable(self) -> boolWhether this outcome may be cached and replayed on a duplicate claim
pub struct IdempotencyKeyIdempotency key for preventing duplicate operations
IdempotencyKey :: fn new(scope : impl Into <String>, key : impl Into <String>) -> SelfCreate a new idempotency key.
IdempotencyKey :: fn with_request_hash(mut self, hash : impl Into <String>) -> SelfBuilder: set request hash.
IdempotencyKey :: fn expires_in(mut self, duration : Duration) -> SelfBuilder: set expiration.
IdempotencyKey :: fn expires_at(mut self, timestamp : DateTime <Utc>) -> SelfBuilder: set expiration timestamp.
IdempotencyKey :: fn start_processing(& mut self)Transition to Processing state.
IdempotencyKey :: fn mark_succeeded(& mut self, response : JsonValue)Mark as succeeded with cached result.
IdempotencyKey :: fn mark_succeeded_with_result(& mut self, response : JsonValue, result_type : impl Into <String>, result_id : impl Into <String>,)Mark as succeeded with result reference.
IdempotencyKey :: fn mark_failed(& mut self, code : impl Into <String>, message : impl Into <String>)Mark as failed with error info.
IdempotencyKey :: fn reset_for_retry(& mut self)Reset for retry (from Failed state).
IdempotencyKey :: fn is_stale_lock(& self, timeout : Duration) -> boolCheck if the lock appears stale (processing for too long).
IdempotencyKey :: fn is_expired(& self) -> boolCheck if this key has expired.
IdempotencyKey :: fn cached_response(& self) -> Option <& JsonValue>Get the cached response if succeeded.
IdempotencyKey :: fn is_terminal_cached(& self) -> boolWhether a terminal, cached outcome exists that must be replayed on a duplicate claim rather than re-fired
IdempotencyKey :: fn is_reclaimable_at(& self, timeout : Duration, now : DateTime <Utc>) -> boolWhether this row is eligible to be reclaimed at now: a stale processing lock, or a retryable failure
IdempotencyKey :: fn id(& self) -> Uuid

`store`

ItemWhat it is
pub const DEFAULT_STALE_SECONDS: i64Default stale-lock timeout: a processing claim older than this is a candidate for reclaim/adjudication (never before — a fresh lock has a live worker).
pub enum ConflictDecisionThe decision made when a claim collides with an existing row
pub struct ClaimTicketProof that this worker owns this idempotency key at this claim epoch
ClaimTicket :: fn scope(& self) -> & strThe operation scope.
ClaimTicket :: fn key(& self) -> & strThe idempotency key.
ClaimTicket :: fn claim_token(& self) -> UuidThe ownership token this claim holds.
pub enum ClaimOutcomeThe result of an IdempotencyStore::claim attempt.
pub struct ReclaimReportThe result of a IdempotencyStore::reclaim_stale sweep.
fn classify_conflict(existing : & IdempotencyKey, incoming_request_hash : Option <& str>, policy : RecoveryPolicy, timeout : Duration, now : DateTime <Utc>,) -> Result <ConflictDecision, DecisioningError>Decide what to do when a claim collides with an existing row
pub struct IdempotencyStoreA Postgres-backed idempotency register with fenced ownership + replay.
IdempotencyStore :: fn new(pool : PgPool) -> SelfCreate a store with the default stale-lock timeout.
IdempotencyStore :: fn with_stale_after(mut self, timeout : Duration) -> SelfOverride how long a processing claim may be held before it is a candidate for reclaim/adjudication
IdempotencyStore :: async fn claim(& self, scope : & str, key : & str, request_hash : Option <& str>, policy : RecoveryPolicy,) -> Result <ClaimOutcome, DecisioningError>Atomically claim (scope, key) before firing an external effect
IdempotencyStore :: async fn complete(& self, ticket : & ClaimTicket, outcome_class : OutcomeClass, response : Option <& JsonValue>,) -> Result <(), DecisioningError>Complete the claimed operation, caching the result for replay
IdempotencyStore :: async fn reclaim_stale(& self, scope : & str, timeout : Duration,) -> Result <ReclaimReport, DecisioningError>Sweep stale processing rows in a scope and classify each by its snapshotted recovery policy

`temporal`

ItemWhat it is
pub trait TimeSemanticsTrait for records with bi-temporal time semantics
pub trait EffectiveDatedTrait for records with validity periods

Re-exports. Exported here, defined elsewhere.

ExportDefined in
DecisioningErrorerror::DecisioningError
HasIdfoundation_basemodels::HasId
{Decision,DecisionBuilder}decision::{Decision,DecisionBuilder}
{EffectiveDated,TimeSemantics}temporal::{EffectiveDated,TimeSemantics}
{IdempotencyKey,IdempotencyState,OutcomeClass,RecoveryPolicy}idempotency::{IdempotencyKey,IdempotencyState,OutcomeClass,RecoveryPolicy}
{classify_conflict,ClaimOutcome,ClaimTicket,ConflictDecision,IdempotencyStore,ReclaimReport,DEFAULT_STALE_SECONDS,}store::{classify_conflict,ClaimOutcome,ClaimTicket,ConflictDecision,IdempotencyStore,ReclaimReport,DEFAULT_STALE_SECONDS,}

Boundary

Depends on no other workspace tier.

Shares tier foundation with 27 other crates: foundation-audit-log, foundation-basemodels, foundation-bounded-io, foundation-conversation-closure, foundation-crypto-sign, foundation-encounter-vocabulary, foundation-fs-metadata, foundation-i18n, … (27 total).

_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._

Where it sits

Tier (ontology)foundation
Architectural role (taxonomy)unclassified (baselined)
Locationcrates/foundation/decisioning
Vocabulary in force (lexicon)current

Dependencies

Runtime, in this workspace.

CrateTierOptionalOnly on
`foundation-basemodels`foundationnoalways

Runtime, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
chrono^0.4serdenoalways
serde^1derivenoalways
serde_json^1noalways
sqlx^0.8runtime-tokio, postgres, chrono, uuid, jsonnoalways
thiserror^2noalways
tokio^1fullnoalways
uuid^1v4, v7, serde, jsnoalways

Development, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
tokio-test^0.4noalways

Build. None.

Depended on by. Nothing in this workspace.

Signal flow — what reaches this crate, and what it reaches.

flowchart LR
  SELF["foundation-decisioning"]
  SELF -->|runtime| n_foundation_basemodels["foundation-basemodels"]
  classDef self fill:#1f883d,stroke:#1f883d,color:#fff;
  class SELF self;

Feature flags

No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.

Targets

KindNameSource
libfoundation_decisioning`src/lib.rs`
testidempotency_store`tests/idempotency_store.rs`
testidempotency_store_pg`tests/idempotency_store_pg.rs`

Error model

Error typeNamed by
DecisioningErrorclassify_conflict

Operational characteristics

PropertyEvidence
async public surfaceyes
async runtimeyes
database accessyes
network I/Onone detected
unsafe codenone detected
environment variablesnone detected

No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.

Configuration

No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.

No workspace crate depends on this one.

Verification

KindCount
Unit tests46
Integration tests11
Examples0
Doctests1

Evidence by module. How often each public module is named by something executable.

ModuleTestsExamplesConsumers
actions1200
decision200
error100
idempotency400
store700
temporal200

What the tests establish, by name:

Documentation coverage

MeasureDocumentedTotal
Public items with rustdoc7075
Public modules with a //! block66
pie showData
    title Public items with rustdoc
    "Documented" : 70
    "No rustdoc detected" : 5

Metrics

MetricValue
Rust source files7
Source lines2184
Code lines1440
Public API items75
Public modules6
Tests57
Examples0
Cargo features0
Direct runtime dependencies8
Workspace reverse dependencies0
pie showData
    title Public API by kind
    "constant" : 13
    "enum" : 6
    "function" : 1
    "method" : 47
    "struct" : 6
    "trait" : 2
pie showData
    title Rust source composition
    "Code" : 1440
    "Blank or comment" : 744

Generation

Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.

Todas las foundation · Manual