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

Immutable, host-selected policy for disposable executions. Networking stays offline
unless an explicit `SmolBox.NetworkPolicy` is approved.

`id` identifies this exact policy revision. CPU and memory are guest allocations;
disk sizes are requested guest volumes, not worker filesystem quotas. The
worker's required `allocation_floor` must cover its actual disk templates;
upstream reports requests even when a larger template is retained. Host admission also
reserves `host_overhead_mb`. No CPU-time, host RSS, process-count, or host-disk
hard quota is promised. Requests for such controls are rejected as unsupported.
Worker qualification and host isolation remain prerequisites for managed use.

Budgets cover preparation, command observation, collection, and cleanup
separately. A socket timeout is never evidence of guest termination.

# `t`

```elixir
@type t() :: %SmolBox.Profile{
  cleanup_ms: pos_integer(),
  collection_ms: pos_integer(),
  cpus: pos_integer(),
  execution_ms: pos_integer(),
  host_overhead_mb: pos_integer(),
  id: String.t(),
  max_file_bytes: pos_integer(),
  max_output_bytes: pos_integer(),
  max_total_file_bytes: pos_integer(),
  memory_mb: pos_integer(),
  network: :offline | SmolBox.NetworkPolicy.t(),
  overlay_gb: pos_integer(),
  preparation_ms: pos_integer(),
  storage_gb: pos_integer()
}
```

# `machine`

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

Convert only the supported machine allocation controls.

# `new`

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

Create an immutable host-approved profile revision.

| Option | Default | Range/meaning |
|---|---|---|
| `:network` | `:offline` | Explicit `SmolBox.NetworkPolicy` allowlist |
| `:cpus` | `1` | 1–64 guest vCPUs |
| `:memory_mb` | `256` | 128–16,384 MiB guest allocation |
| `:storage_gb` | `1` | 1–64 GiB storage allocation |
| `:overlay_gb` | `1` | 1–64 GiB overlay allocation |
| `:host_overhead_mb` | `256` | 128–16,384 MiB additional admission reservation |
| `:max_output_bytes` | `1_048_576` | 1 byte–8 MiB of combined captured stdout/stderr |
| `:max_file_bytes` | `1_048_576` | 1 byte–1 MiB per declared file |
| `:max_total_file_bytes` | `4_194_304` | 1 byte–16 MiB per direction; must cover `:max_file_bytes` |
| `:preparation_ms` | `60_000` | First preparation stage budget |
| `:execution_ms` | `30_000` | Command observation budget |
| `:collection_ms` | `30_000` | Output collection budget |
| `:cleanup_ms` | `30_000` | Cleanup mutation budget, separate from unknown-outcome retention |

Each stage budget must be 1000–300,000 ms. A default profile is structurally
valid but its 1/1 GiB disks do **not** meet the reference SmolVM 1.14.1 template
floor. Use the actual operator-verified floor, as in the example below.

Give every changed policy a new `id`; managed submission matches the complete
profile against the worker's catalog. Unsupported hard quotas, mounts, ports,
GPU, restart or background options return `:unsupported_capability`. Invalid
network policies, including boolean networking flags, return `:validation`.

## Example

    iex> {:ok, profile} = SmolBox.Profile.new("offline-v1", storage_gb: 20, overlay_gb: 10, host_overhead_mb: 768)
    iex> {profile.storage_gb, profile.overlay_gb, profile.max_output_bytes}
    {20, 10, 1_048_576}

# `validate`

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

Revalidate profile shape and bounds; this does not attest worker enforcement.

---

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