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

Renders one `StatifierUI.Fixtures.Bundle` as the per-fragment "test this
step" panel: what the fragment's expressions evaluate to under each of its
datasets, and whether each expectation it states still holds.

A pure function over the bundle, in the shape of
`StatifierUI.TruthTable.Markdown` and `StatifierUI.EventLog.Markdown`: 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.test_panel/2` is the widget wrapper.

## Two questions, both shown

The panel is deliberately both halves of the fixture contract at once:

  * the **truth table** (`StatifierUI.TruthTable`) - what every expression
    actually evaluates to under every dataset, whether or not an
    expectation was stated. This is the reading surface.
  * the **expectations** (`StatifierUI.Fixtures.Expectations`) - whether
    every stated `expect` value held. This is the checking surface.

A fragment's panel is useless with only one: the table without the
expectations says what happens but not what was meant, and the expectations
without the table say a stated belief held while staying silent about every
expression that stated none.

## The summary counts rather than passes

The expectations summary reports four counts - matched, mismatched,
errored, and stated against a dataset the bundle does not carry - and never
collapses them into a pass or a fail. That is not indecision: this
package's two consumers of the same fact already disagree about it.
`StatifierUI.Fixtures.Expectations.check/2` counts a `:missing_dataset` as
a failure, because an expectation naming no dataset was never actually
checked; `StatifierUI.Fixtures.Lint` reports the same dangling key as a
warning, per ADR-0006's severity reasoning. Both are right about their own
question, the reconciliation is not this renderer's to make, and a panel
that printed one verdict would silently pick a side. Four counts let the
reader see exactly which of the two situations they are in.

## Orientation is passed through, not chosen here

`:orientation` is forwarded verbatim to
`StatifierUI.TruthTable.Markdown.render/2`, whose own default stands. This
renderer states no preference between the two axes.

# `opt`

```elixir
@type opt() ::
  {:heading, String.t() | nil}
  | {:origin, boolean()}
  | {:expectations, boolean()}
  | {:diagnostics, boolean()}
  | {:orientation, StatifierUI.TruthTable.Markdown.orientation()}
  | {:legend, boolean()}
  | {:sources, boolean()}
  | {:functions, map()}
  | {:providers, keyword()}
```

Options. `:heading` is this panel's own `#` heading; the truth table below
it is always rendered untitled, since the panel is already named. Every
other option is forwarded to the layer that owns it.

# `render`

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

Renders `bundle` as a Markdown string.

Options:

  * `:heading` - the `#` heading. Defaults to the bundle's name; `nil` for
    none.
  * `:origin` - include a line naming the module or file the bundle came
    from. Defaults to `true`, because a panel that shows wrong examples is
    most often showing the wrong bundle.
  * `:expectations` - include the expectations section. Defaults to `true`.
  * `:diagnostics` - include the bundle's load diagnostics (an unknown
    sidecar key, a future version). Defaults to `true`.
  * `:orientation`, `:legend`, `:sources` - forwarded to
    `StatifierUI.TruthTable.Markdown.render/2`.
  * `:functions`, `:providers` - forwarded to `Predicator.evaluate/3`
    through both the table and the expectation run, so the panel's two
    halves evaluate under identical conditions.

Never raises: an expression that fails to evaluate is a cell and a row,
not an exception.

# `render_discovery`

```elixir
@spec render_discovery(StatifierUI.Fixtures.Bundle.discovery(), [opt()]) :: String.t()
```

Renders every bundle in a `t:StatifierUI.Fixtures.Bundle.discovery/0`, one
panel after another, followed by a section naming the entries that failed
to load.

Entries that ship no bundle are not listed. A palette where most fragments
carry no examples is the normal case, and a page reciting them says nothing
a reader can act on; a bundle that was *meant* to load and did not is the
opposite, and is always named.

`:legend` defaults to `false` here rather than `true`: the three-values
legend is worth one appearance on a page, not one per fragment.

---

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