docs: renumber PRD 0081 -> 0083 across the reconcile chunk
Follows the base PR's renumber (0081 was already taken; main is on 0082). Update every `PRD 0081` reference in the gateway-attach code, tests, and ADR 0006, plus ADR 0006's link to the PRD file. No behaviour change. Refs #516, #519. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -528,7 +528,7 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT, AttachTargetT]):
|
||||
|
||||
def attach_bottled_agents_to_gateway(self) -> None:
|
||||
"""Reconcile every running bottle against the freshly-(re)booted gateway
|
||||
on the cold-boot bring-up path (PRD 0081). The shared flow + fail-hard
|
||||
on the cold-boot bring-up path (PRD 0083). The shared flow + fail-hard
|
||||
policy live in `gateway_attach`; backends override only the three
|
||||
primitives below (ADR 0006)."""
|
||||
from .gateway_attach import reconcile_running_bottles
|
||||
|
||||
@@ -54,7 +54,7 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup
|
||||
|
||||
def __init__(self, *, infra: "DockerInfraService | None" = None) -> None:
|
||||
# The infra service whose gateway just cold-booted, passed in on the
|
||||
# bring-up reconcile path (PRD 0081) so `_gateway_attach_resources`
|
||||
# bring-up reconcile path (PRD 0083) so `_gateway_attach_resources`
|
||||
# reads THAT gateway's CA rather than a fresh default-named service —
|
||||
# otherwise a non-default instance (an isolated integration test's
|
||||
# `-itest-` gateway) reads the default `bot-bottle-orch-gateway`, which
|
||||
|
||||
@@ -272,7 +272,7 @@ class DockerGateway(Gateway):
|
||||
if self._control_network:
|
||||
self._connect_control_network()
|
||||
# (Re)created a fresh container — signal a cold boot so the caller
|
||||
# reconciles running bottles against it (PRD 0081).
|
||||
# reconciles running bottles against it (PRD 0083).
|
||||
return True
|
||||
|
||||
def _connect_control_network(self) -> None:
|
||||
|
||||
@@ -147,7 +147,7 @@ class DockerInfraService(InfraService):
|
||||
)
|
||||
# A (re)created gateway container minted/mounted its CA afresh and lost
|
||||
# every bottle's per-bottle state; reconcile the already-running bottles
|
||||
# against it (PRD 0081). Skipped when a healthy current gateway was left
|
||||
# against it (PRD 0083). Skipped when a healthy current gateway was left
|
||||
# untouched — no cold boot, nothing to reconcile.
|
||||
if cold_booted:
|
||||
from .backend import DockerBottleBackend
|
||||
|
||||
@@ -83,7 +83,7 @@ def running_agent_containers(
|
||||
) -> list[str]:
|
||||
"""Every running agent container on the gateway `network` (the gateway
|
||||
itself excluded) — the bottles the bring-up reconcile attaches to the fresh
|
||||
gateway (PRD 0081). Raises `OSError` if `docker` can't be run (fail hard: a
|
||||
gateway (PRD 0083). Raises `OSError` if `docker` can't be run (fail hard: a
|
||||
reconcile that can't list its bottles must not look like "no bottles")."""
|
||||
proc = run_docker([
|
||||
"docker", "network", "inspect", "--format",
|
||||
@@ -98,7 +98,7 @@ def running_agent_containers(
|
||||
def push_ca_to_container(container: str, ca_pem: str) -> None:
|
||||
"""(Re)attach one running agent container to the current gateway: replace
|
||||
its trusted gateway CA with `ca_pem` and rebuild its trust store via
|
||||
`docker cp` + `docker exec` (PRD 0081). Unconditional install — there is one
|
||||
`docker cp` + `docker exec` (PRD 0083). Unconditional install — there is one
|
||||
gateway, so no fingerprint match is needed.
|
||||
|
||||
Fail hard: raises `InfraLaunchError` (naming the container) on any failure —
|
||||
|
||||
@@ -73,7 +73,7 @@ class FirecrackerInfraService(InfraService):
|
||||
# The fresh gateway rootfs minted a new CA and lost every bottle's
|
||||
# git-gate/token state; reconcile the already-running bottles against
|
||||
# it so a gateway rebuild doesn't silently break their egress
|
||||
# (PRD 0081). Cold-boot only — the adopt fast-paths above never reach
|
||||
# (PRD 0083). Cold-boot only — the adopt fast-paths above never reach
|
||||
# here, so a healthy current gateway is left untouched.
|
||||
if cold_booted:
|
||||
from .backend import FirecrackerBottleBackend
|
||||
|
||||
@@ -90,7 +90,7 @@ def persist_env_var_secret(private_key: Path, guest_ip: str, secret: str) -> Non
|
||||
def attach_ca_to_agent_vm(run_dir: Path, ca_pem: str) -> None:
|
||||
"""(Re)attach one running agent VM (identified by its `run_dir`) to the
|
||||
current gateway: replace its trusted gateway CA with `ca_pem` and rebuild
|
||||
its trust store over SSH (PRD 0081). Unconditional install — there is one
|
||||
its trust store over SSH (PRD 0083). Unconditional install — there is one
|
||||
gateway, so no fingerprint match is needed. Bare-pipe input keeps the cert
|
||||
off argv.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""The shared gateway-attach reconcile flow (PRD 0081).
|
||||
"""The shared gateway-attach reconcile flow (PRD 0083).
|
||||
|
||||
`BottleBackend.attach_bottled_agents_to_gateway()` delegates here so every
|
||||
backend reconciles running bottles against a freshly-booted gateway *the same
|
||||
@@ -21,7 +21,7 @@ if TYPE_CHECKING:
|
||||
@dataclass(frozen=True)
|
||||
class GatewayAttachResources:
|
||||
"""Everything a running bottle needs to (re)attach to the current gateway on
|
||||
a cold boot (PRD 0081). Gathered once per reconcile and handed to every
|
||||
a cold boot (PRD 0083). Gathered once per reconcile and handed to every
|
||||
bottle. The CA now; egress secrets and git-gate state join as the reconcile
|
||||
grows (#516)."""
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ class MacosGateway(Gateway):
|
||||
|
||||
Always returns True: this recreates the gateway container unconditionally
|
||||
(a cold boot), so the caller reconciles running bottles against it
|
||||
(PRD 0081)."""
|
||||
(PRD 0083)."""
|
||||
self._orchestrator_url = orchestrator_url
|
||||
self._gateway_token = gateway_token
|
||||
# Fail closed on a missing policy source or token: the resolver-only data
|
||||
|
||||
@@ -142,7 +142,7 @@ class MacosInfraService(InfraService):
|
||||
url, orchestrator.mint_gateway_token())
|
||||
# A (re)created gateway container minted/mounted its CA afresh and lost
|
||||
# every bottle's per-bottle state; reconcile the already-running bottles
|
||||
# against it (PRD 0081). Skipped when a healthy current gateway was left
|
||||
# against it (PRD 0083). Skipped when a healthy current gateway was left
|
||||
# untouched — no cold boot, nothing to reconcile.
|
||||
if cold_booted:
|
||||
from .backend import MacosContainerBottleBackend
|
||||
|
||||
@@ -99,7 +99,7 @@ def ensure_gateway(
|
||||
|
||||
def running_agent_containers() -> list[str]:
|
||||
"""Every running agent container's name — the bottles the bring-up reconcile
|
||||
attaches to the fresh gateway (PRD 0081). Raises `EnumerationError` if the
|
||||
attaches to the fresh gateway (PRD 0083). Raises `EnumerationError` if the
|
||||
live set can't be determined (fail hard rather than reconcile a partial
|
||||
set)."""
|
||||
return [f"{CONTAINER_NAME_PREFIX}{agent.slug}" for agent in enumerate_active()]
|
||||
@@ -108,7 +108,7 @@ def running_agent_containers() -> list[str]:
|
||||
def push_ca_to_container(name: str, ca_pem: str) -> None:
|
||||
"""(Re)attach one running agent container to the current gateway: replace
|
||||
its trusted gateway CA with `ca_pem` and rebuild its trust store via
|
||||
`container cp` + `container exec` (PRD 0081). Unconditional install — there
|
||||
`container cp` + `container exec` (PRD 0083). Unconditional install — there
|
||||
is one gateway, so no fingerprint match is needed.
|
||||
|
||||
Fail hard: raises `InfraLaunchError` (naming the container) on any failure —
|
||||
|
||||
@@ -133,7 +133,7 @@ class Gateway(abc.ABC):
|
||||
so its mitmproxy minted a fresh CA and lost its per-bottle state), False
|
||||
when a healthy current gateway was left untouched. The bring-up flow
|
||||
uses this as the cold-boot signal that gates the running-bottle
|
||||
reconcile (`attach_bottled_agents_to_gateway`, PRD 0081)."""
|
||||
reconcile (`attach_bottled_agents_to_gateway`, PRD 0083)."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def is_running(self) -> bool:
|
||||
|
||||
@@ -15,7 +15,7 @@ macOS-container). Cross-backend operations can be expressed two ways:
|
||||
concrete method and each backend overrides small **primitives** it calls.
|
||||
|
||||
Form 1 gives each backend total freedom, which is exactly the problem: the three
|
||||
implementations drift. The bring-up reconcile (PRD 0081) first shipped as form 1
|
||||
implementations drift. The bring-up reconcile (PRD 0083) first shipped as form 1
|
||||
and immediately diverged — each backend re-implemented "gather CA → list running
|
||||
bottles → push to each", and one backend's copy silently skipped failures while
|
||||
another's aborted, an inconsistency caught only in review (#519). The behaviour
|
||||
@@ -37,7 +37,7 @@ method that:
|
||||
- delegates only the irreducibly backend-specific steps to `@abstractmethod`
|
||||
primitives with narrow, well-typed signatures.
|
||||
|
||||
The first application is `attach_bottled_agents_to_gateway()` (PRD 0081): the
|
||||
The first application is `attach_bottled_agents_to_gateway()` (PRD 0083): the
|
||||
base gathers resources once, attempts every running bottle, and raises an
|
||||
aggregate `InfraLaunchError` if any failed; backends supply only
|
||||
`_gateway_attach_resources()`, `_running_bottles()`, and
|
||||
@@ -60,6 +60,6 @@ operations whose *shape* should be uniform, not about banning abstract methods.
|
||||
|
||||
## Links
|
||||
|
||||
- PRD 0081 (`docs/prds/0081-reprovision-gateway-state-on-bringup.md`).
|
||||
- PRD 0083 (`docs/prds/0083-reprovision-gateway-state-on-bringup.md`).
|
||||
- Review that prompted this: PR #519.
|
||||
- `bot_bottle/backend/base.py` (`BottleBackend.attach_bottled_agents_to_gateway`).
|
||||
|
||||
@@ -85,7 +85,7 @@ class TestRuntimeModuleSizes(unittest.TestCase):
|
||||
def test_backend_contract_does_not_absorb_preparation_logic(self) -> None:
|
||||
# base.py holds the backend *contract*; implementation lives elsewhere.
|
||||
# The cap is a tripwire against absorbing preparation/impl logic, not a
|
||||
# ban on new contract surface — bumped 580->615 for the PRD 0081
|
||||
# ban on new contract surface — bumped 580->615 for the PRD 0083
|
||||
# gateway-attach contract (delegator + 3 abstract primitives; the flow
|
||||
# itself lives in backend/gateway_attach.py, not here).
|
||||
caps = {
|
||||
|
||||
@@ -162,7 +162,7 @@ class TestFirecrackerReprovision(unittest.TestCase):
|
||||
|
||||
|
||||
class TestAttachFlow(unittest.TestCase):
|
||||
"""PRD 0081 / #519 review: the base backend owns the reconcile flow and
|
||||
"""PRD 0083 / #519 review: the base backend owns the reconcile flow and
|
||||
fails hard — gather resources, attempt every running bottle, then raise an
|
||||
aggregate if any failed (never silently skip)."""
|
||||
|
||||
@@ -208,7 +208,7 @@ class TestAttachFlow(unittest.TestCase):
|
||||
|
||||
|
||||
class TestFirecrackerAttachPrimitive(unittest.TestCase):
|
||||
"""PRD 0081: attach_ca_to_agent_vm pushes the current gateway CA into one
|
||||
"""PRD 0083: attach_ca_to_agent_vm pushes the current gateway CA into one
|
||||
running agent VM over SSH, failing hard."""
|
||||
|
||||
def _run_dir(self, root: Path, ip: str = "10.243.0.3") -> Path:
|
||||
|
||||
@@ -70,7 +70,7 @@ class TestDockerInfraService(unittest.TestCase):
|
||||
|
||||
def test_cold_boot_reconciles_running_bottles(self) -> None:
|
||||
# A (re)created gateway (connect returns True) triggers the bring-up
|
||||
# reconcile so running bottles re-trust the fresh gateway (PRD 0081).
|
||||
# reconcile so running bottles re-trust the fresh gateway (PRD 0083).
|
||||
self.gw.connect_to_orchestrator.return_value = True
|
||||
self.svc.ensure_running()
|
||||
self.attach.assert_called_once_with()
|
||||
|
||||
@@ -63,7 +63,7 @@ class TestFirecrackerGatewayConnect(unittest.TestCase):
|
||||
patch.object(infra_vm, "push_secret") as push:
|
||||
cold_booted = gw.connect_to_orchestrator(_ORCH_URL, _TOKEN)
|
||||
# The VM is booted fresh here (cold-boot path only), so it always
|
||||
# signals a cold boot → the caller reconciles running bottles (PRD 0081).
|
||||
# signals a cold boot → the caller reconciles running bottles (PRD 0083).
|
||||
self.assertTrue(cold_booted)
|
||||
# Booted on the gateway link with the gateway role; the orchestrator's
|
||||
# guest IP (parsed off the URL) rides the cmdline as bb_orch.
|
||||
|
||||
@@ -49,7 +49,7 @@ _ATTACH = (
|
||||
class TestEnsureRunning(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
# The cold-boot branch reconciles running bottles against the fresh
|
||||
# gateway (PRD 0081). Stub it so these composition tests stay isolated
|
||||
# gateway (PRD 0083). Stub it so these composition tests stay isolated
|
||||
# from SSH; the wiring itself is asserted in test_cold_boot_reconciles*.
|
||||
ap = patch(_ATTACH)
|
||||
self.attach = ap.start()
|
||||
|
||||
@@ -46,7 +46,7 @@ class TestMacosGatewayConnect(unittest.TestCase):
|
||||
|
||||
def test_connect_signals_cold_boot(self) -> None:
|
||||
# The container is recreated unconditionally, so connect always signals
|
||||
# a cold boot → the caller reconciles running bottles (PRD 0081).
|
||||
# a cold boot → the caller reconciles running bottles (PRD 0083).
|
||||
run = Mock(return_value=_proc())
|
||||
with patch(f"{_GW}.container_mod") as mod, \
|
||||
patch(f"{_GW}.host_gateway_ca_dir", return_value=Path("/ca")):
|
||||
|
||||
@@ -58,7 +58,7 @@ class TestInfraEnsureRunning(unittest.TestCase):
|
||||
|
||||
def test_cold_boot_reconciles_running_bottles(self) -> None:
|
||||
# A (re)created gateway (connect returns True) triggers the bring-up
|
||||
# reconcile so running bottles re-trust the fresh gateway (PRD 0081).
|
||||
# reconcile so running bottles re-trust the fresh gateway (PRD 0083).
|
||||
self.gw.connect_to_orchestrator.return_value = True
|
||||
with patch(f"{_INFRA}.ensure_networks"):
|
||||
self.svc.ensure_running()
|
||||
|
||||
@@ -90,7 +90,7 @@ class TestDockerGateway(unittest.TestCase):
|
||||
self.assertEqual([], [c for c in calls if c[:2] == ["docker", "run"]])
|
||||
self.assertEqual([], [c for c in calls if c[:2] == ["docker", "rm"]])
|
||||
# A healthy current gateway left untouched is not a cold boot — the
|
||||
# bring-up flow skips the running-bottle reconcile (PRD 0081).
|
||||
# bring-up flow skips the running-bottle reconcile (PRD 0083).
|
||||
self.assertFalse(cold_booted)
|
||||
|
||||
def test_ensure_running_recreates_when_image_is_stale(self) -> None:
|
||||
@@ -113,7 +113,7 @@ class TestDockerGateway(unittest.TestCase):
|
||||
self.assertEqual(1, len([c for c in calls if c[:2] == ["docker", "run"]]))
|
||||
self.assertTrue(any(c[:2] == ["docker", "rm"] for c in calls))
|
||||
# A recreated container minted/mounted its CA afresh — a cold boot that
|
||||
# triggers the running-bottle reconcile (PRD 0081).
|
||||
# triggers the running-bottle reconcile (PRD 0083).
|
||||
self.assertTrue(cold_booted)
|
||||
|
||||
def test_ensure_running_starts_the_singleton_when_absent(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user