# Decision
The outcome of processing an event through [`Machine::on_event`](machine.md).
A `Decision` captures two orthogonal concerns:
- Whether the system should change mode ([`ModeChange`](mode_change.md))
- What commands the runtime should execute
Decisions are **pure data** — they describe intent, not side effects.
## Constructors
```rust
use ready_active_safe::Decision;
// Stay in the current mode
let stay: Decision<&str, &str> = Decision::stay();
assert!(stay.is_stay());
// Transition to a new mode
let go: Decision<&str, &str> = Decision::transition("active");
assert!(go.is_transition());
assert_eq!(go.target_mode(), Some(&"active"));
```
## Chaining Commands — `emit` / `emit_all`
```rust
use ready_active_safe::Decision;
let d: Decision<&str, &str> = Decision::transition("active")
.emit("initialize")
.emit("begin");
assert_eq!(d.commands(), &["initialize", "begin"]);
```
```rust
use ready_active_safe::Decision;
let d: Decision<&str, &str> = Decision::stay()
.emit_all(["log", "notify"]);
assert_eq!(d.commands(), &["log", "notify"]);
```
## Accessors
```rust
use ready_active_safe::Decision;
let d: Decision<&str, &str> = Decision::transition("active").emit("go");
// mode_change returns the full ModeChange
// target_mode is a shortcut
assert_eq!(d.target_mode(), Some(&"active"));
// commands
assert_eq!(d.commands(), &["go"]);
```
## Consuming Accessors — `into_parts`, `into_mode_change`, `into_commands`
```rust
use ready_active_safe::Decision;
let d: Decision<&str, &str> = Decision::transition("active")
.emit("initialize");
let (change, commands) = d.into_parts();
assert_eq!(change.map(|mc| mc.target), Some("active"));
assert_eq!(commands, vec!["initialize"]);
```
```rust
use ready_active_safe::Decision;
let d: Decision<&str, &str> = Decision::transition("safe");
let change = d.into_mode_change();
assert_eq!(change.map(|mc| mc.target), Some("safe"));
```
```rust
use ready_active_safe::Decision;
let d: Decision<&str, &str> = Decision::stay().emit("log").emit("ack");
let commands = d.into_commands();
assert_eq!(commands, vec!["log", "ack"]);
```
## `apply` — consume decision and update mode
```rust
use ready_active_safe::prelude::*;
let d: Decision<&str, &str> = transition("active").emit("go");
let (mode, commands) = d.apply("ready");
assert_eq!(mode, "active");
assert_eq!(commands, vec!["go"]);
```
## `apply_checked` — apply with policy guard
```rust
use ready_active_safe::prelude::*;
let d: Decision<&str, &str> = transition("active").emit("go");
let (mode, commands) = d.apply_checked("ready", &AllowAll)?;
assert_eq!(mode, "active");
let d2: Decision<&str, &str> = transition("active");
let err = d2.apply_checked("ready", &DenyAll).unwrap_err();
assert!(matches!(err, LifecycleError::TransitionDenied { .. }));
# Ok::<(), LifecycleError<&str>>(())
```
## Edge Cases
A stay decision with `apply` returns the current mode unchanged:
```rust
use ready_active_safe::prelude::*;
let d: Decision<&str, ()> = stay();
let (mode, commands) = d.apply("ready");
assert_eq!(mode, "ready");
assert!(commands.is_empty());
```
A stay decision with `apply_checked` always succeeds (no transition to check):
```rust
use ready_active_safe::prelude::*;
let d: Decision<&str, ()> = stay();
let (mode, _) = d.apply_checked("ready", &DenyAll)?;
assert_eq!(mode, "ready");
# Ok::<(), LifecycleError<&str>>(())
```
## See Also
- [`ModeChange`](mode_change.md) — the transition payload inside a `Decision`
- [Free functions](functions.md) — `stay()`, `transition()`, `ignore()` convenience wrappers
- [`Machine`](machine.md) — the trait that produces `Decision` values