# `Tack.Quality`
[🔗](https://github.com/giggleton/pica/blob/v0.1.0/dev/tack/quality.ex#L1)

The decisions behind `mix tack.quality`, the runner the project's `mix quality` alias
points at: which steps run, in what mode, and whether the toolchain can be trusted to run them.

The steps themselves live in the project's `mix.exs`, under the `quality_steps` project key —
one list, the single source of truth for both the local gate and CI. Each step is
`{label, command}` or `{label, command, options}`; the one option is `skip_on_check: true`,
which marks a step `--check` drops. Locally, formatting the tree *first* is the point: an
unformatted file is fixed up front instead of failing at the end. In CI that same write would
make the trailing `--check-formatted` step decorative — it would be checking work the first step
had just done — so CI runs `mix quality --check`, the same list minus the write.

Pure: this module reads no config and runs no command. `Mix.Tasks.Tack.Quality` owns the
IO.

# `configured_step`

```elixir
@type configured_step() ::
  {String.t(), String.t()} | {String.t(), String.t(), keyword()}
```

A step as `mix.exs` declares it.

# `step`

```elixir
@type step() :: {label :: String.t(), command :: String.t()}
```

A step as the runner executes it.

# `hex_version_check`

```elixir
@spec hex_version_check(String.t() | :none) :: :ok | {:error, String.t()}
```

Whether `installed` (a Hex version string, or `:none` when Hex is not on the code path) can run
the `hex.audit` step. Returns the message to raise with when it cannot.

# `minimum_hex_version`

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

The oldest Hex whose `mix hex.audit` reports security advisories.

# `steps`

```elixir
@spec steps(term(), boolean()) :: {:ok, [step()]} | {:error, String.t()}
```

The steps to run, in order, from the project's `quality_steps` configuration.

With `check?` the steps marked `skip_on_check: true` are dropped. Returns an error naming the
fix when the key is missing or a step is malformed, so a typo in `mix.exs` fails the gate loudly
instead of silently running fewer steps.

---

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