# Vision
`ready-active-safe` is a **lifecycle engine** for **externally driven systems**.
It is built for systems whose “state changes” are actually *operational phases* (modes) with
clear contracts: start up, operate, fail safely, and recover. These are driven by events from the outside
world (hardware, runtimes, supervisors, operators).
This document defines the product identity: what the crate is, who it is for, what it will and
will not do, and how we keep the implementation aligned as the API grows.
---
## Problem Statement
Many real systems are not well modeled as “anything can transition to anything” state graphs.
They have a lifecycle:
- Become ready (initialize and validate prerequisites)
- Become active (perform primary work)
- Become safe (shut down, contain faults, recover)
Yet implementation often devolves into ad-hoc flags and scattered conditionals, or into state
machines that interleave effects with transitions, making correctness and auditing hard.
`ready-active-safe` provides a small, explicit vocabulary and a pure decision boundary:
given a current mode and an external event, return **data** describing the next mode (optional)
and commands to execute.
---
## Core Thesis
**Separate decision logic from execution.**
- The **machine** is pure: `(mode, event) -> Decision`.
- The **runtime** (external) owns the current mode, feeds events, checks policy, and executes commands.
- The **policy** (external) determines which transitions are allowed.
- **Recovery** is modeled, not bolted-on: Safe and Safe→Ready are first-class lifecycle paths.
---
## Target Users
This crate is for developers who need:
- Deterministic, testable lifecycle logic without I/O or runtime coupling
- Clear operational phases (modes) with safe/fail/recovery semantics
- Auditability and replay of lifecycle decisions (by logging or via the `journal` feature)
Representative domains:
- Embedded controllers and robotics
- XR/graphics session lifecycles (e.g., OpenXR session state changes)
- Services with explicit readiness/active/safe shutdown boundaries
- Lab/industrial instrumentation and supervisory control
---
## Non-Goals (Identity Guards)
These are deliberate “no’s” that prevent vision drift:
- **Not a general-purpose FSM library** (arbitrary graphs, hierarchical substates, statecharts)
- **No inline side effects** in transition logic (effects belong in runtimes/executors)
- **No required proc-macro DSL** in the core crate (plain Rust traits/structs remain the default)
- **No prescribed runtime** (sync/async/executor choice stays with the user)
- **Not a workflow engine / orchestrator** (no event queues, schedulers, or long-running job graphs)
- **No mandated serialization format** (adapters may offer `serde`, but the core stays lean)
If a feature makes the crate “more like a generic FSM framework”, it is likely out of scope.
---
## The Contract (What Must Always Stay True)
The following are invariants that define correctness and usability:
1. **Purity boundary**: `Machine::on_event` is deterministic and performs no I/O.
2. **Decisions are data**: a `Decision` describes intent. The runtime performs effects.
3. **External control**: the system never transitions itself. Events come from outside.
4. **Recovery-first**: Safe/recovery is modeled as a normal lifecycle phase, not exceptional control flow.
5. **Portability**: core types remain `no_std`-compatible (requires `alloc`).
---
## Product Shape (How It “Feels” To Use)
The intended user flow:
1. Define `Mode`, `Event`, and `Command` types.
2. Implement `Machine` with a `match (mode, event)`.
3. In a runtime loop, feed events and execute commands.
4. Add a `Policy` when you need to restrict transitions.
5. Add logging/journaling when you need audit/replay.
Ergonomics goal: the first useful lifecycle should take **minutes**, not hours.
### Rails-Like DX (In Rust)
“Rails-like” here does not mean “framework”.
It means the crate has a clear, pleasant default path:
- `use ready_active_safe::prelude::*;` is the one obvious import
- examples are copy/paste friendly and kept honest with doctests
- default features are “batteries included”, but never ship stubs
- the escape hatches are real: you can always drop down to `machine.decide(...)`
---
## What “Production Ready” Means Here
“Production ready” is not “feature complete”. It means:
- The **core contract** is stable and well-documented.
- Semantics are explicit (especially policy denial, command ordering, and replay expectations).
- There are no hidden side effects, no `unsafe`, and no panic-based control flow in library code.
- There is a clear path to integrating with real systems (sync loops today, with optional runtime and journaling later).
The crate can be production-ready as a **pure lifecycle kernel** even if optional
`runtime`/`time`/`journal` facilities evolve over time.