# `Milvex.Migration.Reporter`

Renders migration plans and apply reports as user-facing output.

Accepts either:

  * a list of `Milvex.Migration.Plan` structs (used by `--plan` mode), or
  * an apply-report struct (used by `--apply` mode) carrying
    `:plan_results`, `:blocked_by_impossible`, and `:counts` fields.

Two formats are supported via `format: :text | :json`. Both return iodata
so the caller can write directly to stdout without a binary copy.

## Apply-report duck typing

The apply-report path matches structurally on `is_struct/1` plus the presence
of `:plan_results` rather than hard-matching
`Milvex.Migration.Runner.ApplyReport`, keeping this module decoupled from the
Runner's struct definition. Each `plan_result` is expected to carry `:plan`,
`:op_results`, and `:load_status`; each op-result is expected to carry
`:operation` and `:status`.

# `render`

```elixir
@spec render(
  [Milvex.Migration.Plan.t()] | struct(),
  keyword()
) :: iodata()
```

Renders the given plans or apply-report as iodata.

Pass `format: :text` (default) or `format: :json` via `opts` to select the
output format.

---

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