orion-error 0.6.3

Struct Error for Large Project
Documentation
# 与 thiserror 的差异与协作指南

## 定位

- `thiserror`:负责定义错误类型,自动生成 `Display``Error`
- `orion-error`:负责错误治理,提供分类、错误码、上下文、转换和可观测辅助

导入约定:

- 新代码优先 `use orion_error::prelude::*;`
- 只按 trait 分组导入时可用 `use orion_error::traits_ext::*;`
- 旧的 `owe_*()` / `err_wrap(...)` 兼容导入请显式使用 `use orion_error::compat_prelude::*;``use orion_error::compat_traits::*;`

推荐组合方式是:

- `thiserror` 定义领域错误枚举
-`orion-error` 负责 `UvsReason``StructError`、上下文和转换

## 能力对比

| 能力 | thiserror | orion-error |
|---|---|---|
| 定义领域错误 || 一般 |
| 统一错误分类 || `UvsReason` |
| 错误码 || `ErrorCode` |
| 上下文堆栈 || `OperationContext` |
| 非结构错误转结构错误 || `IntoAs` |
| 结构错误跨层转换 || `ErrorConv` / `ErrorWrapAs` |
| 重试/严重级别判断 || `is_retryable()` / `is_high_severity()` |

## 推荐模式

```rust
use derive_more::From;
use orion_error::{ErrorCode, IntoAs, StructError, UvsReason};
use thiserror::Error;

#[derive(Debug, Error, Clone, PartialEq, From)]
enum AppError {
    #[error("parse failed")]
    Parse,
    #[error("{0}")]
    Uvs(UvsReason),
}

impl ErrorCode for AppError {
    fn error_code(&self) -> i32 {
        match self {
            Self::Parse => 1000,
            Self::Uvs(reason) => reason.error_code(),
        }
    }
}

fn handle() -> Result<(), StructError<AppError>> {
    std::fs::read_to_string("config.toml")
        .into_as(AppError::from(UvsReason::system_error()), "read config failed")
        .map(|_| ())?;
    Ok(())
}
```

这里不需要再写空的 `impl DomainReason for AppError {}`。

## 什么时候用 `into_as(...)`,什么时候保留 `owe_*()`

- `into_as(...)`:V1 默认推荐,适合 `E: std::error::Error` 第一次进入结构化体系
- `owe_*()`:兼容路径,只保留字符串 detail,适合 `E: Display`

如果你关心:

- `source()`
- `root_cause()`
- 下游监控的根因分类
- 更完整的错误链

默认优先使用 `into_as(...)`。

如果上游已经是 `StructError<_>`,则不要再走 `.into_as(...)` 或 `.owe_*()`:

- 做 reason 类型转换时,优先 `err_conv()`
- 做上层语义包装时,优先 `wrap_as(...)`

兼容说明:

- `owe_*_source()` 仍然保留,但不再是 V1 主路径
- `err_wrap(...)` 仍然保留,但属于 compat/bridge 层
- `with_source(...)` 建议改成 `with_std_source(...)``with_struct_source(...)`
- 如果旧代码必须继续导入这些 compat helper,请和 `prelude::*` 分开写,避免把 V1 主路径和兼容层混成一个默认接口

## 实践建议

- 服务边界对外暴露 `error_code()` 和受控错误信息
- 领域错误枚举保留少量稳定变体,底层通用错误走 `Uvs(UvsReason)`
- 在关键链路使用 `doing(...)``record(...)`
- 在普通 `StdError` 第一次进入结构化体系时优先使用 `into_as(...)`
- 在需要主动包装现有错误对象时优先使用 `with_std_source(...)`