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

Immutable managed execution intent; host code supplies policy and artifact approval.

The runtime artifact map contains exactly `id`, `sha256`, and `architecture`
(`x86_64` or `aarch64`). It is resolved against host configuration, never fetched
as a caller-provided image URL. The specification contains no endpoint overrides.

Queue budgets are relative at construction; the store must persist an absolute
deadline on first acceptance. Repeated submission never resets that deadline.
`fingerprint/2` uses a stable host secret (at least 32 bytes) to prevent guessing
low-entropy environment/stdin values from a public hash. Rotate this key only
with an explicit stored-identity migration. Do not log or persist its bytes.

The host store must protect command/environment/stdin contents at rest; inspection
of this struct excludes them. Metadata is limited to 16 bounded scalar entries.

# `t`

```elixir
@type t() :: %SmolBox.ExecutionSpec{
  artifact: %{required(String.t()) =&gt; String.t()},
  command: SmolBox.Command.t(),
  id: String.t(),
  inputs: [SmolBox.Manifest.input()],
  metadata: %{required(String.t()) =&gt; String.t() | integer() | boolean() | nil},
  outputs: [SmolBox.Manifest.output()],
  profile: SmolBox.Profile.t(),
  queue_ms: pos_integer(),
  retention_ms: pos_integer(),
  scope: String.t()
}
```

# `fingerprint`

```elixir
@spec fingerprint(t(), binary()) :: {:ok, String.t()} | {:error, SmolBox.Error.t()}
```

Fingerprint every semantic field with domain separation and a host-owned secret.

# `new`

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

Validate a complete managed execution specification without dispatching it.

Required options are `:scope`, `:id`, `:command` (`SmolBox.Command`), `:profile`
(`SmolBox.Profile`), and `:artifact`. Scope and ID are 1–128 ASCII letters,
digits, dots, underscores, colons or hyphens, starting with a letter/digit.
The artifact has exactly string keys `"id"`, `"sha256"`, and `"architecture"`;
its approved worker path is resolved from `SmolBox.Runtime.WorkerConfig`.

| Optional field | Default | Meaning |
|---|---|---|
| `:inputs` | `[]` | Up to 32 exact input declarations; see `SmolBox.Manifest` |
| `:outputs` | `[]` | Up to 32 exact output declarations; see `SmolBox.Manifest` |
| `:queue_ms` | `60_000` | 1–86,400,000 ms from first acceptance until queue expiry |
| `:retention_ms` | `86_400_000` | 60,000–2,592,000,000 ms after the execution deadline for unknown-outcome retention |
| `:metadata` | `%{}` | Up to 16 string identifier keys with string (up to 256 bytes), bounded integer, boolean or nil values |

The command timeout in seconds must fit the profile's execution budget in
milliseconds. Successful construction proves shape and bounds, not worker
availability or artifact approval; `SmolBox.submit/2` checks configured support.
All semantic fields participate in identity conflict detection.

## Example

    iex> {:ok, command} = SmolBox.Command.new(["python", "-c", "print(42)"])
    iex> {:ok, profile} = SmolBox.Profile.new("offline-v1", storage_gb: 20, overlay_gb: 10, host_overhead_mb: 768)
    iex> artifact = %{"id" => "python-v1", "sha256" => SmolBox.Files.sha256("example image bytes"), "architecture" => "aarch64"}
    iex> {:ok, spec} = SmolBox.ExecutionSpec.new(scope: "demo", id: "request-1", command: command, profile: profile, artifact: artifact)
    iex> {spec.scope, spec.id, spec.queue_ms}
    {"demo", "request-1", 60_000}

The digest above is only a constructor example. Actual execution requires the
digest of an approved prepared image, as shown in [Getting started](getting-started.html).

# `validate`

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

Revalidate a specification, including its command, profile, file declarations and budgets.

---

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