# `DripDrop.Dispatch.Idempotency`
[🔗](https://github.com/agoodway/dripdrop/blob/v0.1.0/lib/dripdrop/dispatch/idempotency.ex#L1)

Builds deterministic idempotency keys for step execution scheduling.

# `key`

```elixir
@spec key(
  Ecto.UUID.t() | binary(),
  Ecto.UUID.t() | binary(),
  DateTime.t() | NaiveDateTime.t(),
  integer()
) :: binary()
```

Returns the SHA-256 idempotency key for an enrollment, step, minute, and attempt.

# `sql_call`

```elixir
@spec sql_call(binary(), binary()) :: binary()
```

Returns the schema-qualified call expression for the `idempotency_key` SQL
function. Both the bulk seed `INSERT ... SELECT` path and the parity test
use this — the SQL function is the single source of truth for how a digest
is formed, eliminating Elixir/SQL drift under non-UTC server timezones.

`enrollment_expr` is the SQL expression to use as the enrollment-id argument
(e.g. `"enrollments.id"` for the bulk path, `"$4::uuid"` for tests).

Positional parameters in the returned expression: `$1` step id, `$2`
scheduled-for timestamp, `$3` attempt window.

---

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