# `Mutare.Options`
[🔗](https://github.com/foxbenjaminfox/mutare/blob/v0.4.3/lib/mutare/options.ex#L1)

Validated configuration for a mutation run.

`new/1` resolves a keyword list (or another `Options`) into a struct, validating every field up front. Invalid values raise `ArgumentError`. Passing the same options on the command line or in `.mutare.exs` uses the same validation; see `mix help mutare` for the full list of settable keys and their defaults.

Runtime wiring, such as the resolved `Mutare.Project` and live-progress hooks, lives in `Mutare.Run.Context`, not in this struct.

The fields and their types are listed in `t:t/0` below.

# `t`

```elixir
@type t() :: %Mutare.Options{
  argument_marks: [Mutare.Mutator.mark_declaration()],
  baseline_retries: non_neg_integer(),
  baseline_runs: pos_integer(),
  call_routes: list(),
  compile_timeout: pos_integer() | nil,
  confirm_timeouts: boolean(),
  exclude: [String.t()],
  expand_uses: boolean(),
  extensions: [Mutare.Extension.Spec.t()],
  fail_on_harness_error: boolean(),
  fail_on_poisoned: boolean(),
  harness_retries: non_neg_integer(),
  keep_sandbox: boolean(),
  kill_runs: pos_integer(),
  max_harness_error_rate: number() | nil,
  max_heap_mb: term(),
  max_mutants: pos_integer() | nil,
  max_no_coverage: non_neg_integer() | nil,
  max_survivors: pos_integer() | nil,
  min_score: number() | nil,
  mutators: [Mutare.Mutator.Spec.t()] | nil,
  only_files: MapSet.t() | nil,
  only_lines: MapSet.t() | nil,
  partition_env: String.t() | nil,
  paths: [String.t()],
  probe_timeout: pos_integer() | nil,
  quiet: boolean(),
  reporters: [{:human | :json | :html | :sarif, String.t() | nil}],
  sandbox: String.t() | nil,
  schedulers: pos_integer() | :all,
  seed_app_build: boolean(),
  skip_lifting: MapSet.t(Mutare.Lifting.skip_entry()),
  strict_ignores: boolean(),
  test_selection: :tests | :coverage | :full,
  time_budget: String.t() | nil,
  timeout: pos_integer() | nil,
  timeout_multiplier: number(),
  verbose: boolean(),
  verify_invariants: boolean(),
  workers: pos_integer()
}
```

# `formats`

```elixir
@spec formats() :: [atom()]
```

The output formats a reporter entry may name (`:human`, `:json`, `:html`,
`:sarif`).

    iex> Mutare.Options.formats()
    [:human, :json, :html, :sarif]

# `new`

```elixir
@spec new(t() | keyword()) :: t()
```

Resolve and validate options.

Accepts a keyword list or an existing `Options` struct. Raises `ArgumentError`
on an unknown key or invalid value.

`:workers` (concurrent mutant runs) and `:schedulers` (scheduler threads per
run) divide `System.schedulers_online/0` between them, so the runs do not
oversubscribe the CPU. Whichever is omitted is derived from the other, workers
never above the default's clamp; with neither, workers are half the schedulers
capped at 4. `schedulers: :all` leaves
every run every scheduler. Both are resolved here, so the struct carries
concrete values.

    iex> opts = Mutare.Options.new(
    ...>   paths: ["lib/billing"],
    ...>   workers: 2,
    ...>   mutators: [:arithmetic],
    ...>   reporters: [{:json, "mutare.json"}]
    ...> )
    iex> {opts.paths, opts.workers, Enum.map(opts.mutators, & &1.name), opts.reporters}
    {["lib/billing"], 2, [:arithmetic], [{:json, "mutare.json"}]}

    iex> opts = Mutare.Options.new(workers: 2)
    iex> Mutare.Options.new(opts) == opts
    true

    iex> opts = Mutare.Options.new(workers: 3, schedulers: :all)
    iex> {opts.workers, opts.schedulers}
    {3, :all}

# `renderer`

```elixir
@spec renderer(atom()) :: module()
```

The renderer module for an output `format`.

`:human` maps to `Mutare.Report`; machine formats map to modules under
`Mutare.Report.*`.

---

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