# `StatifierUI.Fixtures.Lint`
[🔗](https://github.com/riddler/statifier-ui/blob/v0.11.0/lib/statifier_ui/fixtures/lint.ex#L1)

ADR-0006's two lint findings for a fixture bundle: an expression whose
source text matches no compiled guard, and an `expect` key naming no
dataset. Both are warnings, never errors - this module has no
`{:error, _}` return path anywhere in its public API.

Guard matching is **byte equality on source text only**. A `t_index` never
appears as a matching key, only as an output pointer for a consumer that
wants to annotate a transition: `t_index` values are document-order
positions that shift under any edit above the transition (a state
inserted earlier in the document, for example), so matching by index
would silently pin the wrong guard the moment the chart changes shape.
Matching by source text survives exactly that kind of edit, which is why
ADR-0006 fixes it as the identity.

An unmatched expression is a warning, not an error, because a
free-standing expression with no corresponding guard is a legal state of
the contract - ADR-0006 does not require every expression to mirror a
guard. The warning exists for the near-miss case: an expression authored
against a guard that has since drifted (reformatted, requoted, or
otherwise edited), where matching is exact and a near match does not
count. That case is exactly the one a bare "no match" message hides, so
the finding's message carries the expression's own source text: a drift
of one space or one quote style is invisible until the two strings can be
read against each other, and the reader has the chart's guards in front
of them already.

Reads a compiled `%Statifier.Machine{}` only for its transitions' guard
source text (`Statifier.Machine.Transition.cond`, the `{:compiled, _,
source}` shape `t:Statifier.Machine.expr/0` documents). Nothing here calls
`Predicator` - it reads source strings, it does not evaluate them - and
nothing here modifies the engine (ADR-0002).

# `dangling_expect_keys`

```elixir
@spec dangling_expect_keys(StatifierUI.Fixtures.t()) :: [
  StatifierUI.Fixtures.diagnostic()
]
```

A warning per `expect` key naming no dataset in `fixtures`.

Needs no machine: this is a fact about the bundle alone, so it is callable
on a bundle by itself.

# `guard_matches`

```elixir
@spec guard_matches(StatifierUI.Fixtures.t(), Statifier.Machine.t()) :: %{
  optional(StatifierUI.Fixtures.expression_name()) =&gt; [non_neg_integer()]
}
```

Expression names matched to the `t_index` of every transition whose guard
source text is byte-equal to the expression's source.

A `{:static, _}` guard and a transition with no `cond` at all (`nil`)
carry no author-written expression text, so both are skipped without
error. An expression can match more than one guard; all matching
`t_index` values are returned, sorted.

The `t_index` values in the result are an output - a pointer for a
consumer (a truth table, a guard annotation) that wants to point back at
the transition - never an input to the match. See the moduledoc for why
matching by index would be wrong.

# `lint`

```elixir
@spec lint(StatifierUI.Fixtures.t(), Statifier.Machine.t() | nil) :: [
  StatifierUI.Fixtures.diagnostic()
]
```

Every lint finding for `fixtures`, sorted by `path` for stable,
byte-comparable output (ADR-0005's canonical-order habit).

`machine` of `nil` runs only the machine-free check
(`dangling_expect_keys/1`); given a `%Statifier.Machine{}`, both checks
run.

# `unmatched_expressions`

```elixir
@spec unmatched_expressions(StatifierUI.Fixtures.t(), Statifier.Machine.t()) :: [
  StatifierUI.Fixtures.diagnostic()
]
```

A warning per expression whose source text is byte-equal to no guard in
`machine`.

See the moduledoc for why this is a warning: an unmatched expression is a
legal, free-standing fixture, and the finding exists to surface the
near-miss case where an author expected a match and a text drift (however
small) broke it.

---

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