# `SmolBox.Execution`
[🔗](https://github.com/hfiguera/smolbox/blob/v0.1.3/lib/smolbox/execution.ex#L1)

Versioned persisted execution evidence, independent of caller processes.

State, execution evidence, collection, and cleanup are separate dimensions.
Versioned store operations are the authority; this module only validates and
transforms records. A transition never sends a worker request. Dispatching may
advance directly to collecting when buffered exec returns a known exit.

Absolute stage deadlines are set on first entry and never reset by observation
or restart. Uncertain execution can have confirmed termination and completed
cleanup while its original command outcome remains unknown.

# `key`

```elixir
@type key() :: {String.t(), String.t()}
```

# `state`

```elixir
@type state() ::
  :accepted
  | :preparing
  | :ready
  | :dispatching
  | :running
  | :collecting
  | :completed
  | :collection_failed
  | :failed
  | :cancelled
  | :expired
  | :unknown
  | :cancelling
```

# `t`

```elixir
@type t() :: %SmolBox.Execution{
  absence_at_ms: non_neg_integer() | nil,
  accepted_at_ms: non_neg_integer(),
  artifacts: [map()],
  cancel_requested_at_ms: non_neg_integer() | nil,
  claim_owner: String.t() | nil,
  claim_until_ms: non_neg_integer() | nil,
  cleanup: :pending | :in_progress | :complete | :failed,
  cleanup_attempts: non_neg_integer(),
  collection: :pending | :complete | :partial | :failed,
  created_machine: SmolBox.Machine.t() | nil,
  deadlines: %{required(atom()) =&gt; non_neg_integer()},
  errors: [%{at_ms: non_neg_integer(), error: SmolBox.Error.t()}],
  evidence: atom(),
  fingerprint: String.t(),
  generation: non_neg_integer(),
  id: String.t(),
  last_error: SmolBox.Error.t() | nil,
  machine_name: String.t() | nil,
  next_due_at_ms: non_neg_integer(),
  reservation: %{required(atom()) =&gt; pos_integer()} | nil,
  result: SmolBox.Result.t() | nil,
  schema: 1,
  scope: String.t(),
  spec: SmolBox.ExecutionSpec.t(),
  state: state(),
  updated_at_ms: non_neg_integer(),
  version: pos_integer(),
  worker_generation: non_neg_integer() | nil,
  worker_id: String.t() | nil
}
```

# `expired?`

```elixir
@spec expired?(t(), non_neg_integer()) :: boolean()
```

Atomic store acceptance must call this before admission; queue expiry never dispatches.

# `key`

```elixir
@spec key(t()) :: key()
```

# `new`

```elixir
@spec new(SmolBox.ExecutionSpec.t(), String.t(), non_neg_integer()) ::
  {:ok, t()} | {:error, SmolBox.Error.t()}
```

# `terminal?`

```elixir
@spec terminal?(t()) :: boolean()
```

States that require no further command dispatch or outcome observation.

# `transition`

```elixir
@spec transition(t(), keyword(), non_neg_integer()) ::
  {:ok, t()} | {:error, SmolBox.Error.t()}
```

Validate a store patch; immutable identity, claims and reservations cannot be patched.

# `validate`

```elixir
@spec validate(term()) :: :ok | {:error, SmolBox.Error.t()}
```

Validate a persisted record after decoding it, including shapes that could contain BEAM resources.

---

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