# Rollout rules

When you deploy a new image (or change anything in the pod template), running units become **stale**. The policy's `rollout` decides how they are replaced.

| Rule | Behaviour | Use it for |
|---|---|---|
| `rolling` | Replace stale units in batches, new unit first. Capacity never dips | stateless APIs, workers |
| `replace_idle` | Replace now every stale unit that is **not allocated and not busy**, at most a quarter of the units at a time and never below `min_units` ready. Allocated or busy units are replaced **when they end**: by their exit, stop or destroy, or at their next `idle` signal | lobbies, matches |
| `next_start` | Leave running units alone. The change applies the next time the platform creates a pod for that unit: a start after a stop, a lost pod, a new warm unit | private worlds, plots |

`replace_idle` needs signals: without them, "idle" cannot be known, and the policy is refused with `invalid-field-value` (`details` starts `replace_idle_needs_signals`). It is the default for `code` mode.

Mixed versions are normal under `replace_idle` and `next_start`. Allocate prefers units already on the newest template, and the console shows how many units still run the old one.

## Read the status

`GET .../units/policy` reports the rollout:

```json
{
  "rollout": "replace_idle",
  "rollout_status": {
    "strategy": "replace_idle",
    "target_template": "9c1f...",
    "stale_units": 2,
    "replaced_units": 7,
    "waiting_on": [{"key": "duel-81", "why": "allocated"}],
    "started_at": "2026-10-14T10:00:00Z"
  }
}
```

and the event log carries `rollout.started`, `rollout.completed` and `rollout.paused` (a replacement failed). `rollout_status` is in the API reference as `RolloutStatusResponse`.

## Pick one

- A match must never be cut short and units are short-lived: `replace_idle`.
- Each unit holds a player's world and may sit stopped for weeks: `next_start`.
- Units are interchangeable and stateless: `rolling`.
