diff --git a/bot_bottle/backend/resolve_common.py b/bot_bottle/backend/resolve_common.py index 612291b..7ea9c14 100644 --- a/bot_bottle/backend/resolve_common.py +++ b/bot_bottle/backend/resolve_common.py @@ -29,7 +29,7 @@ from ..git_gate import GitGate, GitGatePlan from ..log import die from ..manifest import Manifest, ManifestBottle from ..supervisor.plan import SupervisePlan -from ..orchestrator.supervisor.supervise import Supervise +from ..orchestrator.supervisor import Supervisor from . import BottleSpec @@ -102,7 +102,7 @@ def prepare_supervise(bottle: ManifestBottle, slug: str) -> SupervisePlan | None return None supervise_dir = supervise_state_dir(slug) supervise_dir.mkdir(parents=True, exist_ok=True) - return Supervise().prepare(slug, supervise_dir) + return Supervisor().prepare(slug, supervise_dir) def merge_provision_env_vars(provision: AgentProvisionPlan) -> AgentProvisionPlan: diff --git a/bot_bottle/image_cache.py b/bot_bottle/image_cache.py index ff16544..65538e3 100644 --- a/bot_bottle/image_cache.py +++ b/bot_bottle/image_cache.py @@ -5,10 +5,7 @@ from __future__ import annotations from datetime import datetime, timezone from pathlib import Path -try: - from .store.config_store import ConfigStore -except ImportError: - from config_store import ConfigStore # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module +from .store.config_store import ConfigStore class StaleImageError(Exception): diff --git a/bot_bottle/orchestrator/store/queue_store.py b/bot_bottle/orchestrator/store/queue_store.py index 16637f9..a8428e3 100644 --- a/bot_bottle/orchestrator/store/queue_store.py +++ b/bot_bottle/orchestrator/store/queue_store.py @@ -6,16 +6,10 @@ import os import sqlite3 from pathlib import Path -try: - from ...supervisor.types import Proposal, Response - from ...paths import host_db_path - from ...store.db_store import DbStore - from ...store.migrations import TableMigrations -except ImportError: - from supervisor.types import Proposal, Response # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module - from paths import host_db_path # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module - from db_store import DbStore # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module - from migrations import TableMigrations # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module +from ...supervisor.types import Proposal, Response +from ...paths import host_db_path +from ...store.db_store import DbStore +from ...store.migrations import TableMigrations class QueueStore(DbStore): diff --git a/bot_bottle/orchestrator/supervisor/__init__.py b/bot_bottle/orchestrator/supervisor/__init__.py index c6d903e..e222677 100644 --- a/bot_bottle/orchestrator/supervisor/__init__.py +++ b/bot_bottle/orchestrator/supervisor/__init__.py @@ -1,10 +1,10 @@ """The orchestrator's view of the supervise plane. Bundles the orchestrator-owned supervise surface: the queue/audit I/O and diff -rendering (`queue`) and the `Supervise` lifecycle (`supervise`). For -convenience it re-exports the neutral vocabulary (`bot_bottle.supervisor`'s -types + `SupervisePlan`) so orchestrator-side callers — service, CLI, tests — -import from one place. +rendering (`queue`), and the `Supervisor` lifecycle (host-side database +staging). For convenience it re-exports the neutral vocabulary +(`bot_bottle.supervisor`'s types + `SupervisePlan`) so orchestrator-side +callers — service, CLI, tests — import from one place. The data plane must NOT import this package; it imports `bot_bottle.supervisor` (neutral) directly and reaches the queue over the control-plane RPC. @@ -12,8 +12,12 @@ The data plane must NOT import this package; it imports `bot_bottle.supervisor` from __future__ import annotations +from abc import ABC +from pathlib import Path + from ...supervisor.types import * # noqa: F401,F403 — re-export the neutral vocabulary from ...supervisor.plan import SupervisePlan +from ..store.store_manager import StoreManager from .queue import ( archive_all_proposals, archive_proposal, @@ -31,4 +35,22 @@ from .queue import ( write_proposal, write_response, ) -from .supervise import Supervise + + +class Supervisor(ABC): + """Per-bottle supervise lifecycle. Encapsulates host-side database staging; + the gateway's start/stop lifecycle is backend-specific. + + `prepare` migrates the orchestrator's `bot-bottle.db` and returns the + neutral `SupervisePlan`. It touches the orchestrator store manager, so it + lives here rather than in the neutral `bot_bottle.supervisor` package; the + backend (which drives launch) may import it — backend → orchestrator is an + allowed direction, unlike gateway → orchestrator.""" + + def prepare(self, slug: str, stage_dir: Path) -> SupervisePlan: + """Stage the host database. Returns the plan; `internal_network` must be + set by the launch step before .start runs.""" + del stage_dir + mgr = StoreManager.instance() + mgr.migrate() + return SupervisePlan(slug=slug, db_path=mgr.db_path) diff --git a/bot_bottle/orchestrator/supervisor/supervise.py b/bot_bottle/orchestrator/supervisor/supervise.py deleted file mode 100644 index f2e51fe..0000000 --- a/bot_bottle/orchestrator/supervisor/supervise.py +++ /dev/null @@ -1,36 +0,0 @@ -"""The `Supervise` lifecycle — host-side database staging (PRD 0013 / 0070). - -`Supervise.prepare` migrates the orchestrator's `bot-bottle.db` and returns the -neutral `SupervisePlan`. It touches the orchestrator store manager, so it lives -here rather than in the neutral `bot_bottle.supervisor` package; the backend -(which drives launch) may import it — backend → orchestrator is an allowed -direction, unlike gateway → orchestrator. -""" - -from __future__ import annotations - -from abc import ABC -from pathlib import Path - -from ..store.store_manager import StoreManager -from ...supervisor.plan import SupervisePlan - - -class Supervise(ABC): - """Per-bottle supervise daemon. Encapsulates host-side database staging; - the gateway's start/stop lifecycle is backend-specific.""" - - def prepare( - self, - slug: str, - stage_dir: Path, - ) -> SupervisePlan: - """Stage the host database. Returns the plan; `internal_network` must be - set by the launch step before .start runs.""" - del stage_dir - mgr = StoreManager.instance() - mgr.migrate() - return SupervisePlan( - slug=slug, - db_path=mgr.db_path, - ) diff --git a/bot_bottle/store/audit_store.py b/bot_bottle/store/audit_store.py index 3a6738b..d80451b 100644 --- a/bot_bottle/store/audit_store.py +++ b/bot_bottle/store/audit_store.py @@ -5,16 +5,10 @@ from __future__ import annotations import sqlite3 from pathlib import Path -try: - from ..supervisor.types import AuditEntry - from ..paths import host_db_path - from .db_store import DbStore - from .migrations import TableMigrations -except ImportError: - from supervisor.types import AuditEntry # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module - from paths import host_db_path # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module - from db_store import DbStore # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module - from migrations import TableMigrations # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module +from ..supervisor.types import AuditEntry +from ..paths import host_db_path +from .db_store import DbStore +from .migrations import TableMigrations class AuditStore(DbStore): diff --git a/bot_bottle/store/config_store.py b/bot_bottle/store/config_store.py index d282d71..8d7811e 100644 --- a/bot_bottle/store/config_store.py +++ b/bot_bottle/store/config_store.py @@ -4,14 +4,9 @@ from __future__ import annotations from pathlib import Path -try: - from .db_store import DbStore - from .migrations import TableMigrations - from ..paths import host_db_path -except ImportError: - from db_store import DbStore # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module - from migrations import TableMigrations # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module - from paths import host_db_path # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module +from .db_store import DbStore +from .migrations import TableMigrations +from ..paths import host_db_path DEFAULT_CACHED_IMAGE_STALE_WARNING_DAYS = 1 diff --git a/bot_bottle/store/db_store.py b/bot_bottle/store/db_store.py index 256f29e..49bcced 100644 --- a/bot_bottle/store/db_store.py +++ b/bot_bottle/store/db_store.py @@ -6,10 +6,7 @@ import sqlite3 from contextlib import contextmanager from pathlib import Path -try: - from .migrations import TableMigrations -except ImportError: - from migrations import TableMigrations # type: ignore[import-not-found] # pylint: disable=import-error,no-name-in-module +from .migrations import TableMigrations class DbVersionError(Exception): diff --git a/bot_bottle/supervisor/__init__.py b/bot_bottle/supervisor/__init__.py index d76c1e9..7d002f9 100644 --- a/bot_bottle/supervisor/__init__.py +++ b/bot_bottle/supervisor/__init__.py @@ -11,6 +11,6 @@ tier's private code, importable by `bot_bottle.gateway` **and** status / poll-status constants, and the shared daemon constants. * `plan` — `SupervisePlan`, the launch-time staging DTO. -The orchestrator-only half (queue I/O, diff rendering, the `Supervise` +The orchestrator-only half (queue I/O, diff rendering, the `Supervisor` lifecycle) lives under `bot_bottle.orchestrator.supervisor`. """ diff --git a/bot_bottle/supervisor/plan.py b/bot_bottle/supervisor/plan.py index 2962d82..e61cf91 100644 --- a/bot_bottle/supervisor/plan.py +++ b/bot_bottle/supervisor/plan.py @@ -1,9 +1,9 @@ """`SupervisePlan` — the launch-time supervise staging DTO. A pure value type (no store access), so it lives in the neutral package: the -backend builds it at launch and the orchestrator's `Supervise.prepare` returns +backend builds it at launch and the orchestrator's `Supervisor.prepare` returns it. The behaviour that fills it in — staging the host database — is the -orchestrator's, in `bot_bottle.orchestrator.supervisor.supervise`. +orchestrator's, in `bot_bottle.orchestrator.supervisor.Supervisor`. """ from __future__ import annotations @@ -14,7 +14,7 @@ from pathlib import Path @dataclass(frozen=True) class SupervisePlan: - """Output of `Supervise.prepare`; consumed by `.start`. + """Output of `Supervisor.prepare`; consumed by `.start`. `db_path` is the host database bind-mounted into the gateway at /run/supervise/bot-bottle.db. `internal_network` is empty at prepare time; diff --git a/tests/unit/test_supervise.py b/tests/unit/test_supervise.py index f0f41be..7dbdb68 100644 --- a/tests/unit/test_supervise.py +++ b/tests/unit/test_supervise.py @@ -352,7 +352,7 @@ class TestToolConstants(unittest.TestCase): ) -class _StubSupervise(supervise.Supervise): +class _StubSupervise(supervise.Supervisor): """Concrete Supervise subclass for testing the prepare template.""" def start(self, plan): # type: ignore