pub struct DrawOnAuthority { /* private fields */ }Expand description
Drawing on a standing authority, as an effect.
§Why this cannot be a plain call
The remaining balance is mutable state outside the journal. A skill that read it inside the deterministic zone would make replay depend on what the store happens to hold now: a run replayed after a later draw would see a different balance, take a different branch, and produce a history that disagrees with itself. Journaling the draw makes the receipt part of the record, so replay reads what the run actually got.
§The key it deduplicates on is dispatch, not effect
Provenance::effect hashes the attempt number, so a retry carries a
different key — which is right for the journal and exactly wrong here. Two
attempts at one draw must consume the authority once, so the store is keyed
on Provenance::dispatch, the identifier the crate defines as stable
across retries of the same call. Getting this backwards spends a customer’s
authorization twice for one purchase, and only under retry, which is the
hardest condition to notice in testing.
Trait Implementations§
Source§impl Clone for DrawOnAuthority
impl Clone for DrawOnAuthority
Source§impl Debug for DrawOnAuthority
impl Debug for DrawOnAuthority
Source§impl Effect for DrawOnAuthority
impl Effect for DrawOnAuthority
Source§fn mutates(&self) -> bool
fn mutates(&self) -> bool
It changes durable state that authorizes spending, and says so to every
rule reading context.mutates. The id it draws on is checked before
this effect exists: StepCtx::draw
refuses one untrusted data chose.
Source§fn recovery(&self) -> Recovery
fn recovery(&self) -> Recovery
Safe to repeat, because the store deduplicates on the dispatch key and
returns the original receipt. Without that idempotence this would have to
be Reconcile, and every interrupted draw would wake an operator.
Source§type Output = Drawn
type Output = Drawn
Source§fn descriptor(&self) -> EffectDescriptor
fn descriptor(&self) -> EffectDescriptor
Source§fn attach(&mut self, provenance: &Provenance)
fn attach(&mut self, provenance: &Provenance)
Source§fn perform<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Self::Output, EffectError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn perform<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Self::Output, EffectError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn gen_ai_operation(&self) -> Option<&'static str>
fn gen_ai_operation(&self) -> Option<&'static str>
Source§fn gen_ai_request(&self) -> Option<GenAiRequest>
fn gen_ai_request(&self) -> Option<GenAiRequest>
GenAI
span attributes. Read moreSource§fn gen_ai_response(&self, output: &Self::Output) -> Option<GenAiResponse>
fn gen_ai_response(&self, output: &Self::Output) -> Option<GenAiResponse>
Source§fn retry(&self) -> RetryPolicy
fn retry(&self) -> RetryPolicy
Source§fn retries_landed(&self) -> bool
fn retries_landed(&self) -> bool
Source§fn max_sensitivity(&self) -> Sensitivity
fn max_sensitivity(&self) -> Sensitivity
Source§fn sink_arguments(&self) -> Option<&Value>
fn sink_arguments(&self) -> Option<&Value>
Source§fn rebind(&mut self, _arguments: Value) -> bool
fn rebind(&mut self, _arguments: Value) -> bool
arguments in place of the ones this effect was built over,
where it can — what a declared redaction at a sink needs. Read moreSource§fn outbound_bytes(&self) -> u64
fn outbound_bytes(&self) -> u64
Source§fn credential_binding(&self) -> Option<CredentialBinding>
fn credential_binding(&self) -> Option<CredentialBinding>
Source§fn protected_fields(&self) -> &[ProtectedField]
fn protected_fields(&self) -> &[ProtectedField]
Source§fn delegation_depth(&self) -> Option<usize>
fn delegation_depth(&self) -> Option<usize>
Source§fn source(&self) -> SourceId
fn source(&self) -> SourceId
Source§fn output_sensitivity(&self) -> Sensitivity
fn output_sensitivity(&self) -> Sensitivity
Auto Trait Implementations§
impl !RefUnwindSafe for DrawOnAuthority
impl !UnwindSafe for DrawOnAuthority
impl Freeze for DrawOnAuthority
impl Send for DrawOnAuthority
impl Sync for DrawOnAuthority
impl Unpin for DrawOnAuthority
impl UnsafeUnpin for DrawOnAuthority
Blanket Implementations§
Source§impl<E> AnyEffect for Ewhere
E: Effect,
impl<E> AnyEffect for Ewhere
E: Effect,
Source§fn spend_erased(&self, output: &Value) -> Spend
fn spend_erased(&self, output: &Value) -> Spend
Round-trips the output to ask the typed effect what it cost.
A type that cannot be deserialized from its own serialization is already
broken for replay — Effect::Output requires the round-trip, and the
journal reconstructs every output that way. Charging zero here is the
same answer replay would reach, and the defect surfaces where it belongs.
Source§fn gen_ai_response_erased(&self, output: &Value) -> Option<GenAiResponse>
fn gen_ai_response_erased(&self, output: &Value) -> Option<GenAiResponse>
Round-trips the output, for the reason
spend_erased does.
fn descriptor(&self) -> EffectDescriptor
fn attach_erased(&mut self, provenance: &Provenance)
fn gen_ai_operation(&self) -> Option<&'static str>
fn mutates(&self) -> bool
fn recovery(&self) -> Recovery
fn retry(&self) -> RetryPolicy
fn retries_landed(&self) -> bool
fn max_sensitivity(&self) -> Sensitivity
fn sink_arguments(&self) -> Option<&Value>
fn rebind_erased(&mut self, arguments: Value) -> bool
fn outbound_bytes(&self) -> u64
fn credential_binding(&self) -> Option<CredentialBinding>
fn protected_fields(&self) -> &[ProtectedField]
fn delegation_depth(&self) -> Option<usize>
fn source(&self) -> SourceId
fn trust(&self) -> Trust
fn output_sensitivity(&self) -> Sensitivity
fn gen_ai_request(&self) -> Option<GenAiRequest>
fn perform_erased<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Value, EffectError>> + Send + 'async_trait>>where
'life0: 'async_trait,
E: 'async_trait,
fn reconcile_erased<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Reconciliation<Value>, EffectError>> + Send + 'async_trait>>where
'life0: 'async_trait,
E: 'async_trait,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<E> BuildsEffect<E> for Ewhere
E: Effect,
impl<E> BuildsEffect<E> for Ewhere
E: Effect,
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more