refactor(supervise): split the supervise plane by tier; per-service store managers
test / integration-docker (pull_request) Successful in 13s
tracker-policy-pr / check-pr (pull_request) Successful in 14s
test / unit (pull_request) Successful in 42s
lint / lint (push) Failing after 54s
test / integration-firecracker (pull_request) Successful in 3m17s
test / coverage (pull_request) Successful in 17s
test / publish-infra (pull_request) Has been skipped

Give each service its own store package + manager, and cut the supervise module
along the control/data-plane boundary so nothing in the shared layer reaches up
into the orchestrator.

Stores, by owner:
  - bot_bottle/store/ keeps only the shared base (DbStore, migrations) and the
    concrete stores that aren't service-owned (audit_store, config_store).
  - bot_bottle/orchestrator/store/ now houses the orchestrator-owned stores —
    queue_store (supervise queue), secret_store, config_store — plus a new
    orchestrator store_manager that migrates them (composing audit/config
    downward from the base). The old shared store_manager is gone.

Supervise plane, by tier:
  - bot_bottle/supervisor/ (NEUTRAL, importable by every tier including the
    gateway): types.py (the Proposal/Response/AuditEntry wire types + the tool/
    status/poll constants + the shared daemon constants moved out of
    supervise.py) and plan.py (SupervisePlan, a pure DTO).
  - bot_bottle/orchestrator/supervisor/ (orchestrator-only): queue.py (the
    queue/audit I/O wrappers + render_diff + sha256_hex) and supervise.py (the
    Supervise lifecycle that stages the DB via the store manager). Its __init__
    re-exports the neutral vocabulary so orchestrator-side callers import from
    one place.

The gateway now imports only bot_bottle.supervisor.types (never
bot_bottle.supervise), so the data plane holds no code dependency on the
orchestrator — it reaches the queue over the control-plane RPC. This removes
the circular import that moving queue_store under orchestrator introduced
(supervise -> orchestrator -> service -> supervise).

