# Parallel sandbox provisioning — design

audience: AI coding agents first. Implementer: codex (`-m gpt-5.6-terra -c model_reasoning_effort=medium`).
Owner intent: image rollouts serialize minutes of one-core work per box while the other
boxes and cores sit idle; provisioning must use the estate.

## Context (measured 2026-08-16, four rollouts in one day)

`modules/workstation/claude/bin/sandbox-provision` (~235 lines): rsyncs the image context
to each box, then each box runs `sandbox-image-build` locally (single-core gzip/digest
dominated), inside a strictly sequential `for host in "${HOSTS[@]}"` loop — for probe,
rsync, and build/verify phases alike. Wall clock ≈ N_boxes × per-box time. Identical
context produces an identical content-keyed tag on every box, so box builds are
independent by construction.

## Contract

1. **Per-host fan-out.** Every per-host phase (probe, rsync, remote build/verify) runs
   concurrently — one subshell per host, `wait` collecting ALL exit codes (never
   fail-fast-and-abandon: a box that fails is reported by name while the others finish).
   Per-host output goes to a per-host log file under the existing run/state dir and is
   replayed grouped after `wait`, so interleaved lines never corrupt the report. The
   final converged/drifted summary keeps its exact current format — deploy-local parses
   it (verify the consumer contract in `packaging/deploy-local.sh` before changing one
   byte of it).
2. **Concurrency cap = number of hosts** (3 today). No new config knob unless one already
   exists nearby; the registry list is the bound.
3. **Workstation-side steps stay serial** (staging, tag computation) — they are seconds.
4. **Idempotence unchanged:** a box whose recorded tag+image already match skips the
   build exactly as today.

## Out of scope

zstd/compression-format changes (separate measurement first); a central registry
(pulls instead of per-box builds — that is the k3s-lane answer, `2026-08-16-k3s-unpark.md`
step 4 territory); any change to image content or tags.

## Acceptance

- `bash -n` clean; existing sandbox host tests green.
- Timed proof on the real estate: one full `sandbox-provision --all` after touching the
  image context, before vs after, wall-clock recorded in the receipt — expected ≈3× on
  the per-host phase.
- Failure honesty proof: with one box's ssh alias broken, the run reports that box FAILED
  by name, the other two still converge, and exit code is non-zero.
