#[non_exhaustive]pub enum RuntimeError {
Show 30 variants
PolicyDenied(PolicyError),
Delegation(DelegationError),
TaskClaim(ClaimError),
ProposalWithheld {
task: String,
reason: Withheld,
},
TaskChanged {
task: String,
},
PlanContract(String),
UnknownTenant(String),
ReservedEventKind {
kind: String,
},
PolicyBundleChanged {
recorded: Option<Digest>,
configured: Option<Digest>,
},
DeclarationChanged {
agent: String,
recorded: Digest,
configured: Digest,
},
DeclarationPinMismatch {
agent: String,
expected: Digest,
found: Option<Digest>,
},
SubjectUnbound {
binding: String,
reason: String,
},
CanonicalizationChanged {
recorded: u16,
implemented: u16,
},
PayloadsErased {
run: String,
},
PayloadsSealed {
run: String,
},
NoCaseStore {
run: String,
case: String,
},
NoProvider {
target: String,
available: Vec<String>,
},
QuotaExceeded(QuotaError),
Draining,
QuotaSettlementPending {
run: String,
epoch: u64,
detail: String,
},
ChainBroken {
seq: Seq,
detail: String,
},
Fenced {
run: String,
held: u64,
current: u64,
},
LeaseHeld {
run: String,
owner: String,
remaining_secs: u64,
},
NotQuarantined {
run: String,
status: String,
},
NotUndecided {
run: String,
effect: String,
},
CannotUnwind {
run: String,
},
AlreadyConcluded {
run: String,
outcome: String,
},
ControlStands {
run: String,
detail: String,
},
Store(StoreError),
Encoding(Error),
}Expand description
Failures reaching the operator.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
PolicyDenied(PolicyError)
Delegation(DelegationError)
The delegation chain presented for this run cannot act here, now.
Its own variant rather than a PolicyDenied:
no rule fired, and the two call for different responses — a denial is
an answer to retry nowhere, an expired chain is an answer to retry with
a fresh credential. Transparent, so the refusal keeps the chain’s own
words: which link, until when, for which plane.
TaskClaim(ClaimError)
The worklist’s own protocol refused a claim or a decision.
Its own variant rather than a PolicyDenied,
because no policy fired: the refusal is the claim protocol’s — four-eyes
exclusion, a missing role, a task somebody else holds, an id that names
nothing. Transparent, so the refusal keeps the store’s own words; typed,
so a surface can answer honestly — “does not exist”, “not yours to
decide” and “held by Bob” call for three different responses, and a
class that flattens them teaches a caller to retry the permanent and
abandon the transient.
ProposalWithheld
An approval was offered for a task whose proposal this plane cannot show.
Its own class, apart from a claim refusal and from
PlanContract, because a caller does something
different with it: decide from a plane that holds the key ring, or
reject — a rejection of the unseen is safe and still records. Nothing
was claimed or recorded, and the task stays open.
TaskChanged
A decision named a version of its task that is no longer the row’s.
Nothing was recorded, and no claim this call took is left behind. The remedy is to read the task again and decide on what it says now; the current version is deliberately not carried, so a caller cannot resubmit without reading.
PlanContract(String)
UnknownTenant(String)
This process serves no plane for the tenant named.
Refused rather than defaulted, which is the whole point: a fallback plane would answer an unregistered tenant with somebody else’s data, and it would look exactly like working software.
ReservedEventKind
An event from outside named a kind this plane mints for itself.
A human task’s answer travels as an event in the agentplane.
namespace, so accepting one from outside would let whoever may post an
event decide a task. Refused at every intake; the worklist is the one
door into the namespace.
PolicyBundleChanged
An open run would continue under policy semantics other than the bundle recorded at admission.
Journaled as the run’s quarantine reason rather than raised, so the message is the one a person reads off the run, and it names the verbs that answer it.
DeclarationChanged
An open run would continue under a different declaration than the one it was admitted under.
The bundle above covers who may authorize; this covers what the agent is. A declarative agent’s behaviour is its manifest — the prompt, the tool grants, the model, the ceilings — so editing it and resuming runs one program over another’s journal. Refused before anything replays, which is the difference between a named remedy and discovering the same fact as a key mismatch several effects in.
Reported only where both sides name a declaration. A coded skill’s behaviour is the embedder’s binary, which this crate cannot identify and does not claim to; there, divergence is the answer, later and less precisely.
Journaled as the run’s quarantine reason rather than raised, as the bundle refusal is.
DeclarationPinMismatch
A run pinned to one declaration revision was offered to a plane where another governs its capability — or none does.
Refused at admission, before authorization and reservation, so nothing is recorded: the caller reviewed one revision and this plane would run another.
SubjectUnbound
A data-subject binding the run’s declaration names resolved to nothing.
Refused at admission, before the run’s records are written: a run whose declaration says whose data it takes in, and which could not say it, would be traced to nobody.
CanonicalizationChanged
The history was written under a different canonicalization rule.
Not a divergence, and reporting it as one is the defect this exists to remove: every effect key comes out of the canonicalizer, so a rule change moves all of them at once and a healthy run replays as non-determinism. The run is unverifiable by this build, which is a different claim and the one the evidence supports.
The journal chain is unaffected — it hashes the bytes it stored rather than re-canonicalizing them — so the history is intact and readable; it simply cannot be re-derived here. Before format freeze the answer is to recreate; after it, a build that means to read old history implements the old rule and selects on this number.
PayloadsErased
The run’s own history is sealed to a key that was destroyed, so this build cannot read the plan it must replay.
A completed erasure, not a fault, and the two call for opposite
responses — which is why this is its own variant rather than the
deserialization error the payload’s shape produces. A sealed payload
arrives at the parser as {"$sealed": "…"}, and the parser says what a
parser says: a field is missing. An operator reading that goes looking
for a corrupt journal, for a version skew, for a bug. The journal is
intact, the chain still verifies, and nothing is wrong with the build:
the data is gone because somebody asked for it to be.
What is still available is the part that matters. A run whose data is erased can never execute again — its recorded effects cannot be read back, so there is nothing to resume onto — but it can still be concluded. A cancellation and an abandonment are recorded in the clear and need no plan, so an operator is never left holding a run with no verb that clears it.
PayloadsSealed
The run’s history is sealed, and this plane holds no key ring to open it.
Not an erasure, and kept apart from PayloadsErased
because the two send a reader opposite ways: erased says the data is
gone for good, this says it is intact and this plane cannot read it — an
operator’s terminal, a restored export, a verifier handed no key. A ring
that is wired answers for itself: a destroyed key is an erasure, an
unreachable one fails the read.
NoCaseStore
The run is bound to a case and this plane holds no case store, so what a resume wrote would sit outside the case.
About this plane, not the run: a plane with a case store continues it, so a caller holding a durable request — a stop, a delivered answer — leaves the driving to that plane.
NoProvider
Nothing on this plane answers to the name run was given.
Carries what the plane does provide, because the question a reader has next is always “then what should I have asked for?” — and the plane is the only party that can answer it. A refusal that names the missing thing and not the available ones sends somebody back to their own source to reconstruct a list this error was already holding.
Fields
QuotaExceeded(QuotaError)
The tenant is at a ceiling, so nothing was admitted.
Distinct from a policy denial, because they call for opposite responses.
A denial says you may not, and retrying is pointless. A quota refusal
says not right now, and the caller should come back — a concurrency
ceiling clears when a run finishes. Collapsing them would teach callers
to retry denials or to give up on back-pressure.
Transparent, because the variant carries a halt as well as a ceiling
and the two must not share a prefix: an operator reading quota: … is halted has been told a stop is back-pressure, which is the confusion
QuotaError::Halted exists to prevent.
Draining
This instance is shutting down, so nothing was admitted.
Back-pressure, not a verdict: the work is fine and another instance will take it. Kept apart from a quota refusal because the two clear on different terms — a ceiling clears when a run finishes here, this one clears when the caller reaches a different process — and apart from a halt, which means stop asking anybody.
Nothing was written: no lease, no quota slot, no journal. A caller may retry immediately, elsewhere.
QuotaSettlementPending
A live pass finished, but its durable quota receipt did not commit.
The run deliberately keeps its lease. Once it expires, the abandonment
sweep derives the same settlement from the journal and retries it under
the idempotent (run, epoch) key; releasing here would remove that retry
handle and turn a store outage into permanent under-accounting.
ChainBroken
The journal’s hash chain does not verify. Either a record was altered after the fact, or a writer produced bytes it did not hash.
Fenced
A write was rejected because another instance owns this run at a higher epoch. Not an error to retry blindly: this instance has been fenced and must drop the run.
LeaseHeld
Another instance holds a live lease on this run. Retryable after the
lease expires — unlike Fenced, which never is.
NotQuarantined
An operator’s answer was offered to a run that is not asking a question.
Reopening and abandoning are answers to a quarantine specifically, and a run in any other state has either not stopped, stopped for a reason a resume already addresses, or ended. Refused by name rather than recorded and ignored: an intervention that is acknowledged and then not acted on is worse than one that is declined, because the operator stops looking.
NotUndecided
An assertion was offered about an effect whose outcome is already known.
A person may supply the fact the journal lacks; they may not replace one it holds. Overwriting a recorded landing with “it did not happen” would let an operator talk a run out of compensating work that stands in the world — with the record showing an orderly reconciliation.
CannotUnwind
Something that unwinds was asked for on a run that must not unwind.
Cancelling promises to reverse what the run did and put the world back, which is exactly what a run holding an unknown outcome may not do. Its own variant rather than a generic refusal, because the operator’s next move is named in it and a caller matching on the class should be able to route them there.
AlreadyConcluded
A cancellation was asked of a run that has already concluded.
Refused rather than recorded: a sealed run is not reopened by anybody changing their mind, and a stored request against it would answer the operator “recorded” for a stop that can never happen.
ControlStands
An operator’s lift or release was recorded, and the control it ended still stands.
The record is written before the register row goes, and the two share
no transaction. Its own variant rather than a store failure, because
the record exists: run names it, and acting again writes a second.
Store(StoreError)
Encoding(Error)
Implementations§
Source§impl RuntimeError
impl RuntimeError
Sourcepub fn from_store(e: StoreError) -> Self
pub fn from_store(e: StoreError) -> Self
Lift a store error into the operator-facing taxonomy.
Two promotions matter, because both change what a human should do:
- Fenced — “I lost ownership of this run” (drop it; another instance has it), as opposed to “the database is unhappy” (retry).
- Corrupt →
ChainBroken— the journal does not verify. That is never a retryable storage hiccup; it means the history has been altered and nothing downstream of it can be trusted. Leaving it as a generic store error would bury the one failure that must never be shrugged off.
Trait Implementations§
Source§impl Debug for RuntimeError
impl Debug for RuntimeError
Source§impl Display for RuntimeError
impl Display for RuntimeError
Source§impl Error for RuntimeError
impl Error for RuntimeError
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Source§impl From<ClaimError> for RuntimeError
impl From<ClaimError> for RuntimeError
Source§fn from(source: ClaimError) -> Self
fn from(source: ClaimError) -> Self
Source§impl From<DelegationError> for RuntimeError
impl From<DelegationError> for RuntimeError
Source§fn from(source: DelegationError) -> Self
fn from(source: DelegationError) -> Self
Source§impl From<Error> for RuntimeError
impl From<Error> for RuntimeError
Source§impl From<PolicyError> for RuntimeError
impl From<PolicyError> for RuntimeError
Source§fn from(source: PolicyError) -> Self
fn from(source: PolicyError) -> Self
Source§impl From<QuotaError> for RuntimeError
impl From<QuotaError> for RuntimeError
Source§fn from(source: QuotaError) -> Self
fn from(source: QuotaError) -> Self
Source§impl From<StoreError> for RuntimeError
impl From<StoreError> for RuntimeError
Source§fn from(source: StoreError) -> Self
fn from(source: StoreError) -> Self
Auto Trait Implementations§
impl !RefUnwindSafe for RuntimeError
impl !UnwindSafe for RuntimeError
impl Freeze for RuntimeError
impl Send for RuntimeError
impl Sync for RuntimeError
impl Unpin for RuntimeError
impl UnsafeUnpin for RuntimeError
Blanket Implementations§
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
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