npx skills add https://github.com/zhanghandong/rust-skills --skill m13-domain-errorHow M13 Domain Error fits into a Paperclip company.
M13 Domain Error drops into any Paperclip agent that handles this kind of work. Assign it to a specialist inside a pre-configured PaperclipOrg company and the skill becomes available on every heartbeat — no prompt engineering, no tool wiring.
Pre-configured AI company — 18 agents, 18 skills, one-time purchase.
SKILL.md180 linesExpandCollapse
---name: m13-domain-errordescription: "Use when designing domain error handling. Keywords: domain error, error categorization, recovery strategy, retry, fallback, domain error hierarchy, user-facing vs internal errors, error code design, circuit breaker, graceful degradation, resilience, error context, backoff, retry with backoff, error recovery, transient vs permanent error, 领域错误, 错误分类, 恢复策略, 重试, 熔断器, 优雅降级"user-invocable: false--- # Domain Error Strategy > **Layer 2: Design Choices** ## Core Question **Who needs to handle this error, and how should they recover?** Before designing error types:- Is this user-facing or internal?- Is recovery possible?- What context is needed for debugging? --- ## Error Categorization | Error Type | Audience | Recovery | Example ||------------|----------|----------|---------|| User-facing | End users | Guide action | `InvalidEmail`, `NotFound` || Internal | Developers | Debug info | `DatabaseError`, `ParseError` || System | Ops/SRE | Monitor/alert | `ConnectionTimeout`, `RateLimited` || Transient | Automation | Retry | `NetworkError`, `ServiceUnavailable` || Permanent | Human | Investigate | `ConfigInvalid`, `DataCorrupted` | --- ## Thinking Prompt Before designing error types: 1. **Who sees this error?** - End user → friendly message, actionable - Developer → detailed, debuggable - Ops → structured, alertable 2. **Can we recover?** - Transient → retry with backoff - Degradable → fallback value - Permanent → fail fast, alert 3. **What context is needed?** - Call chain → anyhow::Context - Request ID → structured logging - Input data → error payload --- ## Trace Up ↑ To domain constraints (Layer 3): ```"How should I handle payment failures?" ↑ Ask: What are the business rules for retries? ↑ Check: domain-fintech (transaction requirements) ↑ Check: SLA (availability requirements)``` | Question | Trace To | Ask ||----------|----------|-----|| Retry policy | domain-* | What's acceptable latency for retry? || User experience | domain-* | What message should users see? || Compliance | domain-* | What must be logged for audit? | --- ## Trace Down ↓ To implementation (Layer 1): ```"Need typed errors" ↓ m06-error-handling: thiserror for library ↓ m04-zero-cost: Error enum design "Need error context" ↓ m06-error-handling: anyhow::Context ↓ Logging: tracing with fields "Need retry logic" ↓ m07-concurrency: async retry patterns ↓ Crates: tokio-retry, backoff``` --- ## Quick Reference | Recovery Pattern | When | Implementation ||------------------|------|----------------|| Retry | Transient failures | exponential backoff || Fallback | Degraded mode | cached/default value || Circuit Breaker | Cascading failures | failsafe-rs || Timeout | Slow operations | `tokio::time::timeout` || Bulkhead | Isolation | separate thread pools | ## Error Hierarchy ```rust#[derive(thiserror::Error, Debug)]pub enum AppError { // User-facing #[error("Invalid input: {0}")] Validation(String), // Transient (retryable) #[error("Service temporarily unavailable")] ServiceUnavailable(#[source] reqwest::Error), // Internal (log details, show generic) #[error("Internal error")] Internal(#[source] anyhow::Error),} impl AppError { pub fn is_retryable(&self) -> bool { matches!(self, Self::ServiceUnavailable(_)) }}``` ## Retry Pattern ```rustuse tokio_retry::{Retry, strategy::ExponentialBackoff}; async fn with_retry<F, T, E>(f: F) -> Result<T, E>where F: Fn() -> impl Future<Output = Result<T, E>>, E: std::fmt::Debug,{ let strategy = ExponentialBackoff::from_millis(100) .max_delay(Duration::from_secs(10)) .take(5); Retry::spawn(strategy, || f()).await}``` --- ## Common Mistakes | Mistake | Why Wrong | Better ||---------|-----------|--------|| Same error for all | No actionability | Categorize by audience || Retry everything | Wasted resources | Only transient errors || Infinite retry | DoS self | Max attempts + backoff || Expose internal errors | Security risk | User-friendly messages || No context | Hard to debug | .context() everywhere | --- ## Anti-Patterns | Anti-Pattern | Why Bad | Better ||--------------|---------|--------|| String errors | No structure | thiserror types || panic! for recoverable | Bad UX | Result with context || Ignore errors | Silent failures | Log or propagate || Box<dyn Error> everywhere | Lost type info | thiserror || Error in happy path | Performance | Early validation | --- ## Related Skills | When | See ||------|-----|| Error handling basics | m06-error-handling || Retry implementation | m07-concurrency || Domain modeling | m09-domain || User-facing APIs | domain-* |Coding Guidelines
The coding-guidelines skill provides developers with Rust-specific code style standards and best practices, covering naming conventions, data types, error handl
M01 Ownership
The m01-ownership skill diagnoses and resolves Rust ownership, borrowing, and lifetime errors by guiding developers to understand data ownership requirements ra
M02 Resource
m02-resource guides developers through selecting appropriate smart pointers and resource management patterns in Rust by asking design questions rather than pres