feat(orchestrator): slice 13a — orchestrator process lifecycle (idempotent singleton) #369

Closed
didericis-claude wants to merge 1 commits from orchestrator-lifecycle into orchestrator-supervise-writers
Collaborator

First sub-slice of slice 13 (docker launch integration) — the keystone that wires consolidated mode into the real launch path. Slice 13 is too big for one PR (it rewires prepare/launch/teardown and deletes the per-bottle bundle), so it's decomposed:

  • 13a (this PR) — orchestrator process lifecycle. Foundational; does not touch the real launch path.
  • 13b — registration wiring: launch_bottle places the bottle's egress policy + git-gate repos/creds into the shared gateway; deterministic source IP.
  • 13c — agent-only launch on the gateway network with BOT_BOTTLE_ORCHESTRATOR_URL + egress proxy pointed at the shared gateway.
  • 13d — cut get_bottle_backend('docker')/prepare/launch/teardown over; delete the bundle (no fallback).
  • 14 — e2e test_sandbox_escape.

This PR

OrchestratorProcess — the primitive the CLI needs to guarantee one orchestrator control plane + its shared gateway is up before it can register/launch bottles.

  • ensure_running() is an idempotent singleton: returns the control-plane URL if a healthy one already answers GET /health, else spawns python -m bot_bottle.orchestrator --broker docker --gateway detached (start_new_session, output tee'd to <root>/orchestrator.log) and polls /health until healthy or timeout (OrchestratorStartError).
  • The control-plane port is the singleton key — a second orchestrator can't bind it, so a stray double-start fails fast rather than forking a rival.
  • Host-process, not container, per the PRD's dev-harness sequencing: it already has the host user's docker access to broker launches, while the data-plane gateway it manages runs as a container.

Verification

pyright 0 errors, pylint 9.83/10, unit suite green (1714 tests; the 13 test_sidecar_init /bin/sleep errors are pre-existing NixOS-local noise). New tests cover the singleton no-op, spawn+wait, startup timeout, health check, and argv.

Stacked on #368.

🤖 Generated with Claude Code

First sub-slice of **slice 13 (docker launch integration)** — the keystone that wires consolidated mode into the real launch path. Slice 13 is too big for one PR (it rewires `prepare`/`launch`/`teardown` and deletes the per-bottle bundle), so it's decomposed: - **13a (this PR)** — orchestrator process lifecycle. *Foundational; does not touch the real launch path.* - **13b** — registration wiring: `launch_bottle` places the bottle's egress policy + git-gate repos/creds into the shared gateway; deterministic source IP. - **13c** — agent-only launch on the gateway network with `BOT_BOTTLE_ORCHESTRATOR_URL` + egress proxy pointed at the shared gateway. - **13d** — cut `get_bottle_backend('docker')`/`prepare`/`launch`/`teardown` over; delete the bundle (no fallback). - **14** — e2e `test_sandbox_escape`. ### This PR `OrchestratorProcess` — the primitive the CLI needs to guarantee one orchestrator control plane + its shared gateway is up before it can register/launch bottles. - `ensure_running()` is an **idempotent singleton**: returns the control-plane URL if a healthy one already answers `GET /health`, else spawns `python -m bot_bottle.orchestrator --broker docker --gateway` **detached** (`start_new_session`, output tee'd to `<root>/orchestrator.log`) and polls `/health` until healthy or timeout (`OrchestratorStartError`). - The **control-plane port is the singleton key** — a second orchestrator can't bind it, so a stray double-start fails fast rather than forking a rival. - **Host-process, not container**, per the PRD's dev-harness sequencing: it already has the host user's docker access to broker launches, while the data-plane *gateway* it manages runs as a container. ### Verification pyright **0 errors**, pylint **9.83/10**, unit suite green (1714 tests; the 13 `test_sidecar_init` `/bin/sleep` errors are pre-existing NixOS-local noise). New tests cover the singleton no-op, spawn+wait, startup timeout, health check, and argv. Stacked on #368. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
didericis-claude added 1 commit 2026-07-13 20:33:35 -04:00
feat(orchestrator): slice 13a — orchestrator process lifecycle (idempotent singleton)
lint / lint (push) Successful in 2m9s
test / unit (pull_request) Successful in 1m4s
test / integration (pull_request) Successful in 20s
test / coverage (pull_request) Successful in 1m14s
24df322c31
First sub-slice of docker launch integration: the foundation the CLI needs
to ensure exactly one orchestrator control plane + shared gateway is up
before registering/launching bottles. Does NOT touch the real launch path
yet — it's the lifecycle primitive the cut-over slices build on.

- OrchestratorProcess.ensure_running(): idempotent singleton — returns the
  control-plane URL if a healthy one already answers /health, else spawns
  `python -m bot_bottle.orchestrator --broker docker --gateway` detached
  (start_new_session, output tee'd to <root>/orchestrator.log) and polls
  /health until healthy or timeout (OrchestratorStartError).
- The control-plane port is the singleton key: a second orchestrator can't
  bind it, so a stray double-start fails fast rather than forking a rival.
- Host-process (not container) per the PRD's dev-harness sequencing — it
  already has the host user's docker access to broker launches; the
  data-plane gateway it manages is the container.

pyright 0 errors; pylint 9.83/10; unit suite green (1714 tests; the 13
test_sidecar_init /bin/sleep errors are pre-existing NixOS-local noise).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WBMWTEtQdJ4W5UrWuLHCck
Author
Collaborator

Collapsed into the single stack PR #380 (per-host orchestrator, PRD 0070). Closing this slice PR; review + merge happens on #380.

Collapsed into the single stack PR #380 (per-host orchestrator, PRD 0070). Closing this slice PR; review + merge happens on #380.
didericis-claude closed this pull request 2026-07-14 00:57:32 -04:00
Some checks are pending
lint / lint (push) Successful in 2m9s
test / unit (pull_request) Successful in 1m4s
test / integration (pull_request) Successful in 20s
test / coverage (pull_request) Successful in 1m14s

Pull request closed

Sign in to join this conversation.