# Implementation Plan: Managed Environment Cutover Final Seal & Regression Guard Pack **Branch**: `299-managed-environment-cutover-final-seal` | **Date**: 2026-05-13 | **Spec**: [spec.md](/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/299-managed-environment-cutover-final-seal/spec.md) **Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/299-managed-environment-cutover-final-seal/spec.md` ## Summary Spec 299 is a final acceptance-and-regression package over the managed-environment cutover. The runtime app tree is already mostly aligned to the canonical owners introduced and hardened by Specs 297 and 298. The implementation therefore stays narrow: - re-run and document the final cutover baseline in `final-cutover-audit.md` - verify the runtime tree remains clean of retired tenant routes and helper generators - seal any remaining workspace-vs-environment navigation or intended-URL seam - bound the last touched product-facing tenant-first copy on active surfaces - classify remaining technical, provider-specific, historical, and guard-only `Tenant` references - run the final focused proof pack and stop with one explicit cutover decision This plan is preparation only. It does not implement application code. ## Technical Context **Language/Version**: PHP 8.4.15 **Primary Dependencies**: Laravel 12.52.0, Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1, Laravel Sail 1.52.0 **Storage**: PostgreSQL through Laravel/Sail for tests; no schema or persistence change planned **Testing**: Pest via `./vendor/bin/sail artisan test --compact`; targeted Browser smoke only for touched visible anchors **Validation Lanes**: Feature/Guards, Feature/Workspaces, Feature/ProviderConnections, Feature/RequiredPermissions, Feature/Filament, selected Browser anchors **Target Platform**: Laravel Sail local runtime and Gitea-compatible CI runners **Project Type**: Laravel web application under `apps/platform` **Performance Goals**: keep the final proof bounded and reproducible; no raw full suite unless explicitly requested **Constraints**: no compatibility routes, no DB/model rename, no broad localization sweep, no provider/RBAC rewrite, no new panel, no new asset strategy **Scale/Scope**: closure of route/link/navigation/copy/test allowlist seams only ## Initial Repo Baseline Preparation checks on 2026-05-13 found: - Current branch before Spec Kit execution was `node-dev`; Spec Kit created and checked out `299-managed-environment-cutover-final-seal`. - The working tree was clean before creating the package. - `docs/product/spec-candidates.md` currently says there is no safe automatic next-best-prep target. Spec 299 is therefore an explicit manual promotion directed by the user, not an auto-selected queue item. - Related existing specs: - `specs/297-managed-environment-canonical-route-cutover/` is dependency context and carries completed-task signals. - `specs/298-managed-environment-terminology-copy-cleanup/` is dependency context and carries completed-task plus checklist review signals. - Neither package may be rewritten back into preparation-only state. - Current canonical owners are already repo-real: - `apps/platform/app/Support/ManagedEnvironmentLinks.php` - `apps/platform/app/Support/Workspaces/WorkspaceIntendedUrl.php` - `apps/platform/app/Support/Workspaces/WorkspaceRedirectResolver.php` - `apps/platform/app/Providers/Filament/AdminPanelProvider.php` - `apps/platform/tests/Feature/Filament/PanelNavigationSegregationTest.php` - `apps/platform/tests/Pest.php` with `setAdminEnvironmentContext()` - A focused baseline scan found no direct retired tenant route/helper hits under `apps/platform/app`, `apps/platform/resources`, or `apps/platform/routes` for `TenantPanelProvider`, `/admin/t`, `/admin/tenants`, old runtime URL generators, or `setTenantPanelContext()`. - The remaining confirmed pressure is in proof depth and residual wording: - `apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php` still contains active workspace-overview labels such as `Accessible tenants` and `No accessible tenants in this workspace`. - `apps/platform/resources/views/filament/pages/workspace-overview.blade.php` still renders `Governance risk counts affected tenants`. - The test tree still contains many technical `TenantResource::getUrl(...)`, `TenantDashboard::getUrl(...)`, retired-path negative assertions, and explicit `setTenantPanelContext` forbidden-pattern guards that now need final classification instead of broad removal. Implementation-readiness note: - The spec package can be prepared now. - Runtime implementation must still honor the start condition from the spec: 298 changes must be committed/merged or intentionally isolated before 299 runtime edits begin. ## UI / Surface Guardrail Plan - **Guardrail scope**: changed workspace/environment navigation proof, workspace overview copy, and guardrail workflow evidence; no new product surface. - **Native vs custom classification summary**: native Filament/Laravel/Blade surfaces plus shared route helpers. - **Shared-family relevance**: navigation registration, context-bar/workspace summary copy, canonical links, intended URLs, and guard tests. - **State layers in scope**: shell, page, detail, URL-query, test helper, and audit artifact. - **Audience modes in scope**: operator-MSP and support-platform. - **Decision/diagnostic/raw hierarchy plan**: keep workspace routes workspace-first and environment routes environment-first; do not surface extra raw/support detail. - **Raw/support gating plan**: unchanged. - **One-primary-action / duplicate-truth control**: no new actions; keep one scope truth per route and remove or document duplicate tenant-first wording. - **Handling modes by drift class or surface**: active runtime seam = fix now; active product copy seam = fix now; technical/provider/historical reference = document in audit; broad rename request = out of scope. - **Repository-signal treatment**: review-mandatory for final scans, navigation proof, helper retirement, browser anchor changes, and allowlist classification. - **Special surface test profiles**: `standard-native-filament`, `global-context-shell`, `browser-smoke` when touched. - **Required tests or manual smoke**: focused guards and feature tests first, browser anchors only for touched visible flows. - **Exception path and spread control**: every surviving `Tenant` reference must be recorded in `final-cutover-audit.md` with reason and guard status. - **Active feature PR close-out entry**: Guardrail / Final Cutover Seal / Smoke Coverage. ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes. - **Systems touched**: - `ManagedEnvironmentLinks` - `WorkspaceIntendedUrl` - `WorkspaceRedirectResolver` - `AdminPanelProvider` - resource/page `shouldRegisterNavigation()` owners - `WorkspaceOverviewBuilder` - `workspace-overview.blade.php` - `setAdminEnvironmentContext()` and focused guard/browser tests - **Shared abstractions reused**: current canonical route helpers, current route-scope navigation owners, existing guard-test patterns, and the existing test helper vocabulary. - **New abstraction introduced? why?**: none planned. Only extend existing route-scope or navigation owners if a concrete live seam is discovered. - **Why the existing abstraction was sufficient or insufficient**: canonical ownership already exists for routes, links, and intended URLs. The remaining issue is final proof, classification, and narrow residual cleanup. - **Bounded deviation / spread control**: technical `Tenant` owners remain allowed only when documented as internal, provider-owned, historical, or regression-guard only. ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: yes, canonical operations link ownership and intended-URL normalization only. - **Central contract reused**: `OperationRunLinks` and `ManagedEnvironmentLinks::operationsUrl(...)`. - **Delegated UX behaviors**: no local lifecycle or notification behavior; only prove that `/admin/operations` resolves safely and retired tenant-scoped operation paths stay dead. - **Surface-owned behavior kept local**: workspace overview summary copy and existing navigation only. - **Queued DB-notification policy**: N/A. - **Terminal notification path**: unchanged. - **Exception path**: none. ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: yes. - **Provider-owned seams**: Microsoft tenant ID, Entra tenant ID, provider target-tenant scope wording, Graph permission wording. - **Platform-core seams**: workspace/environment navigation and operator vocabulary, canonical route ownership, intended URL handling, workspace overview copy. - **Neutral platform terms / contracts preserved**: workspace, environment, managed environment, provider connection, required permissions, diagnostics, operations, findings, evidence, reviews. - **Retained provider-specific semantics and why**: provider-specific `tenant` wording remains only when it describes external Microsoft/Entra truth. - **Bounded extraction or follow-up path**: no new framework. Structural rename remains a separate future topic if ever promoted. ## Constitution Check *GATE: Must pass before runtime implementation and re-check before close-out.* - Inventory-first: no inventory or snapshot truth changes. - Read/write separation: no new write workflow. Any touched destructive action labels must preserve existing confirmation, authorization, and audit behavior. - Graph contract path: no new Graph calls. - Deterministic capabilities: no capability-resolution change. - Workspace isolation: workspace routes remain workspace-safe and must not be overridden by remembered environment context. - Tenant isolation: canonical environment routes remain entitlement-checked; retired tenant routes remain unavailable. - RBAC-UX: non-member/out-of-scope remains 404; member missing capability remains 403. - OperationRun: no new lifecycle semantics; workspace operations links remain canonical. - Proportionality / no premature abstraction: use the existing route and navigation owners; no new framework is justified. - Persisted truth: no new application persistence. The only new artifact is the spec-local cutover audit. - Provider boundary: generic operator vocabulary must stay environment-first; provider-specific tenant wording remains bounded. - Test governance: validation remains in the narrowest honest lanes; no hidden full-suite requirement. - Filament-native UI: Filament remains v5 on Livewire v4, no new panel, no ad hoc styling. ## Filament v5 Output Contract - **Livewire compliance**: Filament v5 targets Livewire v4.0+; current app has Livewire 4.1.4. - **Provider registration location**: provider registration remains in `apps/platform/bootstrap/providers.php`; this package must not restore any retired panel provider. - **Globally searchable resources**: any remaining technical `TenantResource` surface must stay non-primary and must not leak old routes through global search. - **Destructive actions**: any touched restore/remove/archive action must still use `->action(...)`, `->requiresConfirmation()`, and server-side authorization. - **Asset strategy**: unchanged. If implementation unexpectedly registers assets, deployment must include `cd apps/platform && php artisan filament:assets`. - **Testing plan**: touched pages/resources are covered with focused Pest/Filament tests, plus explicit route/helper/copy guards and selected browser anchors. ## Test Governance Check - **Test purpose / classification by changed surface**: Feature guards for route/helper/copy regression, Feature/Filament and Feature/Workspaces for navigation proof, Browser for touched visible anchors only. - **Affected validation lanes**: Feature/Guards, Feature/Workspaces, Feature/ProviderConnections, Feature/RequiredPermissions, Feature/Filament, selected Browser anchors. - **Why this lane mix is the narrowest sufficient proof**: the goal is final cutover sealing, not broad behavior changes. Focused lanes prove route, navigation, copy, and allowlist integrity without reopening unrelated suites. - **Narrowest proving command(s)**: ```bash cd apps/platform ./vendor/bin/sail artisan test --compact \ tests/Feature/Guards/NoLegacyTenantPanelRuntimeTest.php \ tests/Feature/Guards/NoActiveTenantResourceRoutesTest.php \ tests/Feature/Guards/ManagedEnvironmentCanonicalRouteContractTest.php \ tests/Feature/Filament/PanelNavigationSegregationTest.php \ tests/Feature/Workspaces/WorkspaceIntendedUrlLegacyRejectionTest.php ``` - **Fixture / helper / factory / seed / context cost risks**: do not widen `setAdminEnvironmentContext()` or add new expensive defaults to prove this package. - **Expensive defaults or shared helper growth introduced?**: none planned. - **Heavy-family additions, promotions, or visibility changes**: none planned; browser runs stay anchor-only. - **Surface-class relief / special coverage rule**: `standard-native-filament` plus `global-context-shell`; browser only when touched. - **Closing validation and reviewer handoff**: rerun the focused proof pack, final scans, selected lanes, browser anchors if touched, Pint, and `git diff --check`. - **Budget / baseline / trend follow-up**: none expected beyond recording any unexpected browser or guard runtime drift. - **Review-stop questions**: Did any active runtime legacy seam remain? Did workspace navigation still leak environment-owned entries? Did any active product copy remain tenant-first without classification? Did the proof pack stay focused? - **Escalation path**: document-in-feature for allowed references; blocked-by-prerequisite or blocked-by-runtime-finding if 298 is not landed or a live seam remains. - **Active feature PR close-out entry**: Guardrail / Final Cutover Seal / Smoke Coverage. - **Why no dedicated follow-up spec is needed**: this package exists specifically to close the current cutover topic without reopening broader rename work. ## Project Structure ### Documentation (this feature) ```text specs/299-managed-environment-cutover-final-seal/ ├── spec.md ├── plan.md ├── tasks.md ├── final-cutover-audit.md └── checklists/ └── requirements.md ``` ### Source Code (repository root) Likely touched implementation surfaces if a concrete remaining seam is found: ```text apps/platform/app/ ├── Providers/Filament/AdminPanelProvider.php ├── Support/ManagedEnvironmentLinks.php ├── Support/Workspaces/WorkspaceIntendedUrl.php ├── Support/Workspaces/WorkspaceRedirectResolver.php ├── Support/Workspaces/WorkspaceOverviewBuilder.php └── Filament/** apps/platform/resources/views/ └── filament/pages/workspace-overview.blade.php apps/platform/tests/ ├── Pest.php ├── Feature/Guards/** ├── Feature/Workspaces/** ├── Feature/Filament/** └── Browser/** ``` **Structure Decision**: stay inside the existing Laravel/Filament app and spec package shape; do not create new application folders or dependencies. ## Complexity Tracking | Violation | Why Needed | Simpler Alternative Rejected Because | |---|---|---| | Spec-local `final-cutover-audit.md` | The repo needs one durable final acceptance record that separates active drift from allowed references | A one-paragraph close-out would not preserve the allowlist or proof obligations | | Cross-cutting guard pack | The remaining risk spans routes, navigation, intended URLs, copy, and tests | One local cleanup would not seal the cutover topic | ## Phase 0: Start Condition And Safety Gate 1. Run: ```bash git status --short --branch git diff --stat git log -1 --oneline ``` 2. Confirm Spec 298 changes are committed/merged into the implementation base or intentionally isolated in a separate clean worktree/session branch. 3. Stop if unrelated uncommitted changes are present. 4. Read: ```text .specify/memory/constitution.md specs/297-managed-environment-canonical-route-cutover/ specs/298-managed-environment-terminology-copy-cleanup/ ``` ## Phase 1: Baseline Final Cutover Audit Refresh `final-cutover-audit.md` before runtime edits: ```bash git status --short --branch git diff --stat cd apps/platform ./vendor/bin/sail artisan route:list | rg "admin/t|admin/tenants|workspaces/.*/environments|operations|provider-connections|required-permissions" rg "TenantPanelProvider|panel:\s*'tenant'|panel:\s*\"tenant\"|/admin/t/|/admin/tenants|filament\.admin\.resources\.tenants|TenantResource::getUrl|TenantDashboard::getUrl|TenantRequiredPermissions::getUrl|setTenantPanelContext" app resources routes --glob '!vendor' --glob '!node_modules' rg "setTenantPanelContext|panel:\s*'tenant'|panel:\s*\"tenant\"|/admin/t/|/admin/tenants|TenantResource::getUrl|TenantDashboard::getUrl|TenantRequiredPermissions::getUrl" tests --glob '!vendor' --glob '!node_modules' rg "Tenant dashboard|Tenant detail|Open tenant|Select tenant|Tenant scope|Tenant memberships|Remove tenant|Restore tenant|Accessible tenants|affected tenants" app resources lang tests --glob '!vendor' --glob '!node_modules' rg "shouldRegisterNavigation|getNavigationGroup|getNavigationLabel|getNavigationSort|Filament::getTenant|TenantPageCategory|setAdminEnvironmentContext|WorkspaceContext" app tests --glob '!vendor' --glob '!node_modules' ``` Implementation intent: - if the runtime app tree is still clean, keep it that way and move to proof depth - if a live runtime seam appears, fix only that seam - classify every remaining hit as active runtime, test-only, copy-only, provider-specific, internal, historical, or guard-only ## Phase 2: Runtime Final Seal - Inspect `ManagedEnvironmentLinks`, `WorkspaceIntendedUrl`, `WorkspaceRedirectResolver`, and `AdminPanelProvider` as the current canonical owners. - Keep `TenantPanelProvider` absent from the runtime app tree and registration. - Verify `TenantResource`, `TenantDashboard`, and `TenantRequiredPermissions` remain technical-only or route through canonical owners without reviving retired route families. - If a direct runtime legacy hit still exists, replace it with the existing canonical helper or route owner. Do not add compatibility routes or aliases. - Re-run the focused runtime source scan and update `final-cutover-audit.md`. ## Phase 3: Navigation Seal - Re-prove workspace vs environment navigation using the current route, not stale remembered environment state. - Keep workspace surfaces limited to workspace-owned navigation: Overview, Operations, Alerts, Audit Log, Governance inbox, Customer reviews, Manage workspaces, Integrations, Settings. - Keep environment-owned navigation limited to canonical environment routes. - Reuse existing `shouldRegisterNavigation()` and `TenantPageCategory` / route-scope owners rather than inventing a new navigation framework. - Update focused tests or resource/page navigation owners only when the final proof surfaces a live leak. ## Phase 4: Intended URL And Helper Retirement Proof - Re-prove that `WorkspaceIntendedUrl` and `WorkspaceRedirectResolver` reject `/admin/t...` and `/admin/tenants...` paths. - Re-prove that `/admin/operations` only normalizes to the canonical workspace operations route. - Verify `setAdminEnvironmentContext()` remains the current helper. - Leave `setTenantPanelContext` only inside explicit forbidden-pattern guards, if anywhere. ## Phase 5: Product Copy Boundary And Allowlist - Start with the confirmed active workspace-overview copy seams in `WorkspaceOverviewBuilder.php` and `workspace-overview.blade.php`. - Replace touched product-facing tenant-first wording with environment-first wording where the subject is a managed environment. - Leave provider-specific Microsoft/Entra tenant terms untouched when the provider is the subject. - Classify technical/internal/historical/guard-only `Tenant` references in `final-cutover-audit.md` rather than trying to erase the entire repo. ## Phase 6: Final Proof Pack Run the focused proof pack: ```bash cd apps/platform ./vendor/bin/sail artisan test --compact \ tests/Feature/Guards/NoLegacyTenantPanelRuntimeTest.php \ tests/Feature/Guards/NoActiveTenantResourceRoutesTest.php \ tests/Feature/Guards/ManagedEnvironmentCanonicalRouteContractTest.php \ tests/Feature/Guards/WorkspaceEnvironmentNavigationSegregationTest.php \ tests/Feature/Workspaces/WorkspaceIntendedUrlLegacyRejectionTest.php \ tests/Feature/ProviderConnections/LegacyRedirectTest.php \ tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php \ tests/Feature/Spec080WorkspaceManagedTenantAdminMigrationTest.php \ tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php \ tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php ./vendor/bin/sail artisan test --compact tests/Feature/Guards ./vendor/bin/sail artisan test --compact tests/Feature/Workspaces ./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections ./vendor/bin/sail artisan test --compact tests/Feature/RequiredPermissions ./vendor/bin/sail artisan test --compact tests/Feature/Filament ./vendor/bin/sail artisan test --compact \ tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php \ tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php \ tests/Browser/Dashboard/TenantDashboardProductizationSmokeTest.php \ tests/Browser/Spec192RecordPageHeaderDisciplineSmokeTest.php ./vendor/bin/sail bin pint --dirty --format agent ``` Then from the repo root: ```bash git diff --check ``` Finally rerun the route/source scans from Phase 1 and update the audit with the final clean or blocked state. ## Phase 7: Close-Out - Update `final-cutover-audit.md` with final findings, allowlists, commands, and outcomes. - Record the Filament v5 output contract in the implementation summary. - End with one explicit decision string: - `merge-ready; managed environment cutover sealed` - `merge-ready with documented allowed internal Tenant references` - `blocked by active legacy runtime finding` - `blocked by navigation context leak` ## Explicit Follow-Ups / Out Of Scope - DB/model/table rename from `Tenant` to `ManagedEnvironment` - broad historical or documentation copy sweep - provider-architecture rewrite - new RBAC model or new product navigation framework - new feature work unrelated to cutover closure