error-forge 1.0.0

Pragmatic Rust error-handling framework with stable error metadata, contextual diagnostics, optional async support, and synchronous recovery primitives (retry, circuit-breaker, backoff). Optional #[derive(ModError)], declarative define_errors!, and feature-gated logging / tracing / serde adapters.
Documentation
# error-forge — Stability and SemVer Policy

> Formal stability contract for the `1.x` line. Binding — any
> release that violates it is a bug.

## Headline guarantee

**Every public symbol in `1.0.0` is locked for the entire `1.x`
line.** Signatures, observable behaviour, and the documented
contract of every method cannot change without a major version
bump to `2.0.0`.

This applies to:

- Every symbol re-exported by `mod error_forge` (the crate root)
  and the per-module re-exports under
  `error_forge::{console_theme, context, collector, error,
  logging, macros, recovery, registry}` (and `async_error` /
  `async_error_impl` under `feature = "async"`).
- The trait implementations on the public types
  (`std::error::Error`, `std::fmt::Display`, `std::fmt::Debug`,
  `Clone`, `From<T>`).
- The documented behavioural contracts of every `pub fn`,
  including:
  - Panic-vs-error semantics.
  - Auto-firing of `call_error_hook` from `AppError` / `define_errors!`
    constructors.
  - `ForgeError::register` calling the same hook (and the
    documented double-fire if both paths are exercised).
  - `define_errors!` generating lowercase constructors and
    `Display` / `Error` / `ForgeError` impls.
  - `group!` requiring each wrapped type to implement
    `ForgeError`.

## Version policy

The `1.x` line follows [Semantic Versioning 2.0.0](https://semver.org/).

### Patch releases (`1.x.Y`)

May contain:

- Bug fixes that do not change observable output for any
  documented input.
- Documentation improvements.
- Internal performance work that does not move any public
  surface.
- Test additions.
- Internal dependency updates within their compatible range.

May NOT contain:

- New public items.
- Behavioural changes (including panic-message wording when
  callers may parse it, hook-firing semantics, etc.).
- MSRV bumps.

### Minor releases (`1.Y.0`)

May contain everything a patch release may contain, plus:

- New public items (functions, methods, types, modules) so long
  as they are pure additions — no signature change to any
  existing symbol.
- New optional cargo features that default to off, or default-on
  features that activate purely additive code paths.
- New variants on `#[non_exhaustive]` enums (`ErrorLevel`,
  `CircuitState`) or new fields on `#[non_exhaustive]` structs
  (`ErrorContext`, `ErrorCodeInfo`, `CodedError`,
  `ContextError`, `CircuitBreakerConfig`).
- MSRV bumps. Each MSRV bump is a minor-version bump minimum
  and is called out in the CHANGELOG.

### Major releases (`2.0.0`)

Required for any change that violates the above. Specifically,
any of the following requires `2.0.0`:

- Removal or rename of any public symbol.
- A signature change to any existing public symbol (including
  loosening or tightening the panicking conditions in a
  user-observable way).
- Removing a `#[non_exhaustive]` marker (which would let
  external code resume struct-literal construction —
  considered a contract narrowing, not a widening).
- Changing the default-feature set
  (default features are `[]` in `1.0.0`; adding a default
  feature, or making a default feature opt-in, is breaking).
- Adding a runtime dependency that is not gated behind an
  opt-in feature.
- A change that breaks the documented `0.9.x → 1.0.0`
  migration in [`docs/migration.md`]migration.md.

## Deprecation policy

A symbol marked `#[deprecated]` in a `1.x.Y` release:

- Remains callable for the entire `1.x` line.
- Continues to behave per its documented contract.
- May only be removed in a `2.0.0` release.

Items deprecated in `1.0.0`:

- `error_forge::macros::register_error_hook` (non-`try`
  variant). Use `try_register_error_hook` instead. The non-`try`
  variant silently discards `Err`; the `try_` variant returns it.
- `error_forge::Result<T>` (the type alias). Use
  `error_forge::AppResult<T>` instead. The unqualified `Result`
  name shadows `std::result::Result` in `use error_forge::*`
  glob imports.

Both deprecated names remain callable through the entire `1.x`
line and are removed only in `2.0.0`.

## Panic safety

The crate panics in exactly one place by design: hook
registration is per-process, and a corrupt registry state would
be a bug. Specifically:

- `AppError` and `define_errors!` constructors never panic
  through normal use.
- `ForgeError` default methods never panic.
- `register_error_hook` / `try_register_error_hook` never panic
  on duplicate registration; the `try_` variant returns
  `Err("Error hook already registered")` instead.
- `ConsoleTheme` formatting never panics; ANSI escapes are
  static strings.
- `recovery::CircuitBreaker` uses `parking_lot::Mutex`, which
  does not poison; `lock()` cannot panic in our usage.
- `recovery::RetryExecutor::retry` propagates the inner
  operation's panic if the closure panics (matches what every
  retry library does).

