# `Cairnloop.Doctor`
[🔗](https://github.com/szTheory/cairnloop/blob/main/lib/cairnloop/doctor.ex#L1)

Diagnoses a host application's Cairnloop wiring and returns calm, reason-forward findings.

This is the engine behind `mix cairnloop.doctor`. It is deliberately a pure-ish function over
a host router module + the application environment so it can be unit-tested with a fabricated
router and config (no live app required). Each check returns `{level, message}` where `level`
is `:ok | :warn | :error`:

  - `:error` — Cairnloop will not work (e.g. no repo). The task exits non-zero.
  - `:warn`  — a surface is reachable-but-degraded or unmounted (e.g. audit log will render
    empty). Exits zero unless `--strict`.
  - `:ok`    — wired correctly.

Checks are conservative: when the host router cannot be located, route-dependent checks are
skipped with a single `:warn` rather than guessing (precise over alarming).

# `finding`

```elixir
@type finding() :: {level(), String.t()}
```

# `level`

```elixir
@type level() :: :ok | :warn | :error
```

# `checks`

```elixir
@spec checks(
  module() | nil,
  keyword()
) :: [finding()]
```

Runs all diagnostics for the given host `router` module (or `nil` if it could not be resolved).

`opts` may override config lookups for testing (e.g. `repo:`, `auditor:`, `tools:`); anything
not given falls back to `Application.get_env(:cairnloop, key)`.

# `tally`

```elixir
@spec tally([finding()]) :: %{
  ok: non_neg_integer(),
  warn: non_neg_integer(),
  error: non_neg_integer()
}
```

Tallies findings by level: `%{ok: n, warn: n, error: n}`.

---

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