refactor(types): move loaded manifest from BottleSpec to BottlePlan
test / integration (pull_request) Successful in 21s
test / unit (pull_request) Successful in 49s
lint / lint (push) Successful in 2m15s
test / unit (push) Successful in 56s
test / integration (push) Successful in 27s
Update Quality Badges / update-badges (push) Successful in 2m37s

BottleSpec.manifest was ManifestIndex | Manifest — a union encoding
two lifecycle stages in one field. The union was unjustifiable:
it forced a type-narrowing workaround (loaded_manifest property)
on every consumer.

Clean split:
- BottleSpec.manifest: ManifestIndex (always; CLI-supplied intent)
- BottlePlan.manifest: Manifest (always; loaded by _validate())

_validate() returns the loaded Manifest directly. prepare() passes
it to _resolve_plan(), which stores it on the plan. All provisioner
code now reads plan.manifest.agent / plan.manifest.bottle — no
union, no asserts, no type: ignore.
This commit was merged in pull request #239.
This commit is contained in:
2026-06-23 02:22:10 +00:00
committed by didericis
parent 56ef71060a
commit da42740156
24 changed files with 112 additions and 94 deletions
+1 -1
View File
@@ -240,7 +240,7 @@ class AgentProvider(ABC):
BottleBackend.provision_workspace against the running bottle."""
from .log import info
manifest_bottle = plan.spec.loaded_manifest.bottle
manifest_bottle = plan.manifest.bottle
if manifest_bottle.git:
from .git_gate import GIT_GATE_HOSTNAME, git_gate_render_gitconfig
gate_host = getattr(plan, "git_gate_insteadof_host", GIT_GATE_HOSTNAME)
+16 -28
View File
@@ -37,7 +37,7 @@ import shlex
import sys
from abc import ABC, abstractmethod
from contextlib import AbstractContextManager
from dataclasses import dataclass, replace
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Generic, Sequence, TypeVar
@@ -61,17 +61,10 @@ class BottleSpec:
Resolved values (image names, container name, scratch paths, runsc
availability) live on the plan, not the spec."""
manifest: ManifestIndex | Manifest
manifest: ManifestIndex
agent_name: str
copy_cwd: bool
user_cwd: str
@property
def loaded_manifest(self) -> Manifest:
assert isinstance(self.manifest, Manifest), (
"spec.manifest is still a ManifestIndex — call _validate() first"
)
return self.manifest
# PRD 0016 follow-up: when set, the backend's prepare step uses
# this identity instead of minting a fresh one — the resume path
# (`cli.py resume <identity>`) sets this to continue an existing
@@ -87,6 +80,7 @@ class BottlePlan(ABC):
(e.g. DockerBottlePlan) add backend-specific resolved fields."""
spec: BottleSpec
manifest: Manifest
stage_dir: Path
git_gate_plan: GitGatePlan
@@ -119,7 +113,7 @@ class BottlePlan(ABC):
"""Render the y/N preflight summary to stderr."""
del remote_control
spec = self.spec
manifest = spec.loaded_manifest
manifest = self.manifest
agent = manifest.agent
bottle = manifest.bottle
@@ -296,11 +290,10 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT]):
write_launch_metadata,
)
spec = self._validate(spec)
manifest = self._validate(spec)
self._preflight()
manifest = spec.loaded_manifest
manifest_bottle = manifest.bottle
manifest_agent_provider = manifest_bottle.agent_provider
agent_provider = get_provider(manifest_agent_provider.template)
@@ -320,7 +313,7 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT]):
else:
agent_dockerfile_path = str(agent_provider.dockerfile)
agent_dir, prompt_file = prepare_agent_state_dir(slug, spec)
agent_dir, prompt_file = prepare_agent_state_dir(slug, manifest)
agent_provision_plan = build_agent_provision_plan(
template=manifest_agent_provider.template,
@@ -344,6 +337,7 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT]):
return self._resolve_plan(
spec,
manifest=manifest,
slug=slug,
resolved_env=resolved_env,
agent_provision_plan=agent_provision_plan,
@@ -362,24 +356,18 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT]):
"""
pass
def _validate(self, spec: BottleSpec) -> BottleSpec:
def _validate(self, spec: BottleSpec) -> Manifest:
"""Cross-backend pre-launch checks. Parses the selected agent and
its bottle (raising ManifestError on invalid content), confirms
skills are present on the host, and every git IdentityFile resolves.
Returns a new BottleSpec whose manifest is fully loaded for the
selected agent. Subclasses with additional preconditions should
override and call `super()._validate(spec)` first, using the
returned spec for further checks."""
assert isinstance(spec.manifest, ManifestIndex), (
"_validate() called on a spec whose manifest is already loaded"
)
Returns the loaded Manifest for the selected agent. Subclasses with
additional preconditions should override and call
`super()._validate(spec)` first."""
manifest = spec.manifest.load_for_agent(spec.agent_name)
spec = replace(spec, manifest=manifest)
agent = manifest.agent
self._validate_skills(agent.skills)
self._validate_agent_provider_dockerfile(spec)
return spec
self._validate_skills(manifest.agent.skills)
self._validate_agent_provider_dockerfile(spec, manifest)
return manifest
def _validate_skills(self, skills: Sequence[str]) -> None:
"""Each named skill must be a directory under the host's
@@ -393,8 +381,7 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT]):
f"Create it under ~/.claude/skills/, then re-run."
)
def _validate_agent_provider_dockerfile(self, spec: BottleSpec) -> None:
manifest = spec.loaded_manifest
def _validate_agent_provider_dockerfile(self, spec: BottleSpec, manifest: Manifest) -> None:
bottle = manifest.bottle
dockerfile = bottle.agent_provider.dockerfile
if not dockerfile:
@@ -412,6 +399,7 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT]):
def _resolve_plan(self,
spec: BottleSpec,
*,
manifest: Manifest,
slug: str,
resolved_env: ResolvedEnv,
agent_provision_plan: AgentProvisionPlan,
+3
View File
@@ -30,6 +30,7 @@ from ...egress import EgressPlan
from ...env import ResolvedEnv
from ...git_gate import GitGatePlan
from ...supervise import SupervisePlan
from ...manifest import Manifest
from .. import ActiveAgent, BottleBackend, BottleSpec
from . import cleanup as _cleanup
from . import enumerate as _enumerate
@@ -63,6 +64,7 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup
self,
spec: BottleSpec,
*,
manifest: Manifest,
slug: str,
resolved_env: ResolvedEnv,
agent_provision_plan: AgentProvisionPlan,
@@ -73,6 +75,7 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup
) -> DockerBottlePlan:
return _resolve_plan.resolve_plan(
spec,
manifest=manifest,
slug=slug,
resolved_env=resolved_env,
agent_provision_plan=agent_provision_plan,
+1 -1
View File
@@ -75,7 +75,7 @@ def launch(
Teardown on exit."""
stack = ExitStack()
_bottle_for_revoke = plan.spec.loaded_manifest.bottle
_bottle_for_revoke = plan.manifest.bottle
_git_gate_dir_for_revoke = git_gate_state_dir(plan.slug)
def teardown() -> None:
@@ -18,6 +18,7 @@ from .. import BottleSpec
from ...env import ResolvedEnv
from ...agent_provider import AgentProvisionPlan
from ...egress import EgressPlan
from ...manifest import Manifest
from ...supervise import SupervisePlan
from ...git_gate import GitGatePlan
@@ -31,6 +32,7 @@ def build_guest_env(resolved_env: ResolvedEnv) -> dict[str, str]:
def resolve_plan(
spec: BottleSpec,
manifest: Manifest,
slug: str,
resolved_env: ResolvedEnv,
agent_provision_plan: AgentProvisionPlan,
@@ -48,6 +50,7 @@ def resolve_plan(
return DockerBottlePlan(
spec=spec,
manifest=manifest,
stage_dir=stage_dir,
slug=slug,
forwarded_env=dict(resolved_env.forwarded),
@@ -11,6 +11,7 @@ from ...egress import EgressPlan
from ...env import ResolvedEnv
from ...git_gate import GitGatePlan
from ...supervise import SupervisePlan
from ...manifest import Manifest
from .. import ActiveAgent, BottleBackend, BottleSpec
from . import cleanup as _cleanup
from . import enumerate as _enumerate
@@ -45,6 +46,7 @@ class MacosContainerBottleBackend(
self,
spec: BottleSpec,
*,
manifest: Manifest,
slug: str,
resolved_env: ResolvedEnv,
agent_provision_plan: AgentProvisionPlan,
@@ -55,6 +57,7 @@ class MacosContainerBottleBackend(
) -> MacosContainerBottlePlan:
return _resolve_plan.resolve_plan(
spec,
manifest=manifest,
slug=slug,
resolved_env=resolved_env,
agent_provision_plan=agent_provision_plan,
+1 -1
View File
@@ -68,7 +68,7 @@ def launch(
) -> Generator[MacosContainerBottle, None, None]:
"""Build, run, provision, and yield an Apple Container bottle."""
stack = ExitStack()
bottle_for_revoke = plan.spec.loaded_manifest.bottle
bottle_for_revoke = plan.manifest.bottle
git_gate_dir_for_revoke = git_gate_state_dir(plan.slug)
def teardown() -> None:
@@ -9,6 +9,7 @@ from ...egress import EgressPlan
from ...env import ResolvedEnv
from ...git_gate import GitGatePlan
from ...supervise import SupervisePlan
from ...manifest import Manifest
from .. import BottleSpec
from . import util as container_mod
from .bottle_plan import MacosContainerBottlePlan
@@ -24,6 +25,7 @@ def build_guest_env(resolved_env: ResolvedEnv) -> dict[str, str]:
def resolve_plan(
spec: BottleSpec,
manifest: Manifest,
slug: str,
resolved_env: ResolvedEnv,
agent_provision_plan: AgentProvisionPlan,
@@ -34,6 +36,7 @@ def resolve_plan(
) -> MacosContainerBottlePlan:
return MacosContainerBottlePlan(
spec=spec,
manifest=manifest,
stage_dir=stage_dir,
slug=slug,
forwarded_env=dict(resolved_env.forwarded),
+3 -3
View File
@@ -26,7 +26,7 @@ from ..bottle_state import (
)
from ..egress import Egress, EgressPlan
from ..git_gate import GitGate, GitGatePlan
from ..manifest import ManifestBottle
from ..manifest import Manifest, ManifestBottle
from ..supervise import Supervise, SupervisePlan
from . import BottleSpec
@@ -66,10 +66,10 @@ def write_launch_metadata(
))
def prepare_agent_state_dir(slug: str, spec: BottleSpec) -> tuple[Path, Path]:
def prepare_agent_state_dir(slug: str, manifest: Manifest) -> tuple[Path, Path]:
"""Create the agent state subdir, write the prompt file.
Returns (agent_dir, prompt_file)."""
agent = spec.loaded_manifest.agent
agent = manifest.agent
agent_dir = agent_state_dir(slug)
agent_dir.mkdir(parents=True, exist_ok=True)
prompt_file = agent_dir / "prompt.txt"
@@ -18,6 +18,7 @@ from ...egress import EgressPlan
from ...env import ResolvedEnv
from ...git_gate import GitGatePlan
from ...supervise import SupervisePlan
from ...manifest import Manifest
from .. import ActiveAgent, BottleBackend, BottleSpec
from . import cleanup as _cleanup
from . import enumerate as _enumerate
@@ -55,6 +56,7 @@ class SmolmachinesBottleBackend(
self,
spec: BottleSpec,
*,
manifest: Manifest,
slug: str,
resolved_env: ResolvedEnv,
agent_provision_plan: AgentProvisionPlan,
@@ -65,6 +67,7 @@ class SmolmachinesBottleBackend(
) -> SmolmachinesBottlePlan:
return _resolve_plan.resolve_plan(
spec,
manifest=manifest,
slug=slug,
resolved_env=resolved_env,
agent_provision_plan=agent_provision_plan,
+1 -1
View File
@@ -130,7 +130,7 @@ def _teardown_smolmachines(
except BaseException as exc: # noqa: W0718 — teardown must not fail
teardown_exc = exc
warn(f"smolmachines teardown failed: {exc!r}")
bottle = plan.spec.loaded_manifest.bottle
bottle = plan.manifest.bottle
revoke_git_gate_provisioned_keys(bottle, git_gate_state_dir(plan.slug))
if teardown_exc is not None:
raise teardown_exc
@@ -13,6 +13,7 @@ from __future__ import annotations
from pathlib import Path
from .. import BottleSpec
from ...manifest import Manifest
from ...env import ResolvedEnv
from ...agent_provider import AgentProvisionPlan
from ...egress import EgressPlan
@@ -46,6 +47,7 @@ def build_guest_env(resolved_env: ResolvedEnv) -> dict[str, str]:
def resolve_plan(
spec: BottleSpec,
manifest: Manifest,
slug: str,
resolved_env: ResolvedEnv,
agent_provision_plan: AgentProvisionPlan,
@@ -67,6 +69,7 @@ def resolve_plan(
return SmolmachinesBottlePlan(
spec=spec,
manifest=manifest,
stage_dir=stage_dir,
slug=slug,
bundle_subnet=subnet,
+2 -2
View File
@@ -211,7 +211,7 @@ class ClaudeAgentProvider(AgentProvider):
when the agent has no skills."""
from ...backend.util import host_skill_dir
agent = plan.spec.loaded_manifest.agent
agent = plan.manifest.agent
if not agent.skills:
return
skills_dir = _skills_dir(plan.guest_home)
@@ -240,7 +240,7 @@ class ClaudeAgentProvider(AgentProvider):
f"chown node:node {prompt_path} && chmod 600 {prompt_path}",
user="root",
)
agent = plan.spec.loaded_manifest.agent
agent = plan.manifest.agent
return prompt_path if plan.agent_provision.has_prompt or agent.prompt else None
def provision(self, plan: "BottlePlan", bottle: "Bottle") -> None:
+2 -2
View File
@@ -177,7 +177,7 @@ class CodexAgentProvider(AgentProvider):
skills."""
from ...backend.util import host_skill_dir
agent = plan.spec.loaded_manifest.agent
agent = plan.manifest.agent
if not agent.skills:
return
skills_dir = _skills_dir(plan.guest_home)
@@ -206,7 +206,7 @@ class CodexAgentProvider(AgentProvider):
f"chown node:node {prompt_path} && chmod 600 {prompt_path}",
user="root",
)
agent = plan.spec.loaded_manifest.agent
agent = plan.manifest.agent
return prompt_path if plan.agent_provision.has_prompt or agent.prompt else None
def provision(self, plan: "BottlePlan", bottle: "Bottle") -> None:
+1 -1
View File
@@ -232,7 +232,7 @@ class PiAgentProvider(AgentProvider):
def provision_skills(self, plan: "BottlePlan", bottle: "Bottle") -> None:
from ...backend.util import host_skill_dir
agent = plan.spec.loaded_manifest.agent
agent = plan.manifest.agent
if not agent.skills:
return
skills_dir = _skills_dir(plan.guest_home)
+8 -11
View File
@@ -67,16 +67,6 @@ def _manifest(*, supervise: bool, with_git: bool, with_egress: bool) -> Manifest
})
def _spec(*, supervise: bool, with_git: bool, with_egress: bool) -> BottleSpec:
return BottleSpec(
manifest=_manifest(
supervise=supervise, with_git=with_git, with_egress=with_egress,
),
agent_name="demo",
copy_cwd=False,
user_cwd="/tmp/x",
)
def _git_gate_plan(upstreams: tuple[GitGateUpstream, ...] = ()) -> GitGatePlan:
return GitGatePlan(
@@ -146,9 +136,16 @@ def _plan(
roles=(),
),)
spec = _spec(supervise=supervise, with_git=with_git, with_egress=with_egress)
index = _manifest(supervise=supervise, with_git=with_git, with_egress=with_egress)
spec = BottleSpec(
manifest=index,
agent_name="demo",
copy_cwd=False,
user_cwd="/tmp/x",
)
return DockerBottlePlan(
spec=spec,
manifest=index.load_for_agent("demo"),
stage_dir=STAGE,
slug=SLUG,
forwarded_env={"CLAUDE_CODE_OAUTH_TOKEN": "x"},
+5 -3
View File
@@ -55,7 +55,7 @@ def _plan(
bottle_json: dict = {"agent_provider": {"template": "claude"}} # type: ignore
if supervise:
bottle_json["supervise"] = True
manifest = ManifestIndex.from_json_obj({
index = ManifestIndex.from_json_obj({
"bottles": {"dev": bottle_json},
"agents": {
"demo": {
@@ -64,9 +64,10 @@ def _plan(
"bottle": "dev",
},
},
}).load_for_agent("demo")
})
manifest = index.load_for_agent("demo")
spec = BottleSpec(
manifest=manifest, agent_name="demo",
manifest=index, agent_name="demo",
copy_cwd=False, user_cwd="/tmp/x",
)
supervise_plan = None
@@ -78,6 +79,7 @@ def _plan(
)
return DockerBottlePlan(
spec=spec,
manifest=manifest,
stage_dir=Path("/tmp/stage"),
slug="demo-abc12",
forwarded_env={},
+5 -3
View File
@@ -55,7 +55,7 @@ def _plan(
bottle_json: dict = {"agent_provider": {"template": "codex"}} # type: ignore
if supervise:
bottle_json["supervise"] = True
manifest = ManifestIndex.from_json_obj({
index = ManifestIndex.from_json_obj({
"bottles": {"dev": bottle_json},
"agents": {
"demo": {
@@ -64,9 +64,10 @@ def _plan(
"bottle": "dev",
},
},
}).load_for_agent("demo")
})
manifest = index.load_for_agent("demo")
spec = BottleSpec(
manifest=manifest, agent_name="demo",
manifest=index, agent_name="demo",
copy_cwd=False, user_cwd="/tmp/x",
)
supervise_plan = None
@@ -78,6 +79,7 @@ def _plan(
)
return DockerBottlePlan(
spec=spec,
manifest=manifest,
stage_dir=Path("/tmp/stage"),
slug="demo-abc12",
forwarded_env={},
+5 -3
View File
@@ -43,7 +43,7 @@ def _plan(
skills: list[str] | None = None,
agent_provision: AgentProvisionPlan | None = None,
) -> DockerBottlePlan:
manifest = ManifestIndex.from_json_obj({
index = ManifestIndex.from_json_obj({
"bottles": {"dev": {"agent_provider": {"template": "pi"}}},
"agents": {
"demo": {
@@ -52,13 +52,15 @@ def _plan(
"bottle": "dev",
},
},
}).load_for_agent("demo")
})
manifest = index.load_for_agent("demo")
spec = BottleSpec(
manifest=manifest, agent_name="demo",
manifest=index, agent_name="demo",
copy_cwd=False, user_cwd="/tmp/x",
)
return DockerBottlePlan(
spec=spec,
manifest=manifest,
stage_dir=Path("/tmp/stage"),
slug="demo-abc12",
forwarded_env={},
+7 -11
View File
@@ -23,22 +23,17 @@ from bot_bottle.egress import EgressPlan
from bot_bottle.git_gate import GitGatePlan
from bot_bottle.manifest import ManifestIndex
from bot_bottle.manifest import Manifest, ManifestIndex
def _manifest() -> Manifest:
return ManifestIndex.from_json_obj({
"bottles": {"dev": {}},
"agents": {"demo": {"skills": [], "prompt": "", "bottle": "dev"}},
}).load_for_agent("demo")
_INDEX = ManifestIndex.from_json_obj({
"bottles": {"dev": {}},
"agents": {"demo": {"skills": [], "prompt": "", "bottle": "dev"}},
})
def _plan(tmp: str) -> DockerBottlePlan:
stage = Path(tmp)
manifest = _manifest()
manifest = _INDEX.load_for_agent("demo")
spec = BottleSpec(
manifest=manifest,
manifest=_INDEX,
agent_name="demo",
copy_cwd=False,
user_cwd=tmp,
@@ -46,6 +41,7 @@ def _plan(tmp: str) -> DockerBottlePlan:
)
return DockerBottlePlan(
spec=spec,
manifest=manifest,
stage_dir=stage,
git_gate_plan=GitGatePlan(
slug="test-teardown-00001",
+5 -3
View File
@@ -51,16 +51,18 @@ def _plan(*, git_user: dict | None = None, # type: ignore
bottle_json: dict = {} # type: ignore
if git_user is not None:
bottle_json["git-gate"] = {"user": git_user}
manifest = ManifestIndex.from_json_obj({
index = ManifestIndex.from_json_obj({
"bottles": {"dev": bottle_json},
"agents": {"demo": {"skills": [], "prompt": "", "bottle": "dev"}},
}).load_for_agent("demo")
})
manifest = index.load_for_agent("demo")
spec = BottleSpec(
manifest=manifest, agent_name="demo",
manifest=index, agent_name="demo",
copy_cwd=copy_cwd, user_cwd=user_cwd,
)
return DockerBottlePlan(
spec=spec,
manifest=manifest,
stage_dir=stage_dir or Path("/tmp/stage"),
slug="demo-abc12",
forwarded_env={},
@@ -11,6 +11,12 @@ from unittest.mock import patch
from bot_bottle.backend.macos_container import launch
from bot_bottle.backend.macos_container.bottle_plan import MacosContainerBottlePlan
from bot_bottle.manifest import ManifestIndex
_MANIFEST = ManifestIndex.from_json_obj({
"bottles": {"dev": {}},
"agents": {"demo": {"skills": [], "prompt": "", "bottle": "dev"}},
}).load_for_agent("demo")
def _plan(
@@ -67,6 +73,7 @@ def _plan(
)
return cast(MacosContainerBottlePlan, SimpleNamespace(
spec=SimpleNamespace(),
manifest=_MANIFEST,
stage_dir=stage_dir,
slug="dev-abc",
container_name="bot-bottle-dev-abc",
@@ -193,6 +200,7 @@ class TestMacosContainerLaunchArgv(unittest.TestCase):
)
plan = MacosContainerBottlePlan(
spec=base.spec,
manifest=base.manifest,
stage_dir=base.stage_dir,
git_gate_plan=base.git_gate_plan,
egress_plan=base.egress_plan,
+18 -17
View File
@@ -22,16 +22,15 @@ from bot_bottle.git_gate import GitGatePlan, GitGateUpstream
from bot_bottle.manifest import Manifest, ManifestIndex
def _manifest() -> Manifest:
return ManifestIndex.from_json_obj({
"bottles": {"dev": {}},
"agents": {"demo": {"skills": [], "prompt": "", "bottle": "dev"}},
}).load_for_agent("demo")
_INDEX = ManifestIndex.from_json_obj({
"bottles": {"dev": {}},
"agents": {"demo": {"skills": [], "prompt": "", "bottle": "dev"}},
})
def _spec(manifest: Manifest, tmp: str) -> BottleSpec:
def _spec(index: ManifestIndex, tmp: str) -> BottleSpec:
return BottleSpec(
manifest=manifest,
manifest=index,
agent_name="demo",
copy_cwd=False,
user_cwd=tmp,
@@ -92,10 +91,11 @@ def _agent_provision(tmp: str) -> AgentProvisionPlan:
)
def _docker_plan(spec: BottleSpec, tmp: str) -> DockerBottlePlan:
def _docker_plan(spec: BottleSpec, manifest: Manifest, tmp: str) -> DockerBottlePlan:
stage = Path(tmp)
return DockerBottlePlan(
spec=spec,
manifest=manifest,
stage_dir=stage,
git_gate_plan=_git_gate_plan(tmp),
egress_plan=_egress_plan(tmp),
@@ -107,10 +107,11 @@ def _docker_plan(spec: BottleSpec, tmp: str) -> DockerBottlePlan:
)
def _smolmachines_plan(spec: BottleSpec, tmp: str) -> SmolmachinesBottlePlan:
def _smolmachines_plan(spec: BottleSpec, manifest: Manifest, tmp: str) -> SmolmachinesBottlePlan:
stage = Path(tmp)
return SmolmachinesBottlePlan(
spec=spec,
manifest=manifest,
stage_dir=stage,
git_gate_plan=_git_gate_plan(tmp),
egress_plan=_egress_plan(tmp),
@@ -140,10 +141,10 @@ class TestGitGatePrintParity(unittest.TestCase):
def setUp(self) -> None:
self._tmp = tempfile.mkdtemp(prefix="plan-print-parity-")
manifest = _manifest()
spec = _spec(manifest, self._tmp)
self._docker_lines = _capture_print(_docker_plan(spec, self._tmp))
self._smol_lines = _capture_print(_smolmachines_plan(spec, self._tmp))
manifest = _INDEX.load_for_agent("demo")
spec = _spec(_INDEX, self._tmp)
self._docker_lines = _capture_print(_docker_plan(spec, manifest, self._tmp))
self._smol_lines = _capture_print(_smolmachines_plan(spec, manifest, self._tmp))
def _git_gate_lines(self, lines: list[str]) -> list[str]:
return [ln for ln in lines if "git gate" in ln]
@@ -170,10 +171,10 @@ class TestEgressPrintParity(unittest.TestCase):
def setUp(self) -> None:
self._tmp = tempfile.mkdtemp(prefix="plan-print-parity-")
manifest = _manifest()
spec = _spec(manifest, self._tmp)
self._docker_lines = _capture_print(_docker_plan(spec, self._tmp))
self._smol_lines = _capture_print(_smolmachines_plan(spec, self._tmp))
manifest = _INDEX.load_for_agent("demo")
spec = _spec(_INDEX, self._tmp)
self._docker_lines = _capture_print(_docker_plan(spec, manifest, self._tmp))
self._smol_lines = _capture_print(_smolmachines_plan(spec, manifest, self._tmp))
def _egress_section(self, lines: list[str]) -> list[str]:
"""Return lines from the egress label through the last route entry.
+5 -3
View File
@@ -110,7 +110,7 @@ def _plan(
bottle_json["git-gate"] = git_gate_json
if supervise:
bottle_json["supervise"] = True
manifest = ManifestIndex.from_json_obj({
index = ManifestIndex.from_json_obj({
"bottles": {"dev": bottle_json},
"agents": {
"demo": {
@@ -119,9 +119,10 @@ def _plan(
"bottle": "dev",
},
},
}).load_for_agent("demo")
})
manifest = index.load_for_agent("demo")
spec = BottleSpec(
manifest=manifest,
manifest=index,
agent_name="demo",
copy_cwd=copy_cwd,
user_cwd=user_cwd,
@@ -135,6 +136,7 @@ def _plan(
)
return SmolmachinesBottlePlan(
spec=spec,
manifest=manifest,
stage_dir=stage_dir or Path("/tmp/stage"),
slug="demo-abc12",
bundle_subnet="192.168.50.0/24",