# `Mutare.Selector`
[🔗](https://github.com/foxbenjaminfox/mutare/blob/v0.2.1/lib/mutare/selector.ex#L1)

Runtime selection of the active mutant.

The active mutant is constant for an entire suite run, so it is read once from
the environment in the sandbox mix.exs prefix, before target project code, and
stashed in `:persistent_term` (O(1) reads, built for write-once/read-many). Every
selector site in the metamutant reads this key, normally hoisted to one read per
function activation.

Eligible functions run their uninstrumented source when the active mutation
belongs elsewhere: a lifted function through a copy of its original clauses, a
function that stays in place through a second body chosen after its one read.
Pure direct self-recursion may stay in a lifted function's clean clauses without
rereading the selector; it relies on selection remaining stable during the
computation. Ordinary entries and effectful recursion still read afresh, so
`put/1` can select another mutant between in-process calls.

A schema mutant is stored as `{root_relative_file, local_id}` in that single
slot, the file as an **atom** (`namespace_key/1`): every instrumented function
compares it on entry, and an atom compares in one instruction where a path string
of equal length is read byte by byte. `Mutare.Metamutant` projects the slot to the
local integer for the active file, `0` at baseline, or `:inactive` for other files.
Thus only one file can be active and inactive files still short-circuit coverage
before its tracking-flag read. `put/1` and `active/0` speak the string form.
Standalone transforms continue to select by plain integer, including `:start_id`.
The bootstrap combines `MUTARE_ACTIVE_MUTANT` (the local integer) with
`MUTARE_MUTANT_NAMESPACE` (the file); the runner translates report ids before
setting these. An absent namespace retains standalone integer selection.

This module defines both sides of that contract: `Mutare.Metamutant` uses its key
and baseline when building selectors, while `Mutare.Sandbox` renders
`bootstrap_ast/0` into the target project's dependency-free project prefix, with
an idempotent fallback in the test bootstrap.

## Self-hosting: a private key for the suite-under-test

When the target *is* Mutare, the suite-under-test contains Mutare's own tests,
many of which drive selection directly (`put/1`, building fixtures via
`Mutare.Transform`) to exercise the machinery. If those tests wrote the *same*
`:persistent_term` slot the harness uses to hold the mutant-under-test, they
would clobber it mid-run — the active mutant would silently revert to baseline
and every mutant whose killing test ran afterwards would register a **false
survivor** (see `NOTES.md`, "Self-hosting").

So the *runtime* key is configurable: `key/0` returns `default_key/0`
(`:mutare_active`, the harness key) unless `override_env/0` names another, in
which case the suite plays in that private slot. `Mutare.Sandbox.Command` sets
that env var (to `suite_key/0`) on every sandbox `mix` it spawns, so the
suite-under-test reads/writes `:mutare_active__suite` while the *real*
metamutant — whose sites and bootstrap bake `default_key/0` as literals at
transform time, in the harness process where the override is unset — keeps
reading `:mutare_active`. The two never collide. On a normal target there is no
`Mutare.Selector` compiled in, so the env is inert.

# `active`

```elixir
@spec active() :: Mutare.RuntimeId.t()
```

The active mutant id for in-process execution (`0` if unset).

# `baseline`

```elixir
@spec baseline() :: non_neg_integer()
```

The baseline id (no mutant active).

# `bootstrap_ast`

```elixir
@spec bootstrap_ast() :: Macro.t()
```

Dependency-free code that reads the selector environment variables and stores
the active runtime identity. Initialization precedes target project code; repeated
project prefixes and umbrella helpers preserve the first value, even if target
code later changes the environment.

`Mutare.Sandbox` renders this AST directly into project prefixes and the test
bootstrap fallback, so the target does not need Mutare as a dependency.

# `default_key`

```elixir
@spec default_key() :: atom()
```

The harness selection key (`:mutare_active`) — the default `key/0`, env-independent.

# `env_var`

```elixir
@spec env_var() :: String.t()
```

The environment variable a runner sets to pick the active mutant.

# `environment`

```elixir
@spec environment(Mutare.RuntimeId.t()) :: [{String.t(), String.t() | nil}]
```

Selection environment, explicitly clearing an inherited namespace for integer ids.

# `key`

```elixir
@spec key() :: atom()
```

The `:persistent_term` key the metamutant reads at runtime.

`default_key/0` (`:mutare_active`) unless `override_env/0` names another — the
one knob self-hosting needs so the suite-under-test does not clobber the
harness's active-mutant slot (see the moduledoc).

# `namespace_env`

```elixir
@spec namespace_env() :: String.t()
```

Environment variable carrying a schema mutant's root-relative file namespace.

# `namespace_key`

```elixir
@spec namespace_key(String.t()) :: atom() | String.t()
```

The form a file namespace takes in the stored selection and in the projection generated
code matches it against (`Mutare.Metamutant.subject_ast/1`): an atom, or the string itself
when it is too long to be one. `bootstrap_ast/0` applies the same rule inside the target.

# `override_env`

```elixir
@spec override_env() :: String.t()
```

Env var a sandbox run sets to give the suite-under-test a private selection key.

# `put`

```elixir
@spec put(Mutare.RuntimeId.t()) :: :ok
```

Set the active mutant id directly for in-process execution.

# `suite_key`

```elixir
@spec suite_key() :: String.t()
```

The private key (`override_env/0`'s value) the suite-under-test selects on under dogfooding.

---

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