# `Mobus.Stepwise.SpecHelpers`
[🔗](https://github.com/fosferon/mobus_stepwise/blob/main/lib/mobus/stepwise/spec_helpers.ex#L1)

Shared pure functions for inspecting stepwise workflow specs.

Extracted from `StepwiseAdvance`, `StepwiseProjection`, and
`FsmBreakpoint` to eliminate internal duplication. Used by pipeline
components in the foundation; workflow_stem inherits these via
defdelegate.

All functions are pure (no side effects, no process dependency) so
they compose safely in ALF pipeline stages.

# `equivalent_state?`

```elixir
@spec equivalent_state?(term(), term()) :: boolean()
```

Returns `true` when two state identifiers refer to the same state.

Compares atoms directly, binaries directly, and cross-compares
atom/binary via `Atom.to_string/1`.

## Examples

    iex> equivalent_state?(:greeting, :greeting)
    true

    iex> equivalent_state?(:greeting, "greeting")
    true

    iex> equivalent_state?(:greeting, :problem_solving)
    false

# `ordered_steps`

```elixir
@spec ordered_steps(map()) :: [atom() | String.t()]
```

Returns the ordered list of step identifiers for a workflow spec.

Order is derived from:
- `spec.steps` when present and non-empty (explicit order)
- `spec.states` sorted by `step_number` (or `step`) ascending, otherwise
  insertion order

Returns `[]` when the spec has no steps or states.

## Examples

    iex> ordered_steps(%{steps: [:a, :b, :c]})
    [:a, :b, :c]

# `pipeline_stage_modules`

```elixir
@spec pipeline_stage_modules() :: [module()]
```

Returns the ordered list of component modules in the canonical stepwise
pipeline.

Both `Mobus.Stepwise.Pipeline.Stepwise` and `WorkflowStem.Pipelines.Stepwise`
derive their `@components` from this function, guaranteeing a single source
of truth for the pipeline stage order.

Order matters — changing this list changes the pipeline for ALL consumers.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
