pub trait ProviderSession: Send + Sync {
// Required methods
fn attestation(&self) -> &CapabilityAttestation;
fn execute<'life0, 'async_trait>(
&'life0 self,
call: BoundActionCall,
cancel: Option<CancellationToken>,
) -> Pin<Box<dyn Future<Output = Result<ActionOutcome, ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn observe<'life0, 'async_trait>(
&'life0 self,
req: ObserveRequest,
cancel: Option<CancellationToken>,
) -> Pin<Box<dyn Future<Output = Result<Observation, ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn ui_snapshot<'life0, 'life1, 'async_trait>(
&'life0 self,
observation_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<UiSnapshotOutcome, ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn reconcile<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
call_id: &'life1 str,
issuing: &'life2 EventCursor,
) -> Pin<Box<dyn Future<Output = Result<ReconcileResult, ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn fetch_evidence<'life0, 'life1, 'async_trait>(
&'life0 self,
asset: &'life1 AssetRef,
) -> Pin<Box<dyn Future<Output = Result<EvidenceStream, ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn record_verdict<'life0, 'async_trait>(
&'life0 self,
verdict: VerdictWrite,
) -> Pin<Box<dyn Future<Output = Result<(), ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn current_cursor<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<EventCursor, ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn health<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<SessionHealth, ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn end<'life0, 'async_trait>(
&'life0 self,
outcome: SessionOutcome,
reason: Option<String>,
) -> Pin<Box<dyn Future<Output = Result<(), ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
}Expand description
An open provider session (spine §4.2 ProviderSession). One session
owns one underlying client connection exclusively. In the broken state
every method except health (which reports
{ ok: false }) fails with a transport_lost-class error (04 §2.1).
Required Methods§
Sourcefn attestation(&self) -> &CapabilityAttestation
fn attestation(&self) -> &CapabilityAttestation
The attestation result (already verified inside open_session),
exposed for Evidence and reports.
Sourcefn execute<'life0, 'async_trait>(
&'life0 self,
call: BoundActionCall,
cancel: Option<CancellationToken>,
) -> Pin<Box<dyn Future<Output = Result<ActionOutcome, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn execute<'life0, 'async_trait>(
&'life0 self,
call: BoundActionCall,
cancel: Option<CancellationToken>,
) -> Pin<Box<dyn Future<Output = Result<ActionOutcome, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Executes an action (devicerail: device.execute). The four-way
terminal outcome is returned unfolded and untranslated — failed,
cancelled and timedOut are Ok values, not errors. Err means
“no terminal could be obtained” (transport rupture, envelope
timeout, abort undeliverable); the runner records the attempt as
hanging and goes through reconcile (04 §3).
Preconditions the conformance suite enforces: call.call_id is used
verbatim as the substrate action id; a repeated call_id is
rejected (a retry is a new call_id + new WAL intent); an
unattested action_name is rejected with capability_drift before
any wire request.
Sourcefn observe<'life0, 'async_trait>(
&'life0 self,
req: ObserveRequest,
cancel: Option<CancellationToken>,
) -> Pin<Box<dyn Future<Output = Result<Observation, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn observe<'life0, 'async_trait>(
&'life0 self,
req: ObserveRequest,
cancel: Option<CancellationToken>,
) -> Pin<Box<dyn Future<Output = Result<Observation, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Takes an explicit observation (devicerail: device.observe).
Omissions are data, not errors: a wanted-but-missing part comes back
as a typed omission reason on the Observation (04 §4.1).
Sourcefn ui_snapshot<'life0, 'life1, 'async_trait>(
&'life0 self,
observation_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<UiSnapshotOutcome, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn ui_snapshot<'life0, 'life1, 'async_trait>(
&'life0 self,
observation_id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<UiSnapshotOutcome, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Dereferences an observation’s normalized UI tree (devicerail:
ui.snapshot.get { observationId }; feature
observation.uiSnapshot.v1). Protocol hard limit: readable only
while the issuing session is active → the runner localizes
immediately during observing (04 §4.2).
Sourcefn reconcile<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
call_id: &'life1 str,
issuing: &'life2 EventCursor,
) -> Pin<Box<dyn Future<Output = Result<ReconcileResult, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn reconcile<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
call_id: &'life1 str,
issuing: &'life2 EventCursor,
) -> Pin<Box<dyn Future<Output = Result<ReconcileResult, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Effect reconciliation of a pending intent (spine §6.7-B, 04 §5).
issuing is the credential of the session generation that
dispatched the intent (2026-07-18 incorporation: explicit
parameter — pendingIntent issuing state, falling back to the
checkpoint binding cursor). The implementation must consult the
ISSUING session’s log: when issuing.sessionId is not this
session and the old log is unreachable, the honest answer is
logUnavailable — never a scan of the current session’s log
(a reachable-but-wrong log can fabricate neverDispatched).
Sourcefn fetch_evidence<'life0, 'life1, 'async_trait>(
&'life0 self,
asset: &'life1 AssetRef,
) -> Pin<Box<dyn Future<Output = Result<EvidenceStream, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn fetch_evidence<'life0, 'life1, 'async_trait>(
&'life0 self,
asset: &'life1 AssetRef,
) -> Pin<Box<dyn Future<Output = Result<EvidenceStream, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Fetches evidence bytes by AssetRef.uri for the local
content-addressed store. When asset.sha256 is present the provider
must verify while reading and fail on mismatch — evidence integrity
is non-negotiable (04 §4.3).
Sourcefn record_verdict<'life0, 'async_trait>(
&'life0 self,
verdict: VerdictWrite,
) -> Pin<Box<dyn Future<Output = Result<(), ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn record_verdict<'life0, 'async_trait>(
&'life0 self,
verdict: VerdictWrite,
) -> Pin<Box<dyn Future<Output = Result<(), ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Writes back a Pointlock-computed verdict (devicerail:
verdict.record; feature verdict.record.v1). Wire hard caps
(VERDICT_SUMMARY_MAX_CHARS, VERDICT_EVIDENCE_MAX_ENTRIES):
the provider fails closed on oversize input with a
bind_arguments_invalid-class error (04 §5).
Sourcefn current_cursor<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<EventCursor, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn current_cursor<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<EventCursor, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
The checkpoint event-cursor watermark: the highest sequence the provider has delivered to the runner (ack-after-persist), not the highest the daemon has produced (04 §5).
Sourcefn health<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<SessionHealth, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn health<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<SessionHealth, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Lightweight, side-effect-free health probe. Must not fail on a
broken session — it reports { ok: false } instead (04 §2.1).
Sourcefn end<'life0, 'async_trait>(
&'life0 self,
outcome: SessionOutcome,
reason: Option<String>,
) -> Pin<Box<dyn Future<Output = Result<(), ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn end<'life0, 'async_trait>(
&'life0 self,
outcome: SessionOutcome,
reason: Option<String>,
) -> Pin<Box<dyn Future<Output = Result<(), ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Ends the session (devicerail: session.end). Idempotent: calling it
on an already ended/broken session is a no-op; best-effort — it must
not fail and block the runner’s teardown when the transport is
already gone (04 §2.1).
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".