## What is NOT covered

The stability contract does NOT cover:

- **Exact wording of error messages and panic-payload messages.**
  The error *kind* (visible through `ForgeError::kind()`), the
  `Display` chain via `Error::source`, and the prefix
  `"[CODE] "` on `CodedError`-formatted output are part of the
  contract; the human-readable text following them is not.
- **Internal types and modules.** Any item not re-exported
  through `lib.rs` (`pastey`, internal helpers in
  `error.rs::panic_payload_to_listener_error`, the private
  `recovery::retry::{BackoffStrategy, BackoffType, RetryPredicate}`)
  is internal and may move or change between minor releases.
- **Performance characteristics.** A `1.x.Y` may make any
  operation faster or slower than `1.0.0`. Documented benchmark
  numbers (where they exist) are illustrative, not contractual.

## Dependencies

The following runtime dependencies are sealed for the `1.x` line:

- `thiserror` (always-on, error-handling support).
- `pastey` (always-on, macro support — drop-in fork of the
  archived `paste`).
- `parking_lot` (always-on, non-poisoning `Mutex` used by
  `recovery::CircuitBreaker`).
- `error-forge-derive` (optional, gated on `derive` feature).
- `serde` (optional, gated on `serde` feature).
- `log` (optional, gated on `log` feature).
- `tracing` (optional, gated on `tracing` feature).
- `async-trait` (optional, gated on `async` feature).
- `rand` (optional, gated on `jitter` feature).

Adding a new runtime dependency requires a `2.0.0` bump.
Removing any of the always-on deps requires a `2.0.0` bump.
Adding new optional dependencies behind a new opt-in feature is
a minor-version bump.

## MSRV

`1.0.0` ships with MSRV `1.81.0`. Any change to the MSRV is a
minor-version bump minimum.

The `1.81` floor is driven by three independent constraints:

1. `io::Error::other` (used by `AppError::filesystem`) is stable
   since `1.74`.
2. The committed `Cargo.lock` is format v4, which Cargo cannot
   parse on toolchains older than `1.78`.
3. Clippy's `incompatible_msrv` lint flags additional `1.81`
   items in the current source.

`1.81` is the conservative floor satisfying all three.

## Feature flags

The default feature set is `[]` — every optional feature is
opt-in. The full feature list is documented in
[`docs/API.md`](API.md).

Removing a feature from defaults is fine (no change since the
default is empty). Adding a default feature is breaking.
Renaming a feature is breaking.

## Reporting a stability break

If you encounter what looks like a `1.x` stability break:

1. Run the failing case against the latest patch release of
   `1.x` to confirm reproducibility.
2. Capture the exact API call sequence and observed-vs-expected
   behaviour.
3. Open an issue at
   <https://github.com/jamesgober/error-forge/issues> with the
   repro.

Stability breaks are bugs and are fixed in the next patch
release.