feat(core): typed error domains — Tell/Ask split, PanicError, ActorStopReason (#113)#135
Merged
Conversation
…opReason (#113) Rebuild src/error.rs from the kameo reference oracle, diverging where the type system pays for itself. Split kameo's single SendError into two honest types: - TellError<M>: fire-and-forget delivery failures (ActorNotAlive / MailboxFull); the undelivered message is always handed back (msg is total). - AskError<M, E>: composes TellError via Deliver(..), plus the three reply-side failures a tell can never have (Timeout / Interrupted / Handler(E)). From<TellError> bridges them so `?` works. Whether the message returns is encoded in the variant, not an Option<M>. Retryability is a method (is_retryable / is_terminal), never a caller's guess (rule #3): only delivery backpressure is retryable — a Timeout is not (the message is already in the actor), and a Handler domain error (where nexus's Conflict lives) must never be re-driven as backpressure. Lifecycle side: ActorStopReason (Normal / Killed / Panicked / SupervisorRestart + is_normal) and PanicError, which holds the type-erased payload behind a plain Arc<dyn ReplyError> — no Mutex, since the ReplyError Send+Sync bound recovers Sync without a lock. PanicReason distinguishes a lifecycle-hook failure from a handler panic (the supervisor's restart-storm signal). downcast-rs + thiserror adopted (no manual Display). Deferred to producing cards: ActorStopReason::LinkDied / PeerDisconnected, PanicReason::OnLinkDied, TellError::SendTimeout, serde on the remote tier. 13 tests (TDD red→green) incl. the @bug conflict_is_domain_not_retryable probe and Display stability. Mutation: 0 survivors. nix flake check green.
# Conflicts: # docs/testing/coverage-baseline.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rebuilds
src/error.rsfrom the kameo reference oracle (card #113, epic #122), diverging where the type system pays for itself.What changed
TellError<M>— fire-and-forget delivery failures (ActorNotAlive/MailboxFull); the undelivered message is always handed back (msgis total).AskError<M, E>— composesTellErrorviaDeliver(..), plus the three reply-side failures atellcan never have (Timeout/Interrupted/Handler(E)).From<TellError>bridges them so?works. Whether the message returns is encoded in the variant, not anOption<M>.is_retryable/is_terminal), never a caller's guess (rule feat: replace DHT registry with key-expr discovery #3): only delivery backpressure is retryable — aTimeoutis not (the message is already in the actor), and aHandlerdomain error (nexusConflict) must never be re-driven as backpressure.ActorStopReason(Normal/Killed/Panicked/SupervisorRestart+is_normal) andPanicError, which holds the type-erased payload behind a plainArc<dyn ReplyError>— noMutex(theSend+Syncbound recoversSyncwithout a lock).PanicReasondistinguishes a lifecycle-hook failure from a handler panic (the supervisor's restart-storm signal).downcast-rs+thiserroradopted (rule feat: replace DHT registry with key-expr discovery #3: no manualDisplay).Divergence from the card's finalized note
The card listed the two-type
Tell/Asksplit as "considered, not adopted"; it was adopted here (leverage the type system, push erasure to the edges).Timeoutis classified not retryable (the card's original test list had it retryable). See the card comment for the full rationale.Deferred to producing cards
ActorStopReason::LinkDied/PeerDisconnected(#120/#121, needsActorId),PanicReason::OnLinkDied(#120),TellError::SendTimeout(#118), serde on the remote tier, and theactor_not_alive_unifies_terminalsequence test (needs a spawnable actor, #116/#117).Verification
nix flake checkgreen (14 checks)@bug conflict_is_domain_not_retryableprobe and Display stabilitycargo-mutants): 0 survivorsCloses #113. Absorbs #50 (thiserror), #53 (downcast-rs).