# `ExUnitJSON.Trace`
[🔗](https://github.com/ZenHive/ex_unit_json/blob/main/lib/ex_unit_json/trace.ex#L1)

Opt-in failure-only BEAM message tracing for `mix test.json`.

Adds a "flight recorder" to a test: while the test runs, the inter-process
`send`/`receive` messages of the test process tree are captured into a bounded
ring buffer. If the test **fails**, the messages (and a best-effort mailbox
snapshot of still-alive processes) are emitted into the JSON output under a
`"trace"` key; if it **passes**, the buffer is discarded. This surfaces the
message flow that led to a failure for AI consumers debugging GenServer / Port /
LiveView interactions.

## Enabling

Tracing must start *inside* the test process (the formatter runs separately and
only sees a test once it is already finished), so it is wired via a `setup`
callback you add once to your shared `ExUnit.Case` template:

    defmodule MyApp.Case do
      use ExUnit.CaseTemplate

      using do
        quote do
          setup {ExUnitJSON.Trace, :setup}
        end
      end
    end

Then activate it per test or per module with a tag:

    @moduletag trace_messages: true          # whole module
    @tag trace_messages: true                # one test
    @tag trace_messages: 200                 # one test, ring size 200

Without the tag the `setup` callback is a zero-cost no-op, so it is safe to wire
globally.

## What it can and cannot capture

The recorded message **flow** (the ring buffer, with relative timestamps) is the
reliable signal. The mailbox snapshot is **best-effort and marked `approx`**:
by the time a failing test's process dies, its own mailbox is gone, and only
processes still alive near the failure can be sampled. There is no authoritative
"what was unread when it crashed" on the BEAM — that is physically unrecoverable.

Requires OTP 27+ (for `:trace` dynamic sessions), already implied by the library's
use of the built-in `:json` module.

# `setup`

```elixir
@spec setup(map()) :: :ok
```

ExUnit `setup` callback. Use as `setup {ExUnitJSON.Trace, :setup}`.

Reads `:trace_messages` from the test context. When falsy/absent it is a no-op.
When truthy it starts a recorder tracing this test process and the ExUnit test
supervisor (so `start_supervised/2` children are covered). An integer value sets
the ring-buffer size.

---

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