diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md index 4fd6a40efc..6d3415ca97 100644 --- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md +++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md @@ -118,6 +118,9 @@ work extends shared components instead of creating new local variants. 72. `frontend-modern/src/components/Settings/useSettingsNavigation.ts` 73. `frontend-modern/src/components/Settings/useSettingsPanelRegistry.tsx` 74. `frontend-modern/src/components/Settings/useSettingsSystemPanels.tsx` +75. `frontend-modern/src/components/Settings/DockerRuntimeSettingsCard.tsx` +76. `frontend-modern/src/components/shared/EnvironmentLockBadge.tsx` +77. `frontend-modern/src/utils/environmentLockPresentation.ts` ## Shared Boundaries @@ -1026,6 +1029,15 @@ customer-facing action copy, while provider labels, empty states, and action/status messaging. Future settings copy changes in those areas should extend these helpers instead of inlining panel-local strings inside the shell or reactive state owners. +That same shared primitive boundary now also owns environment-lock +presentation. `frontend-modern/src/components/shared/EnvironmentLockBadge.tsx` +stays the reusable badge shell, +`frontend-modern/src/utils/environmentLockPresentation.ts` owns the canonical +badge label, title, and lock-button copy, and +`frontend-modern/src/components/Settings/DockerRuntimeSettingsCard.tsx` stays +the settings-shell consumer for environment-variable-locked container-update +controls. Future environment-lock UX should extend those owners instead of +reintroducing panel-local lock labels, badge styling, or title copy. First-session runtime framing is now part of that same owned primitive story. `frontend-modern/src/components/SetupWizard/SetupWizard.tsx` must stay on the real two-step runtime shape (`Welcome`, then `Security`) and hand successful diff --git a/docs/release-control/v6/internal/subsystems/registry.json b/docs/release-control/v6/internal/subsystems/registry.json index 46de91a3a1..eb8a365723 100644 --- a/docs/release-control/v6/internal/subsystems/registry.json +++ b/docs/release-control/v6/internal/subsystems/registry.json @@ -2309,6 +2309,7 @@ "frontend-modern/src/components/Settings/diagnosticsModel.ts", "frontend-modern/src/components/Settings/DiagnosticsPanel.tsx", "frontend-modern/src/components/Settings/DiagnosticsResultsPanel.tsx", + "frontend-modern/src/components/Settings/DockerRuntimeSettingsCard.tsx", "frontend-modern/src/components/Settings/GeneralSettingsPanel.tsx", "frontend-modern/src/components/Settings/NetworkBoundarySettingsSection.tsx", "frontend-modern/src/components/Settings/NetworkDiscoverySection.tsx", @@ -2374,6 +2375,7 @@ "frontend-modern/src/utils/diagnosticsPresentation.ts", "frontend-modern/src/utils/discoveryPresentation.ts", "frontend-modern/src/utils/emptyStatePresentation.ts", + "frontend-modern/src/utils/environmentLockPresentation.ts", "frontend-modern/src/utils/problemResourcePresentation.ts", "frontend-modern/src/utils/reportableResourceTypes.ts", "frontend-modern/src/utils/reportingPresentation.ts", @@ -2437,6 +2439,7 @@ "frontend-modern/src/components/Settings/diagnosticsModel.ts", "frontend-modern/src/components/Settings/DiagnosticsPanel.tsx", "frontend-modern/src/components/Settings/DiagnosticsResultsPanel.tsx", + "frontend-modern/src/components/Settings/DockerRuntimeSettingsCard.tsx", "frontend-modern/src/components/Settings/GeneralSettingsPanel.tsx", "frontend-modern/src/components/Settings/NetworkBoundarySettingsSection.tsx", "frontend-modern/src/components/Settings/NetworkDiscoverySection.tsx", @@ -2484,6 +2487,21 @@ "frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts" ] }, + { + "id": "environment-lock-primitives", + "label": "environment lock primitive proof", + "match_prefixes": [], + "match_files": [ + "frontend-modern/src/components/shared/EnvironmentLockBadge.tsx", + "frontend-modern/src/utils/environmentLockPresentation.ts" + ], + "allow_same_subsystem_tests": false, + "test_prefixes": [], + "exact_files": [ + "frontend-modern/src/utils/__tests__/environmentLockPresentation.test.ts", + "frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts" + ] + }, { "id": "route-shell-and-operations", "label": "route shell and operations proof", diff --git a/scripts/release_control/canonical_completion_guard_test.py b/scripts/release_control/canonical_completion_guard_test.py index 038e68a474..3da8f3b52e 100644 --- a/scripts/release_control/canonical_completion_guard_test.py +++ b/scripts/release_control/canonical_completion_guard_test.py @@ -3110,6 +3110,63 @@ index 1111111..2222222 100644 ], ) + def _assert_environment_lock_boundary_requires_frontend_primitives( + self, touched_path: str, requirement_id: str, exact_files: list[str] + ) -> None: + required = infer_impacted_subsystems([touched_path]) + self.assertEqual(set(required), {"frontend-primitives"}) + + frontend = required["frontend-primitives"] + self.assertEqual( + frontend["contract"], + "docs/release-control/v6/internal/subsystems/frontend-primitives.md", + ) + self.assertEqual(frontend["touched_runtime_files"], [touched_path]) + self.assertEqual( + frontend["verification_requirements"], + [ + { + "id": requirement_id, + "label": ( + "settings shell framing proof" + if requirement_id == "settings-shell-and-framing" + else "environment lock primitive proof" + ), + "touched_runtime_files": [touched_path], + "allow_same_subsystem_tests": False, + "test_prefixes": [], + "exact_files": exact_files, + } + ], + ) + + def test_docker_runtime_settings_card_change_requires_frontend_primitives(self): + self._assert_environment_lock_boundary_requires_frontend_primitives( + "frontend-modern/src/components/Settings/DockerRuntimeSettingsCard.tsx", + "settings-shell-and-framing", + ["frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts"], + ) + + def test_environment_lock_badge_change_requires_frontend_primitives(self): + self._assert_environment_lock_boundary_requires_frontend_primitives( + "frontend-modern/src/components/shared/EnvironmentLockBadge.tsx", + "environment-lock-primitives", + [ + "frontend-modern/src/utils/__tests__/environmentLockPresentation.test.ts", + "frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts", + ], + ) + + def test_environment_lock_presentation_change_requires_frontend_primitives(self): + self._assert_environment_lock_boundary_requires_frontend_primitives( + "frontend-modern/src/utils/environmentLockPresentation.ts", + "environment-lock-primitives", + [ + "frontend-modern/src/utils/__tests__/environmentLockPresentation.test.ts", + "frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts", + ], + ) + def test_cloud_paid_entitlement_lease_uses_specific_guardrails(self): rule = next(rule for rule in load_subsystem_rules() if rule["id"] == "cloud-paid") requirements = build_verification_requirements( diff --git a/scripts/release_control/subsystem_lookup_test.py b/scripts/release_control/subsystem_lookup_test.py index bbe31d36f8..61dbb2bbf5 100644 --- a/scripts/release_control/subsystem_lookup_test.py +++ b/scripts/release_control/subsystem_lookup_test.py @@ -3097,6 +3097,61 @@ class SubsystemLookupTest(unittest.TestCase): "security-settings-surfaces", ) + def _assert_environment_lock_lookup( + self, path: str, requirement_id: str, exact_files: list[str] + ) -> None: + result = lookup_paths([path]) + self.assertEqual(result["unowned_runtime_files"], []) + self.assertEqual( + {item["subsystem"] for item in result["impacted_subsystems"]}, + {"frontend-primitives"}, + ) + file_entry = result["files"][0] + self.assertEqual(file_entry["classification"], "runtime") + self.assertEqual( + {match["subsystem"] for match in file_entry["matches"]}, + {"frontend-primitives"}, + ) + match = file_entry["matches"][0] + self.assertEqual( + match["contract"], + "docs/release-control/v6/internal/subsystems/frontend-primitives.md", + ) + self.assertEqual(match["lane_context"]["lane_id"], "L8") + self.assertEqual(match["verification_requirement"]["id"], requirement_id) + self.assertEqual(match["verification_requirement"]["exact_files"], exact_files) + + def test_lookup_paths_assigns_docker_runtime_settings_card_to_frontend_primitives( + self, + ) -> None: + self._assert_environment_lock_lookup( + "frontend-modern/src/components/Settings/DockerRuntimeSettingsCard.tsx", + "settings-shell-and-framing", + ["frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts"], + ) + + def test_lookup_paths_assigns_environment_lock_badge_to_frontend_primitives(self) -> None: + self._assert_environment_lock_lookup( + "frontend-modern/src/components/shared/EnvironmentLockBadge.tsx", + "environment-lock-primitives", + [ + "frontend-modern/src/utils/__tests__/environmentLockPresentation.test.ts", + "frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts", + ], + ) + + def test_lookup_paths_assigns_environment_lock_presentation_to_frontend_primitives( + self, + ) -> None: + self._assert_environment_lock_lookup( + "frontend-modern/src/utils/environmentLockPresentation.ts", + "environment-lock-primitives", + [ + "frontend-modern/src/utils/__tests__/environmentLockPresentation.test.ts", + "frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts", + ], + ) + def test_lookup_paths_assigns_remaining_settings_shell_panels_to_frontend_primitives(self) -> None: runtime_files = [ "frontend-modern/src/components/Settings/APIAccessPanel.tsx",