# `Excessibility.Review.Judge`
[🔗](https://github.com/lessthanseventy/excessibility/blob/v0.18.1/lib/excessibility/review/judge.ex#L1)

Turns a `Excessibility.Review` change into a release-risk **verdict**.

A judge takes one view's change (regions + newly-introduced findings) and
returns a tier, a human-readable blast-radius summary, and structured
risks. Two judges ship:

  * `Excessibility.Review.Judge.Heuristic` (default) — transparent, no
    dependencies; derives the verdict from the change's findings.
  * `Excessibility.Review.Judge.LLM` — asks a model to reason about the
    change. excessibility owns the prompt, schema, and parsing; the host
    app supplies the actual model call (a `completion` function), so the
    library takes on no HTTP dependency.

Select a judge per call (`judge: MyJudge`) or globally:

    config :excessibility, review_judge: Excessibility.Review.Judge.LLM

## Verdict shape

    %{
      tier: :auto | :review | :block,
      blast_radius: String.t(),
      risks: [%{severity: String.t(), area: String.t(), detail: String.t()}],
      confidence: float() | nil,
      source: :heuristic | :llm
    }

# `verdict`

```elixir
@type verdict() :: %{
  :tier =&gt; Excessibility.Review.tier(),
  :blast_radius =&gt; String.t(),
  :risks =&gt; [%{severity: String.t(), area: String.t(), detail: String.t()}],
  :confidence =&gt; float() | nil,
  :source =&gt; :heuristic | :llm,
  optional(:judge_tier) =&gt; Excessibility.Review.tier()
}
```

# `judge`

```elixir
@callback judge(change :: Excessibility.Review.change(), opts :: keyword()) :: verdict()
```

# `verdict`

```elixir
@spec verdict(
  Excessibility.Review.change(),
  keyword()
) :: verdict()
```

Judge a change with the configured (or explicitly given) judge.

Resolution order: `opts[:judge]`, then `config :excessibility, :review_judge`,
then `Heuristic`.

## Tier floor

A judge may raise the tier freely, but may not fully green-light a
deterministic `:block`: when the change's heuristic tier is `:block`
(new critical/serious findings from the rules engine) and the judge
says `:auto`, the verdict is floored to `:review` and the judge's raw
tier is kept in `:judge_tier`. `:auto` means nobody looks at the
change — rendered page content feeds LLM prompts, so that is not a
downgrade a model is allowed to make on its own. `:review` still cuts
block-level false-positive friction while keeping a human in the loop.

---

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