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

22 KiB

Implementation Plan: Managed Environment Cutover Final Seal & Regression Guard Pack

Branch: 299-managed-environment-cutover-final-seal | Date: 2026-05-13 | Spec: 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):
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)

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:

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:
git status --short --branch
git diff --stat
git log -1 --oneline
  1. Confirm Spec 298 changes are committed/merged into the implementation base or intentionally isolated in a separate clean worktree/session branch.
  2. Stop if unrelated uncommitted changes are present.
  3. Read:
.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:

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:

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:

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