TenantAtlas/specs/299-managed-environment-cutover-final-seal/plan.md
ahmido b98bafcf86 feat: finalize managed environment cutover seal (#354)
## Summary
- replace the remaining workspace overview tenant-first copy with environment-first wording in the builder, Blade view, and focused feature assertions
- add the Spec 299 workspace overview browser smoke and the final cutover audit documenting fixed copy, clean runtime scans, and allowed internal/provider/regression-guard `Tenant` references
- add the Spec 299 spec package (`spec.md`, `plan.md`, `tasks.md`, checklist, audit) to close the managed-environment cutover with an explicit final seal decision

## Validation
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/WorkspaceOverviewContentTest.php tests/Feature/Filament/AdminHomeRedirectsToChooseTenantWhenWorkspaceSelectedTest.php tests/Feature/Filament/WorkspaceOverviewEmptyStatesTest.php`
- `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 tests/Feature/ProviderConnections/LegacyRedirectTest.php tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php tests/Feature/Spec080WorkspaceManagedTenantAdminMigrationTest.php tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Guards`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Workspaces`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/RequiredPermissions`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec299WorkspaceOverviewCutoverSealSmokeTest.php`
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
- `git diff --check`

## Notes
- Filament remains on Livewire v4.
- Provider registration remains in `apps/platform/bootstrap/providers.php`.
- No new panel provider or asset-strategy changes are included.
- Remaining technical `Tenant` references are documented in `specs/299-managed-environment-cutover-final-seal/final-cutover-audit.md`.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #354
2026-05-13 20:33:30 +00:00

351 lines
22 KiB
Markdown

# 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