supervise_types.py -> supervisor/types.py; supervise.py deleted (split). Full
unit suite green (2251).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 14:15:04 -04:00
parent f77023db1d
commit 44e2b5a897
52 changed files with 380 additions and 385 deletions
+1 -1
View File
@@ -91,7 +91,7 @@ class TestGatewayImage(unittest.TestCase):
# Probe that the package imports resolve inside the image.
rc, out = self._run_in_image(
"python3", "-c",
"from bot_bottle import supervise; from bot_bottle.gateway import supervise_server; print('ok')",
"from bot_bottle.supervisor import types; from bot_bottle.gateway import supervise_server; print('ok')",
)
self.assertEqual(0, rc, msg=out)
self.assertIn("ok", out)
+1 -1
View File
@@ -16,7 +16,7 @@ from bot_bottle.backend.docker.bottle_plan import DockerBottlePlan
from bot_bottle.egress import EgressPlan, EgressRoute
from bot_bottle.git_gate import GitGatePlan, GitGateUpstream
from bot_bottle.manifest import ManifestIndex
from bot_bottle.supervise import SupervisePlan
from bot_bottle.supervisor.plan import SupervisePlan
SLUG = "demo-abc12"
+1 -1
View File
@@ -15,7 +15,7 @@ from bot_bottle.cli import main
from bot_bottle.store.db_store import DbStore
from bot_bottle.log import Die
from bot_bottle.manifest import ManifestError
from bot_bottle.store.store_manager import StoreManager
from bot_bottle.orchestrator.store.store_manager import StoreManager
class TestMainDispatch(unittest.TestCase):
+1 -1
View File
@@ -11,7 +11,7 @@ from bot_bottle.store.config_store import (
DEFAULT_CACHED_IMAGE_STALE_WARNING_DAYS,
ConfigStore,
)
from bot_bottle.store.store_manager import StoreManager
from bot_bottle.orchestrator.store.store_manager import StoreManager
class TestConfigStore(unittest.TestCase):
+1 -1
View File
@@ -25,7 +25,7 @@ from bot_bottle.contrib.claude.agent_provider import ClaudeAgentProvider
from bot_bottle.egress import EgressPlan
from bot_bottle.git_gate import GitGatePlan
from bot_bottle.manifest import ManifestIndex
from bot_bottle.supervise import SupervisePlan
from bot_bottle.supervisor.plan import SupervisePlan
_URL = "http://supervise:9100/"
+1 -1
View File
@@ -25,7 +25,7 @@ from bot_bottle.contrib.codex.agent_provider import CodexAgentProvider
from bot_bottle.egress import EgressPlan
from bot_bottle.git_gate import GitGatePlan
from bot_bottle.manifest import ManifestIndex
from bot_bottle.supervise import SupervisePlan
from bot_bottle.supervisor.plan import SupervisePlan
_URL = "http://supervise:9100/"
+1 -1
View File
@@ -15,7 +15,7 @@ import unittest
from pathlib import Path
from types import ModuleType
from bot_bottle.orchestrator.config_store import (
from bot_bottle.orchestrator.store.config_store import (
DEFAULT_TEARDOWN_TIMEOUT_SECONDS,
TEARDOWN_TIMEOUT_ENV,
OrchestratorConfigStore,
@@ -24,8 +24,8 @@ from bot_bottle.orchestrator.broker import StubBroker
from bot_bottle.orchestrator.control_plane import dispatch, make_server
from bot_bottle.orchestrator.registry import BottleRecord, RegistryStore
from bot_bottle.orchestrator.service import Orchestrator
from bot_bottle.store.store_manager import StoreManager
from bot_bottle.supervise import (
from bot_bottle.orchestrator.store.store_manager import StoreManager
from bot_bottle.orchestrator.supervisor import (
Proposal,
TOOL_EGRESS_ALLOW,
sha256_hex,
+1 -1
View File
@@ -4,7 +4,7 @@ from __future__ import annotations
import unittest
from bot_bottle.orchestrator.secret_store import (
from bot_bottle.orchestrator.store.secret_store import (
ENV_VAR_SECRET_NAME,
decrypt_value,
encrypt_value,
+3 -3
View File
@@ -14,9 +14,9 @@ from unittest.mock import patch
from bot_bottle.orchestrator.broker import LaunchBroker, LaunchRequest, StubBroker
from bot_bottle.orchestrator.registry import RegistryStore
from bot_bottle.orchestrator.service import Orchestrator
from bot_bottle.orchestrator.secret_store import new_env_var_secret
from bot_bottle.store.store_manager import StoreManager
from bot_bottle.supervise import (
from bot_bottle.orchestrator.store.secret_store import new_env_var_secret
from bot_bottle.orchestrator.store.store_manager import StoreManager
from bot_bottle.orchestrator.supervisor import (
Proposal,
STATUS_APPROVED,
TOOL_EGRESS_ALLOW,
+3 -3
View File
@@ -7,12 +7,12 @@ import unittest
from datetime import datetime, timezone
from pathlib import Path
from bot_bottle import supervise
from bot_bottle.orchestrator import supervisor as supervise
from bot_bottle.paths import host_db_path
from tests.unit import use_bottle_root
from bot_bottle.store.audit_store import AuditStore
from bot_bottle.store.queue_store import QueueStore
from bot_bottle.supervise import (
from bot_bottle.orchestrator.store.queue_store import QueueStore
from bot_bottle.orchestrator.supervisor import (
AuditEntry,
Proposal,
Response,
+1 -1
View File
@@ -13,7 +13,7 @@ from datetime import datetime, timezone
from unittest.mock import MagicMock, patch
from bot_bottle.cli import supervise as supervise_cli
from bot_bottle.supervise import (
from bot_bottle.orchestrator.supervisor import (
Proposal,
TOOL_EGRESS_ALLOW,
TOOL_EGRESS_BLOCK,
+3 -3
View File
@@ -10,11 +10,11 @@ import unittest
from pathlib import Path
from unittest.mock import patch
from bot_bottle import supervise
from bot_bottle.orchestrator import supervisor as supervise
from bot_bottle.store.audit_store import AuditStore
from bot_bottle.paths import bot_bottle_root
from bot_bottle.store.queue_store import QueueStore
from bot_bottle.supervise import (
from bot_bottle.orchestrator.store.queue_store import QueueStore
from bot_bottle.orchestrator.supervisor import (
AuditEntry,
Proposal,
STATUS_APPROVED,
+2 -2
View File
@@ -18,8 +18,8 @@ from pathlib import Path
from tests.unit import use_bottle_root
from bot_bottle import supervise as _sv
from bot_bottle.store import queue_store as _qs
from bot_bottle.orchestrator import supervisor as _sv
from bot_bottle.orchestrator.store import queue_store as _qs
from bot_bottle.store import audit_store as _as
from bot_bottle.gateway import supervise_server # noqa: E402