# `Enact.Guardrails`
[🔗](https://github.com/svycal/enact/blob/v0.1.0/lib/enact/guardrails.ex#L1)

Mechanical enforcement of input-schema invariants — every "just don't
do X" rule that is detectable gets detected and raised, upgrading
conventions to invariants.

The runner invokes `assert_valid_input_schema!/2` automatically on an
action's first run (memoized per action). The memoization lives in
`:persistent_term` and survives dev code reloads, so editing an input
schema in a running server does not re-trigger the check until restart —
another reason host apps should *also* call it from a CI test on every
action's input module for compile-adjacent feedback:

    for action <- MyApp.Actions.all(), input = action.input() do
      Enact.Guardrails.assert_valid_input_schema!(input,
        mode: Keyword.get(action.config(), :mode, :create)
      )
    end

# `assert_valid_input_schema!`

Walks an input module recursively (through its embeds, with a cycle
guard for self-referential schemas) and raises a teaching error on:

1. any scalar field with a non-nil default (embed fields excluded —
   their structural `[]`/`nil` defaults are fine)
2. a primary key at any level
3. associations at any level — embeds only
4. top-level module only: missing `changeset/3` or `fields/1` exports,
   or missing `from_subject/1` when `mode: :patch` is given (nested item
   modules are exempt — they implement `changeset/2` for `cast_embed`)

Options: `:mode` — the referencing action's mode; `:patch` requires
`from_subject/1`.

---

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