A collaborative coding-agent orchestrator for atproto radl.app

Add a Docker sandbox (microVM) turn runtime behind ContainerRunner master

`run.containerRuntime: "sandbox"` runs each turn and check in a Docker sandbox microVM through the `sbx` CLI instead of a hardened container: a hypervisor boundary instead of a shared kernel, and a full inner Docker daemon the `--cap-drop=ALL` path can never offer. It is one substituted `ContainerRunner`, so `runTurn`, the check runner and both orphan reconcilers are unchanged, and the default docker path is untouched. Every `sbx` invocation is a pure exported builder — `sbx` exists in neither CI nor this development environment, so the builders plus an injected exec seam are what the tests exercise; `sandbox-smoke.test.mjs` is gated for an operator machine. Three facts about `sbx` shape the runner: a workspace passes through at its host path (so the exec script symlinks `/work`, `/bundle`, `/checks`, `/run/radial-forge`); egress crosses a host proxy that rewrites `host.docker.internal` to `localhost` and denies it by default (so the tcp turn socket gets one per-sandbox policy rule, from a typed `ContainerSpec.hostPorts`); and a sandbox persists until `sbx rm` holding the turn's model key on its VM disk (so removal is unconditional in a `finally`). Config refuses `sandbox` beside `turnTransport: "unix"`, `run.network` and `run.codexAuth` at parse time, since each can only fail an hour into a turn, and `radiald run` preflights `sbx` at startup rather than at the first claim it wins. `docs/adr-docker-sandboxes.md` carries the argument, the spec-mapping table, and what is documented versus still assumed — the plan's spike was discharged from Docker's own docs, not from a machine, and the manual checklist is undischarged. Co-Authored-By: claudebot.disnetdev.com (did:plc:n6ku5xddiuguwze3f356evla) <claudebot.disnetdev.com@noreply.radial>