# `Squidie.Workflow.EditorSpec`
[🔗](https://github.com/dark-trench/squidie/blob/main/lib/squidie/workflow/editor_spec.ex#L1)

JSON-safe workflow spec projection for visual editors.

This module keeps editor round-trips on the data side of the boundary. It does
not load workflow modules, create atoms from input, resolve editor input into
modules, or start runs. Runtime execution of validated specs remains a
separate boundary.

# `diff_map`

```elixir
@type diff_map() :: %{required(String.t()) =&gt; term()}
```

# `editor_map`

```elixir
@type editor_map() :: %{required(String.t()) =&gt; term()}
```

# `validation_error`

```elixir
@type validation_error() :: %{
  path: [atom() | String.t() | non_neg_integer()],
  code: atom(),
  message: String.t(),
  details: map()
}
```

# `validation_opts`

```elixir
@type validation_opts() :: [
  {:action_registry, Squidie.Workflow.ActionRegistry.registry()}
]
```

# `diff`

```elixir
@spec diff(Squidie.Workflow.Spec.t() | map(), Squidie.Workflow.Spec.t() | map()) ::
  {:ok, diff_map()}
  | {:error, {:invalid_workflow_editor_spec, [validation_error()]}}
```

Compares a source workflow spec with an edited JSON-safe draft.

The result is JSON-safe and reports added, removed, and changed preview nodes
and edges. Both inputs stay on the editor side of the boundary: this validates
and previews data, but does not resolve draft specs into runtime definitions
or start runs.

# `diff`

```elixir
@spec diff(
  Squidie.Workflow.Spec.t() | map(),
  Squidie.Workflow.Spec.t() | map(),
  validation_opts()
) ::
  {:ok, diff_map()}
  | {:error, {:invalid_workflow_editor_spec, [validation_error()]}}
```

Compares a source workflow spec with an edited draft after option-aware validation.

Pass `:action_registry` when either side contains runtime-authored top-level
action keys that must stay inside the host allowlist.

# `preview_graph`

```elixir
@spec preview_graph(Squidie.Workflow.Spec.t() | map()) ::
  {:ok, editor_map()}
  | {:error, {:invalid_workflow_editor_spec, [validation_error()]}}
```

Builds a draft graph preview from a JSON-safe editor spec map.

# `preview_graph`

```elixir
@spec preview_graph(Squidie.Workflow.Spec.t() | map(), validation_opts()) ::
  {:ok, editor_map()}
  | {:error, {:invalid_workflow_editor_spec, [validation_error()]}}
```

Builds a draft graph preview after option-aware editor validation.

Pass `:action_registry` to reject unapproved top-level action keys before the
graph is returned.

# `to_map`

```elixir
@spec to_map(Squidie.Workflow.Spec.t() | map()) :: editor_map()
```

Converts a normalized workflow spec into a JSON-safe editor map.

The projection keeps only editor-owned fields and serializes atoms, module
atoms, keyword lists, nested maps, and lists into JSON-compatible values.

# `validate_map`

```elixir
@spec validate_map(term()) ::
  :ok | {:error, {:invalid_workflow_editor_spec, [validation_error()]}}
```

Validates an editor spec map without starting a run.

Without `:action_registry`, validation stays structural and does not load
workflow modules. When `:action_registry` is supplied, editor-owned top-level
action keys are checked against the host allowlist before the draft can be
previewed or accepted.

# `validate_map`

```elixir
@spec validate_map(term(), validation_opts()) ::
  :ok | {:error, {:invalid_workflow_editor_spec, [validation_error()]}}
```

Validates an editor spec map with optional host-owned action validation.

Pass `:action_registry` when editor-owned top-level action keys should be
checked against the same allowlist used by runtime-authored spec activation.

---

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