fix(manifest): presence-aware runtime merge for nested_containers
test / integration-docker (pull_request) Successful in 17s
test / unit (pull_request) Successful in 44s
lint / lint (push) Successful in 57s
test / integration-firecracker (pull_request) Successful in 3m31s
test / coverage (pull_request) Successful in 19s
test / publish-infra (pull_request) Has been skipped
tracker-policy-pr / check-pr (pull_request) Successful in 13s

The runtime merge (merge_bottles_runtime / _fold_two_bottles) was using
OR semantics for nested_containers, which meant `nested_containers: false`
in a later bottle could never override an earlier `true`.

Fix: add `nested_containers_explicit: bool` to ManifestBottle, set to
True only when the key is present in the source dict. The runtime merge
functions now use the override's value only when it was explicitly
supplied; otherwise the base's value is preserved. This matches the
documented last-wins / presence-aware semantics used by supervise and
agent_provider, and aligns with _merge_bottles (the file-based extends
path) which already did presence checks via `"nested_containers" in
child_raw`.

Tests: rename existing test to clarify the preserved-when-omitted case,
add explicit-false-overrides-true and explicit-true-overrides-false cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 17:58:00 +00:00
parent 315ed04979
commit bf8ff91b31
3 changed files with 43 additions and 15 deletions
+7
View File
@@ -49,6 +49,12 @@ class ManifestBottle:
# costs image weight, a resident service, and relaxed guest device modes
# that the majority of bottles never need.
nested_containers: bool = False
# True when nested_containers was explicitly present in the source dict.
# Used by the runtime merge path to distinguish "omitted → default False"
# from "explicitly set to False", so an explicit false in a later bottle
# can override an earlier true while a bottle that never mentions the key
# does not silently drop the capability.
nested_containers_explicit: bool = False
@classmethod
def from_dict(cls, name: str, raw: object) -> "ManifestBottle":
@@ -139,4 +145,5 @@ class ManifestBottle:
env=env, agent_provider=agent_provider, git=git,
git_user=git_user, egress=egress, supervise=supervise_raw,
nested_containers=nested_raw,
nested_containers_explicit="nested_containers" in d,
)
+21 -11
View File
@@ -15,16 +15,14 @@ def merge_bottles_runtime(bottles: "list[ManifestBottle]") -> "ManifestBottle":
the same field-merge rules as the file-based extends machinery:
env: dict merge, later wins; git_user: per-field overlay, later
wins on non-empty; git (repos): union by name, later wins; egress
routes: concatenate; agent_provider, supervise: later
replaces; nested_containers: OR (see below).
routes: concatenate; agent_provider, supervise, nested_containers:
later replaces (presence-aware).
nested_containers is OR'd rather than replaced because these objects
are already resolved: a bottle that never mentions the key is
indistinguishable from one that sets it false, so "later replaces"
would let any bottle composed after a container-enabled one silently
drop the capability. The file-based `extends:` path still sees the
raw keys, so there an explicit `nested_containers: false` in a child
turns it back off.
nested_containers uses presence-aware replacement: if the later bottle
was loaded from a source that explicitly declared the key, its value
wins (so an explicit `false` can override an earlier `true`). If the
later bottle never mentioned the key, the earlier value is preserved
(so a bottle that only sets env does not silently drop the capability).
"""
if not bottles:
raise ValueError("merge_bottles_runtime requires at least one bottle")
@@ -56,6 +54,11 @@ def _merge_two_bottles_runtime(base: "ManifestBottle", override: "ManifestBottle
merged_routes = base.egress.routes + override.egress.routes
merged_egress = ManifestEgressConfig(routes=merged_routes, Log=override.egress.Log)
merged_nc = (
override.nested_containers
if override.nested_containers_explicit
else base.nested_containers
)
return ManifestBottle(
env=merged_env,
agent_provider=override.agent_provider,
@@ -63,7 +66,8 @@ def _merge_two_bottles_runtime(base: "ManifestBottle", override: "ManifestBottle
git_user=merged_git_user,
egress=merged_egress,
supervise=override.supervise,
nested_containers=base.nested_containers or override.nested_containers,
nested_containers=merged_nc,
nested_containers_explicit=base.nested_containers_explicit or override.nested_containers_explicit,
)
@@ -209,6 +213,11 @@ def _fold_two_bottles(
Log=later.egress.Log,
)
folded_nc = (
later.nested_containers
if later.nested_containers_explicit
else earlier.nested_containers
)
return ManifestBottle(
env=merged_env,
agent_provider=later.agent_provider,
@@ -216,7 +225,8 @@ def _fold_two_bottles(
git_user=merged_git_user,
egress=merged_egress,
supervise=later.supervise,
nested_containers=earlier.nested_containers or later.nested_containers,
nested_containers=folded_nc,
nested_containers_explicit=earlier.nested_containers_explicit or later.nested_containers_explicit,
), merged_repos_raw
+15 -4
View File
@@ -56,16 +56,27 @@ class TestMergeBottlesRuntime(unittest.TestCase):
result = merge_bottles_runtime([base, override])
self.assertFalse(result.supervise)
def test_nested_containers_survives_a_later_bottle(self):
"""OR, not replace: a resolved bottle that never mentioned the key is
indistinguishable from one that set it false, so `--bottle with-docker
--bottle claude-dev` must not silently drop the capability."""
def test_nested_containers_survives_a_later_bottle_that_omits_the_key(self):
"""A bottle that never mentions nested_containers must not silently
drop the capability: `--bottle with-docker --bottle claude-dev`."""
enabled = _bottle(nested_containers=True)
quiet = _bottle(env={"X": "1"})
self.assertTrue(merge_bottles_runtime([enabled, quiet]).nested_containers)
self.assertTrue(merge_bottles_runtime([quiet, enabled]).nested_containers)
self.assertFalse(merge_bottles_runtime([quiet, quiet]).nested_containers)
def test_nested_containers_explicit_false_overrides_earlier_true(self):
"""An explicit nested_containers: false in a later bottle must win
over an earlier true (last-wins, presence-aware)."""
enabled = _bottle(nested_containers=True)
disabled = _bottle(nested_containers=False)
self.assertFalse(merge_bottles_runtime([enabled, disabled]).nested_containers)
def test_nested_containers_explicit_true_overrides_earlier_false(self):
enabled = _bottle(nested_containers=True)
disabled = _bottle(nested_containers=False)
self.assertTrue(merge_bottles_runtime([disabled, enabled]).nested_containers)
def test_three_bottles_merged_left_to_right(self):
b1 = _bottle(env={"A": "1", "B": "1", "C": "1"})
b2 = _bottle(env={"B": "2", "C": "2"})