# `JevDSL.Runner`
[🔗](https://github.com/boxxxie/jev_dsl/blob/v0.1.0/lib/jev_dsl/runner.ex#L1)

Runtime evaluation, batch execution, two-tier (L1 + L2) cache orchestration,
and deterministic test stubbing for `JevDSL` contract modules.

Every module that invokes `use JevDSL` automatically receives `evaluate/3`,
`evaluate!/3`, `evaluate_many/3`, `available?/2`, and `cache_key/2` delegated
to `JevDSL.Runner`.

## Telemetry Events

`JevDSL.Runner` emits `:telemetry.span/3` events:
* `[:jev_dsl, :evaluate, :start | :stop | :exception]` — Metadata: `%{module: module(), contract: atom() | String.t(), status: :ok | :error}`.
* `[:jev_dsl, :evaluate_many, :start | :stop | :exception]` — Metadata: `%{module: module(), contract: atom() | String.t(), count: non_neg_integer()}`.

# `api_key`

```elixir
@spec api_key(keyword()) :: String.t()
```

Resolves the trimmed `TYPESAFE_API_KEY` from `opts`, application config, or environment.

# `available?`

```elixir
@spec available?(module(), keyword(), atom()) :: boolean()
```

Returns `true` if the contract module can execute evaluations — either via an injected
1-arity test function (`:eval_fn` or `:eval_fn_key`), an explicit `%SystemOneSDK.Client{}` (`:client`),
a configured `TYPESAFE_API_KEY`, or an enabled Tier-2 cache (`:tier2_cache`).

# `evaluate`

```elixir
@spec evaluate(module(), atom() | String.t(), map(), keyword()) ::
  {:ok, SystemOneSDK.SystemOneResponse.t() | map()} | {:error, term()}
```

Evaluates a single `state` map against `contract_key` defined in `contract_mod`.

## Options

  * `:cache?` - Enables L1/L2 caching (default: `true`).
  * `:cache` - L1 cache module implementing `JevDSL.Cache` (default: module's configured `:cache` or `JevDSL.Cache.ETS`).
  * `:tier2_cache` - Optional L2 durable cache module implementing `JevDSL.Cache`.
  * `:use_tier2_cache` - Allows serving L2 cache hits even when `TYPESAFE_API_KEY` is unset (default: `true`).
  * `:persist_tier2` - Persists new live evaluations and backfills L1 hits into L2 (default: `true`).
  * `:cache_only` - When `true`, resolves only from L1/L2 caches without making live network calls, returning `{:error, :cache_miss}` on misses.
  * `:eval_fn` - A 1-arity mock function `fn state -> {:ok, resp} end` for deterministic unit testing.
  * `:eval_fn_key` - Custom option key holding a 1-arity mock function (default: `:eval_fn`).
  * `:eval_fn_state` - Custom state map passed to the mock `eval_fn` when test assertions inspect extra fields.
  * `:client` - Pre-configured `%SystemOneSDK.Client{}` (including `SystemOneSDK.Test.client()`).
  * `:typesafe_api_key` / `:api_key` - Explicit API key override.
  * `:base_url` / `:model` / `:timeout` / `:timeout_ms` / `:retry` - Forwarded to `SystemOneSDK`.

# `evaluate!`

```elixir
@spec evaluate!(module(), atom() | String.t(), map(), keyword()) ::
  SystemOneSDK.SystemOneResponse.t() | map()
```

Evaluates a single `state` map against `contract_key` or raises `JevDSL.Error` / `SystemOneSDK.Error`.

# `evaluate_many`

```elixir
@spec evaluate_many(module(), atom() | String.t(), [map()], keyword()) :: [
  ok: SystemOneSDK.SystemOneResponse.t() | map(),
  error: term()
]
```

Evaluates a list of `states` concurrently against `contract_key` using `SystemOneSDK.evaluate_many/4`.
Resolves L1 and L2 cache hits first and only dispatches uncached misses over the network,
returning results in the exact order of `states`.

# `has_api_key?`

```elixir
@spec has_api_key?(keyword()) :: boolean()
```

Returns `true` if a non-empty `TYPESAFE_API_KEY` is available.

---

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