fix(variants): apply a variant pin only while its carrier is in the round

Pins of every role applied at every round index, so a role the round did not deploy could pull a partner into a heavier variant (web-app-discourse#1 measured 35.46 GB against the 32 GB reservation cap). resolve_round now starts every role on its clamped index and recomputes the include and the pins in force until the assignment settles, raising VariantPinError on a cycle. The planner resolves each round once (39.1 s to 16.0 s for all rounds), affected judges every (role, index) with the round the planner deploys for it, and the resource budget lint measures the pin-aware rounds. The stale web-app-matomo pin above the primary-only docs entry is dropped, and test_variant_pin_fixed_point.py guards every planned round against unsettled pins and pins above a disabled entry. docs/contributing/artefact/files/role/variants.md explains the settle loop with diagrams.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 5.5 committed 2026-10-31 12:45:53 +01:00
1 parent 8127d61018
commit 76fc6992c4
10 files changed
+935 -173

No files matched your search

@@ -21,11 +21,6 @@ class TestPlanDevInventoryMatrix(unittest.TestCase):
"cli.administration.deploy.development.inventory.legacy_resolver._resolve_round_include",
autospec=True,
)
@patch(
"cli.administration.deploy.development.inventory.legacy_resolver._build_services_overrides_for_round",
autospec=True,
return_value={},
)
@patch(
"cli.administration.deploy.development.inventory.planner.get_variants",
autospec=True,
@@ -33,7 +28,6 @@ class TestPlanDevInventoryMatrix(unittest.TestCase):
def test_single_variant_apps_share_one_unsuffixed_folder(
self,
get_variants_mock: MagicMock,
_overrides_mock: MagicMock,
resolve_include_mock: MagicMock,
) -> None:
get_variants_mock.return_value = {
@@ -63,11 +57,6 @@ class TestPlanDevInventoryMatrix(unittest.TestCase):
"cli.administration.deploy.development.inventory.legacy_resolver._resolve_round_include",
autospec=True,
)
@patch(
"cli.administration.deploy.development.inventory.legacy_resolver._build_services_overrides_for_round",
autospec=True,
return_value={},
)
@patch(
"cli.administration.deploy.development.inventory.planner.get_variants",
autospec=True,
@@ -75,7 +64,6 @@ class TestPlanDevInventoryMatrix(unittest.TestCase):
def test_two_variant_primary_drives_two_suffixed_folders(
self,
get_variants_mock: MagicMock,
_overrides_mock: MagicMock,
resolve_include_mock: MagicMock,
) -> None:
get_variants_mock.return_value = {
@@ -115,11 +103,6 @@ class TestPlanDevInventoryMatrix(unittest.TestCase):
"cli.administration.deploy.development.inventory.legacy_resolver._resolve_round_include",
autospec=True,
)
@patch(
"cli.administration.deploy.development.inventory.legacy_resolver._build_services_overrides_for_round",
autospec=True,
return_value={},
)
@patch(
"cli.administration.deploy.development.inventory.planner.get_variants",
autospec=True,
@@ -127,7 +110,6 @@ class TestPlanDevInventoryMatrix(unittest.TestCase):
def test_round_count_driven_by_primary_max_variants(
self,
get_variants_mock: MagicMock,
_overrides_mock: MagicMock,
resolve_include_mock: MagicMock,
) -> None:
get_variants_mock.return_value = {
@@ -175,11 +157,6 @@ class TestPlanDevInventoryMatrix(unittest.TestCase):
"cli.administration.deploy.development.inventory.legacy_resolver._resolve_round_include",
autospec=True,
)
@patch(
"cli.administration.deploy.development.inventory.legacy_resolver._build_services_overrides_for_round",
autospec=True,
return_value={},
)
@patch(
"cli.administration.deploy.development.inventory.planner.get_variants",
autospec=True,
@@ -187,7 +164,6 @@ class TestPlanDevInventoryMatrix(unittest.TestCase):
def test_purge_set_is_union_when_variants_differ(
self,
get_variants_mock: MagicMock,
_overrides_mock: MagicMock,
resolve_include_mock: MagicMock,
) -> None:
get_variants_mock.return_value = {
@@ -266,11 +242,6 @@ class TestPlanBakesPinnedVariant(unittest.TestCase):
autospec=True,
return_value=("web-app-bar", "web-app-foo"),
)
@patch(
"cli.administration.deploy.development.inventory.legacy_resolver._build_services_overrides_for_round",
autospec=True,
return_value={},
)
@patch(
"cli.administration.deploy.development.inventory.planner.get_variants",
autospec=True,
@@ -278,7 +249,6 @@ class TestPlanBakesPinnedVariant(unittest.TestCase):
def test_round_variants_carry_the_pinned_index(
self,
get_variants_mock: MagicMock,
_overrides_mock: MagicMock,
_include_mock: MagicMock,
_pins_mock: MagicMock,
) -> None: