# 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