# `MailglassAdmin.OptionalDeps.MailglassInbound`
[🔗](https://github.com/szTheory/mailglass/blob/v1.2.0/lib/mailglass_admin/optional_deps/mailglass_inbound.ex#L16)

Runtime gateway for all `mailglass_inbound` access from `mailglass_admin`
(CONTEXT D-48-02 / D-48-03).

The admin LiveView never references `MailglassInbound.*` directly — it calls
these wrappers, which `apply/3` into the inbound read-models
(`Internal.Operator.{Records,Timeline,Detail}`), the routing-trace reflection
(`Router.Matcher.explain/2`), and the replay seam (`Internal.Replay`). When
`mailglass_inbound` is absent (prod-admin without inbound, or the
`--no-optional-deps` compile lane), this whole module is elided and
`available?/0` is unreachable — callers guard with
`Code.ensure_loaded?(__MODULE__)` and degrade by hiding the inbound surface.

Boundary classification: submodule auto-classifies into the `MailglassAdmin`
root boundary; `classify_to:` is reserved for mix tasks and protocol
implementations and is not used here.

# `available?`
*since 0.2.0* 

```elixir
@spec available?() :: boolean()
```

Returns `true`. Because this module is conditionally compiled, its mere
existence implies `mailglass_inbound` is loaded. Callers should still
`Code.ensure_loaded?(__MODULE__)` before calling.

# `detail`
*since 0.2.0* 

```elixir
@spec detail(
  map() | keyword(),
  keyword()
) :: map() | nil
```

Detail (record + evidence + matched outcome) for one inbound record.

# `explain`
*since 0.2.0* 

```elixir
@spec explain(struct(), struct()) :: [tuple()]
```

Per-clause routing-trace verdicts for a route against a message (IADM-04).

# `explain_routes`
*since 0.2.0* 

```elixir
@spec explain_routes(
  module() | nil,
  struct()
) :: [%{mailbox: String.t(), verdicts: [tuple()]}]
```

Builds the per-route routing-trace for one inbound record (IADM-04).

Reflects the adopter's declared routes from `router_module` via
`__mailglass_inbound_routes__/0` (in declared order), reconstructs the
canonical `%InboundMessage{}` from the stored record through
`MailglassInbound.Execution.message_from_record/1`, and runs the in-package
`Router.Matcher.explain/2` per route — so the rendered verdict equals real
matcher behavior (D-48-06; the view never re-implements match semantics).

Returns a list (declared route order) of `%{mailbox: String.t(), verdicts:
[tuple()]}`. The `mailbox` is the route's mailbox module rendered as a string;
`verdicts` is the per-clause list from `explain/2`. Returns `[]` when
`router_module` is `nil` or does not export the reflection function.

# `list_records`
*since 0.2.0* 

```elixir
@spec list_records(
  map() | keyword(),
  keyword()
) :: [map()]
```

Recent inbound records for a tenant — routes to the inbound read-model.

# `replay`
*since 0.2.0* 

```elixir
@spec replay(
  Ecto.UUID.t(),
  keyword()
) :: {:ok, map()} | {:error, term()}
```

Replays a stored inbound record by id. The caller passes `tenant_id:` in `opts`
— `Internal.Replay.replay/2` scopes every load to that tenant and refuses a
foreign-tenant id with `{:error, :not_found}` (T-49-17). The admin's
`verify_tenant/2` gate (D-48-05) remains the first line of defence; this seam is
now tenant-safe by construction too.

# `timeline`
*since 0.2.0* 

```elixir
@spec timeline(
  map() | keyword(),
  keyword()
) :: [map()]
```

Execution-lineage timeline for one inbound record.

---

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