Skip to content

ADR 022 Bounded On-Demand Starlight Runtime

The stage docs-dev container started on every Mutagen project launch. Its restart: unless-stopped policy combined with astro dev --force turned a missing contract-source mount into a tight TypeDoc failure loop. Every restart reinstalled workspace state, forced Astro dependency optimization, failed on /workspace/contract-repo, and restarted again. This consumed CPU and memory without serving documentation.

Starlight preview is a human review tool. Contract, backend, and booking stage work must not require a persistent documentation watcher.

docs-dev uses the explicit Compose profile docs. Default Mutagen stage startup excludes it. Operators start and stop it through generated docs-up, docs-stop, and docs-logs commands or the equivalent Compose commands.

The service:

  1. waits for both assembly and contract Mutagen source volumes;
  2. mounts contract source read-only for TypeDoc and OpenAPI generation;
  3. runs root pnpm docs:dev without Astro --force rebuilding;
  4. uses restart: "no" so configuration failures stay visible and finite;
  5. caps CPU, container memory, and V8 old-space through stage env; and
  6. remains absent after normal stage recreation unless explicitly requested.

CI and migration control loops use finite pnpm docs:check and pnpm docs:build commands. They do not start a watcher or deploy documentation.

  • docker compose ... config --quiet validates the profiled service.
  • pnpm stage:check enforces profile, restart policy, source mount, resource limits, heap cap, non-forced command, and Mutagen default exclusion.
  • Generated Mutagen project config contains explicit docs commands and no docs-dev entry in beforeCreate.

Normal backend and E2E work no longer pays Starlight watcher cost. A broken TypeDoc or OpenAPI configuration exits once instead of creating a crash loop. Human preview needs an explicit start command and is bounded if a plugin leaks.

  • 2026-07-11: accepted on-demand, resource-bounded Starlight preview runtime.