# `Statifier.Validator.Checks.InitialTargets`
[🔗](https://github.com/riddler/statifier-ex/blob/v2.15.0/lib/statifier/validator/checks/initial_targets.ex#L1)

Check 3 (spec 3.2, 3.3, 3.6): every `initial` reference - a state's
`initial` attribute, a state's `<initial>` element, and the document's own
root `initial` attribute - resolves and lands on a legal target. Three
reasons, in this precedence:

1. `{:initial_on_atomic_state, id}`: a state carrying
   `initial` or `initial_element` that has nothing to default into - an
   empty `states` list, or a `:parallel`, `:final`, or `:history` kind.
   `id` is the state's own id, `nil` for a state with no `id`.
   Fires first and **suppresses every other reason for that state**: an
   atomic state's initial cannot be resolved, checked for descendancy, or
   anything else, so reporting more than this one error would be two
   errors for one mistake.
2. `{:unresolved_initial, id}`: an id in `State.initial` or
   `Document.initial` absent from `Context.states`. `id` is that missing
   target, so a containing state with no `id` reports it the same way.
   An `<initial>`
   element's own transition targets are **not** re-checked here for
   existence - check 2 already owns that; this check only
   asks `Context.states` the same question check 2 already answered, so
   it can skip the descendancy test below rather than re-reporting.
3. `{:initial_not_descendant, id, parent_id}`: a resolved target - from
   `State.initial` or from an `<initial>` element's transitions - that is
   not among the containing state's descendants (ancestry all the way
   up, not direct-child membership - spec 3.3/3.6 both say
   "descendants", which is where v1 is wrong). Descendancy is decided by
   the tree's structure (`Context.inside?/3`) for every containing state,
   with or without an `id`, the rule the History check keeps for a
   history's parent: a state that shares its `id` with another is not
   credited with the other's children, and a containing state with no
   `id` reports a `nil` `parent_id`. Such a state answers every reason here:
   `unresolved_initial` carries the missing target, and the two reasons
   that carry the state's own id (`initial_on_atomic_state`'s `id`,
   `initial_not_descendant`'s `parent_id`) carry `nil`. This check has
   **no analog** for
   `Document.initial`: spec 3.11's
   "additional requirement" ("all the states MUST be descendants of the
   containing `<state>` or `<parallel>` element") is written for `<state>`
   `initial` and for a `<transition>` inside `<initial>`/`<history>` only -
   `<scxml>` is named in neither. The root's own `initial` (spec 3.2.1) is
   typed only as "a legal state specification" (spec 3.11), which for a
   single resolved id demands nothing beyond existing - `enterStates`
   (Appendix D) walks up from any resolved target and adds its ancestors
   regardless of how deep it sits, so a document-level `initial` naming a
   descendant several levels down is legal and enters that descendant with
   every ancestor auto-added. There used to be a fourth reason here,
   `{:initial_not_top_level, id}`, requiring a resolved `Document.initial`
   id to be a direct child of `<scxml>`; it is gone because the spec never
   asked for that restriction - `check_document_initial/2` below now stops
   at existence.

# `check`

```elixir
@spec check(
  document :: Statifier.Document.t(),
  context :: Statifier.Validator.Context.t()
) :: [
  Statifier.Validator.Error.t()
]
```

Returns, per state and for the document's own root `initial` attribute, one
of `:initial_on_atomic_state` (the initial reference has nothing to default
into and suppresses every other reason for that state),
`:unresolved_initial` (the id does not resolve in `Context.states`), or
`:initial_not_descendant` (a resolved target is not a descendant of the
containing state - never fired for `Document.initial`, which has no
containing state to be a descendant of). Returns `[]` when every `initial`
reference in the document resolves and lands on a legal target.

---

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