ready-active-safe 0.1.3

Lifecycle engine for externally driven systems
Documentation
# Landscape

Where `ready-active-safe` fits in the Rust ecosystem and how it differs from existing crates.

---

## Identity

`ready-active-safe` is a **lifecycle engine**, not a finite state machine library.

The distinction matters: FSM libraries model arbitrary state graphs with arbitrary transitions. `ready-active-safe` models system lifecycles. This is the deliberate progression through operational phases (readiness, activity, safe shutdown) that externally driven systems share.

If you need an arbitrary state machine with guards, hierarchical states, and event queues, use an FSM library. If you need to model how a system starts up, runs, and shuts down with pure, testable logic, `ready-active-safe` is designed for that.

---

## Landscape Mapping

### statig

[statig](https://crates.io/crates/statig) is a hierarchical state machine library with
optional procedural macros. It is a good fit when hierarchical state is the
right model and you want a no-heap embedded story.

| Aspect              | statig                                | ready-active-safe                     |
|---------------------|---------------------------------------|---------------------------------------|
| Paradigm            | Hierarchical state machine (UML)      | Lifecycle phases (modes)              |
| API style           | Optional proc macros + traits         | Manual trait implementation           |
| State model         | Arbitrary graph with hierarchy        | Deliberate lifecycle phases           |
| I/O                 | Actions can perform side effects      | Pure: returns `Decision`, no effects  |
| Time                | Not modeled                           | Composable via feature module         |
| Transition auditing | Not built-in                          | Journal feature (std-only)            |
| `no_std`            | Supported                             | Supported (core types)                |

**When to choose statig:** You have a complex state graph with hierarchical substates and you want macro-generated boilerplate reduction.

**When to choose ready-active-safe:** You want pure lifecycle logic with testable decisions, external event driving, and built-in transition auditing.

### smlang

[smlang](https://crates.io/crates/smlang) is a state machine DSL implemented as macros. You describe states, events, transitions, and actions, and it generates the matching/dispatch code for you.

| Aspect              | smlang                                | ready-active-safe                     |
|---------------------|---------------------------------------|---------------------------------------|
| Paradigm            | Traditional FSM                        | Lifecycle phases (modes)              |
| API style           | DSL + macro expansion                  | Manual trait implementation           |
| I/O                 | Actions are usually side-effecting     | Pure: returns `Decision`, no effects  |
| Boilerplate         | Very low                               | Low, but explicit                     |
| Debuggability       | Depends on generated code              | Plain Rust                            |
| `no_std`            | Varies by usage                        | Supported (core types)                |

**When to choose smlang:** You want a compact DSL and are happy with macro-generated code and inline actions.

**When to choose ready-active-safe:** You want to keep effects out of the transition function and keep lifecycle logic as a pure, testable component.

### rustate

[rustate](https://crates.io/crates/rustate) is primarily an **actor framework**.
It may use state-machine concepts internally, but it is closer to “actors with
messages” than a small lifecycle kernel.

| Aspect              | rustate                               | ready-active-safe                     |
|---------------------|---------------------------------------|---------------------------------------|
| Paradigm            | Actor framework                       | Lifecycle phases (modes)              |
| Model richness      | Messaging, supervision, actor model   | Minimal kernel + external adapters    |
| I/O                 | Actor handlers usually do I/O         | Pure: returns `Decision`, no effects  |
| Target problems     | Long-lived concurrent components      | Operational lifecycle modeling        |
| Trade-off           | More power, more framework gravity    | Less power, tighter semantics         |

**When to choose rustate:** You want an actor framework and your “state machine”
needs are part of that broader concurrency model.

**When to choose ready-active-safe:** Your system is externally driven and you primarily need correctness, portability, and auditable lifecycle decisions.

### statechart

[statechart](https://crates.io/crates/statechart) is an implementation of
statecharts (hierarchy, internal transitions, richer semantics) in Rust.

| Aspect              | statechart                            | ready-active-safe                     |
|---------------------|---------------------------------------|---------------------------------------|
| Paradigm            | Statecharts                           | Lifecycle phases (modes)              |
| API style           | Macro + interpreter                    | Manual trait implementation           |
| Complexity          | High (rich semantics)                  | Low (small vocabulary)                |
| I/O                 | Actions often run inline               | Pure: returns `Decision`, no effects  |
| Fit                 | Rich behavior modeling                 | Operational lifecycle modeling        |

**When to choose statechart:** You need hierarchical/statecharts semantics and
are okay with a richer runtime model.

**When to choose ready-active-safe:** You want a small kernel with strict
purity and a clear runtime boundary.

### sm

[sm](https://crates.io/crates/sm) is a compile-time state machine library that uses the type system to enforce valid transitions. Invalid transitions are compile errors.

| Aspect              | sm                                    | ready-active-safe                     |
|---------------------|---------------------------------------|---------------------------------------|
| Paradigm            | Type-state pattern                    | Runtime decisions                     |
| Transition safety   | Compile-time (type system)            | Runtime (Policy trait)                |
| Flexibility         | Fixed transitions at compile time     | Dynamic decisions based on events     |
| Output model        | Type transforms                       | Commands (data) for runtime           |
| `no_std`            | Supported                             | Supported (core types)                |

**When to choose sm:** You want the compiler to enforce that only valid transitions are possible, and your state graph is fully known at compile time.

**When to choose ready-active-safe:** Your transitions depend on runtime data (events, configuration), and you need dynamic decisions with command emission.

### state-machines

[state-machines](https://docs.rs/state-machines/) is a Rust port of Ruby’s
`state_machines` gem, with a DSL macro and a callback-oriented model. It is a
good fit if you want a Ruby-style “state machine with hooks” experience.

| Aspect              | state-machines                        | ready-active-safe                     |
|---------------------|---------------------------------------|---------------------------------------|
| Paradigm            | DSL + callbacks                        | Runtime decisions                     |
| Transition hooks    | Yes (callback-style)                   | No (commands returned as data)        |
| Runtime model       | Richer (more semantics)                | Minimal (small vocabulary)            |
| Fit                 | App/domain state machines              | Externally driven lifecycles          |

**When to choose state-machines:** You want a callback/hook model similar to
Ruby state machine libraries.

**When to choose ready-active-safe:** You want a lightweight kernel where transitions are a pure function of runtime events and configuration.

### state_machine_future

[state_machine_future](https://crates.io/crates/state_machine_future) models
state machines as futures, where each state transition is an async step.

| Aspect              | state_machine_future                  | ready-active-safe                     |
|---------------------|---------------------------------------|---------------------------------------|
| Paradigm            | Async state machine                   | Synchronous, pure decisions           |
| Runtime coupling    | Tied to async runtime                 | Sans-I/O, no runtime coupling         |
| I/O model           | States perform async I/O              | Machine is pure. Runtime does I/O.    |
| Testability         | Requires async test harness           | Plain synchronous assertions          |
| Ecosystem fit       | Older futures-era patterns            | Modern Rust patterns                   |

**When to choose state_machine_future:** Your state machine *is* an async task
and you want state transitions expressed as `Future` steps (be aware this is an
older design relative to modern async ecosystems).

**When to choose ready-active-safe:** You want to separate decision logic from execution, and test lifecycle rules without async machinery.

### finny

[finny](https://crates.io/crates/finny) is a finite state machine library with proc macros, guards, actions, and timers.

| Aspect              | finny                                 | ready-active-safe                     |
|---------------------|---------------------------------------|---------------------------------------|
| Paradigm            | Traditional FSM with guards/actions   | Lifecycle engine with modes           |
| API style           | Proc macros, builder pattern          | Plain trait, manual implementation    |
| Guards              | Built-in guard functions              | Policy trait (separate concern)       |
| Actions             | Inline side effects                   | Commands returned as data             |
| Timers              | Built-in timer support                | Time composes externally              |
| Transition history  | Not built-in                          | Journal feature (std-only)            |
| `no_std`            | Supported                             | Supported (core types)                |

**When to choose finny:** You want a batteries-included FSM with built-in guards, actions, and timers, and you prefer proc-macro-driven definitions.

**When to choose ready-active-safe:** You want decisions separated from effects, composable time, transition auditing, and no proc-macro dependency.

### rs_state_machine / rs-statemachine

There are several crates in the ecosystem that generate FSM implementations from
annotated definitions (for example `rs_state_machine`, `rs_statemachine`, and
`rs-statemachine`). They are useful when you want a more feature-rich FSM model
or code generation to reduce repetitive match code.

**When to choose a generator crate:** Your problem is best modeled as a general FSM, and you want code generation to reduce repetitive match code.

**When to choose ready-active-safe:** You want to keep your lifecycle model explicit and keep effects outside the decision boundary.

---

## Differentiation

The following properties distinguish `ready-active-safe` from FSM libraries as a category:

### Modes vs. States

FSM libraries model arbitrary state graphs. `ready-active-safe` models lifecycle phases. This is not a limitation. It is a design choice. Lifecycle systems have a natural structure (initialize, run, shut down) that arbitrary graphs do not capture. By optimizing for this structure, the crate provides a simpler mental model and better defaults for the systems it targets.

### Sans-I/O

The `Machine` trait is pure. It takes immutable references and returns a `Decision`. It never performs I/O, accesses global state, or mutates the machine. This means:

- Machine logic is tested with plain assertions.
- The same machine works with any runtime (sync, async, embedded, simulated).
- Decision logic can be replayed deterministically.

Most FSM libraries allow actions to perform side effects inline, coupling the state machine to its execution environment.

### First-Class Time

Time is deliberately excluded from the base trait and offered as a composable feature. This means:

- The core trait works on `no_std` targets without clocks.
- Time can be virtual (test clocks, simulation clocks) or real.
- The runtime manages timers. The machine sees time-related events.

FSM libraries either ignore time entirely or build timer support into the state machine itself, coupling the model to a specific time source.

### Journaling

The journal feature records every mode transition as structured data. This enables auditing, debugging, and deterministic replay. Most FSM libraries do not provide built-in transition recording.

### Recovery as a First-Class Phase

Safe mode is not an error handler. It is a lifecycle phase with the same status as Ready and Active. Recovery transitions (e.g., Safe back to Ready) are modeled with the same `Decision` mechanism as forward transitions. The `Policy` trait can enforce which recovery paths are allowed.

---

## Non-Goals

These are things `ready-active-safe` deliberately does not try to be:

| Non-Goal                         | Rationale                                                                    |
|----------------------------------|------------------------------------------------------------------------------|
| General-purpose FSM library      | The crate models lifecycle phases, not arbitrary state graphs.               |
| Async runtime                    | The machine is synchronous and pure. Async execution is a runtime adapter concern. |
| Proc-macro DSL                   | Plain traits and structs are easier to debug, read, and understand.          |
| Type-state enforcement           | Transitions are checked at runtime by policies, not at compile time by types. This allows dynamic decisions based on runtime data. |
| GUI / game state management      | The crate targets systems with lifecycle semantics (services, controllers, protocols), not UI or game loops. |

### Complementary Crates

These crates solve adjacent problems and pair well with `ready-active-safe`:

| Crate       | Role                                      | How It Complements                          |
|-------------|-------------------------------------------|---------------------------------------------|
| `tokio`     | Async runtime                             | Drives events and dispatches commands async  |
| `tracing`   | Structured logging                        | Logs decisions and transitions               |
| `serde`     | Serialization                             | Serializes mode, event, and command types    |
| `defmt`     | Embedded logging                          | Logs decisions on `no_std` targets           |
| `proptest`  | Property-based testing                    | Generates random event sequences for machine testing |
| `criterion` | Benchmarking                              | Measures decision throughput                 |

---

## Roadmap

For the full versioned release plan (v0.1.0 through v1.0), see [`ROADMAP.md`](ROADMAP.md).

For the competitive audit that informed the roadmap, see [`AUDIT.md`](AUDIT.md).

### Summary

| Version | Theme |
|---------|-------|
| v0.1.0 | Foundation: core types, policy helpers, testing helpers |
| v0.1.1 | Batteries (Minimal): minimal time/runtime/journal + cookbook |
| v0.2.0 | Interop & Observability: optional `serde`, tracing/async examples |
| v0.3.0 | Embedded & Performance: allocation story, perf baseline, embedded guidance |
| v0.4.0 | Property testing & tooling: proptest patterns, visualization ideas |
| v0.5.0 | Polish: API review, migration guides, additional examples |
| v0.6–0.9 | Stabilization: API freeze, real-world validation, docs hardening |
| v1.0.0 | Stable: production-ready, frozen API |