ready-active-safe 0.1.3

Lifecycle engine for externally driven systems
Documentation
# LifecycleError

Errors that can occur during lifecycle operations.

Uses `#[non_exhaustive]` so new variants can be added in minor versions
without breaking downstream code.

## Variants

### `TransitionDenied`

A mode transition was rejected by the [`Policy`](policy.md).

Fields:
- `from: M` — the mode the system was in
- `to: M` — the mode the system attempted to reach
- `reason: &'static str` — human-readable explanation

## Example

```rust
use ready_active_safe::LifecycleError;

let err: LifecycleError<&str> = LifecycleError::TransitionDenied {
    from: "active",
    to: "ready",
    reason: "backward transitions are not allowed",
};

assert_eq!(
    err.to_string(),
    "transition denied from active to ready: backward transitions are not allowed",
);
```

## Produced by `apply_checked`

```rust
use ready_active_safe::prelude::*;

#[derive(Debug, Clone, PartialEq, Eq)]
enum Mode { Ready, Active, Safe }

let d: Decision<Mode, ()> = transition(Mode::Active);
let err = d.apply_checked(Mode::Ready, &DenyAll).unwrap_err();

match err {
    LifecycleError::TransitionDenied { from, to, reason } => {
        assert_eq!(from, Mode::Ready);
        assert_eq!(to, Mode::Active);
        assert_eq!(reason, "transition denied by policy");
    }
    _ => unreachable!(),
}
```

## Edge Cases

`TransitionDenied` is only produced for actual transitions. Stay decisions
never trigger a policy check:

```rust
use ready_active_safe::prelude::*;

let d: Decision<&str, ()> = stay();
let result = d.apply_checked("ready", &DenyAll);
assert!(result.is_ok());
```

## See Also

- [`Policy`]policy.md — the trait that produces denials
- [`Decision::apply_checked`]decision.md — method form
- [`Machine::step_checked`]machine.md — convenience wrapper