# `StatifierUI.EventLog.Markdown`
[🔗](https://github.com/riddler/statifier-ui/blob/v0.11.0/lib/statifier_ui/event_log/markdown.ex#L1)

Renders a `StatifierUI.EventLog.t()` as Markdown a host hands to
`Kino.Markdown.new/1`, per the sui-t36.5 plan's Phase 3.

`render/2` is a pure function over the log and the `StatifierUI.EventLog.Labels.t()`
that resolves its indexes - it names `Kino` only in this moduledoc and
calls nothing under `Kino.*`, so the same string serves a Livebook cell, a
generated docs page, or a test assertion. `StatifierUI.Kino.Updater` is the
widget wrapper: it hands `StatifierUI.Inspector.event_log/2`'s string,
which is this module's output, to `Kino.Markdown.new/1` for the
inspector's log frame.

## Structure

A header line naming the session (and a drop warning when the log's
`truncated?` is `true`), then one block per macrostep - a collapsible
`<details>`/`<summary>` by default, or a plain `### Macrostep <n>` heading
with `collapsible: false` - each holding a Markdown table with one row per
round, that round's notes (a raised-cause line, its executed content, a
budget-exhausted line), and the macrostep's round-less `effect.*` messages
listed last under their own heading. A footer names `session.halted`/
`session.terminated`/`session.unroutable` when the log carries one.

`exited` and `entered` render through `Labels.states/2` **in list order**
(ADR-0011): this module never re-sorts either list.

With a `:deep_link` template configured, a macrostep whose messages carry
the wire format's `otel` key also gets a `[trace](...)` link at the end of
its summary line (ADR-0013, `StatifierUI.EventLog.DeepLink`). Without the
option, or on a macrostep carrying no correlation, the summary is exactly
what it was.

# `open_selector`

```elixir
@type open_selector() :: :last | :all | :none | [non_neg_integer()]
```

# `opt`

```elixir
@type opt() ::
  {:labels, StatifierUI.EventLog.Labels.t()}
  | {:collapsible, boolean()}
  | {:open, open_selector()}
  | {:selected, non_neg_integer() | nil}
  | {:deep_link, String.t() | StatifierUI.Trace.DeepLink.t() | nil}
```

# `render`

```elixir
@spec render(StatifierUI.EventLog.t(), [opt()]) :: String.t()
```

Renders `log` as a Markdown string.

Options:

  * `:labels` - a `Labels.t()` to resolve indexes with. Defaults to
    `Labels.from_log(log)`.
  * `:collapsible` - wraps each macrostep in `<details>`/`<summary>` when
    `true` (the default), or renders a plain `### Macrostep <n>` heading
    with no HTML when `false`.
  * `:open` - which macrosteps start open when `:collapsible` is `true`:
    `:last` (the default, opens the highest-numbered macrostep), `:all`,
    `:none`, or a list of macrostep numbers.
  * `:selected` - the macrostep number that is selected (sui-3gg), or
    `nil` (the default) when none is. The selected macrostep's summary is
    suffixed `- selected`, the same mark `StatifierUI.Live`'s event log
    uses (sui-jbw); it does not name a diagram, because a host may compose
    this log with no diagram beside it. Where one is mounted - the Kino
    inspector, Livebook - that entry is what the diagram draws, and the
    mark is the whole of the link between the two panes. It is only a
    marker - use `:open` to open that entry as well.
  * `:deep_link` - the host's APM URL template (ADR-0013, sui-4w2), e.g.
    `"https://apm.example.com/trace/{trace_id}?span={span_id}"`. A
    macrostep whose messages carry the wire format's `otel` key gets a
    `[trace](...)` link on its summary line; one that carries none, and
    every macrostep when the option is absent, renders exactly as before.
    A malformed template raises here, where the option is read.

---

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