TenantAtlas/specs/299-managed-environment-cutover-final-seal/spec.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

31 KiB

Feature Specification: Managed Environment Cutover Final Seal & Regression Guard Pack

Feature Branch: 299-managed-environment-cutover-final-seal
Created: 2026-05-13
Status: Ready
Input: User-provided Spec 299 prompt: final hardening, regression guards, and cutover closure for the workspace-first managed-environment migration after Specs 297 and 298.

Spec Candidate Check (mandatory - SPEC-GATE-001)

  • Problem: The managed-environment cutover is close to done, but the repo still lacks one final seal package that proves the runtime core stays off retired tenant routes, that workspace surfaces remain workspace-scoped even with stale environment context, and that remaining Tenant terms are either removed from active product UI or explicitly allowlisted.
  • Today's failure: Contributors can still see broad legacy test and copy surfaces, including technical TenantResource::getUrl(...) / TenantDashboard::getUrl(...) usages in tests, workspace overview copy such as Accessible tenants, and route-scope-sensitive navigation that must stay sealed against remembered environment context. Without a final proof pack, future work can accidentally revive retired product truths even if the app tree currently looks clean.
  • User-visible improvement: Operators get one final, credible cutover state: workspace-first navigation on workspace pages, explicit environment drill-down on canonical environment routes, no revived /admin/t... or /admin/tenants... runtime paths, and environment-first copy on the touched active surfaces.
  • Smallest enterprise-capable version: Refresh a final cutover audit, prove the runtime app tree remains clean, seal any last workspace-vs-environment navigation or intended-URL seam, bound active product copy, classify remaining technical/provider/historical Tenant references, and add the final focused regression guard pack.
  • Explicit non-goals: No database/model/table rename from Tenant to ManagedEnvironment, no compatibility routes, no dual-read or dual-write, no new product workflow, no new RBAC model, no provider-model rewrite, no package execution, no guided operations, no AI workflow, no generic historical-doc cleanup, and no raw full-suite requirement by default.
  • Permanent complexity imported: One spec-local final-cutover-audit.md artifact, a final focused guard/validation pack, and at most narrow adjustments to existing navigation or link owners if a concrete remaining seam is found. No new application persistence, status family, framework, or broad UI layer is introduced.
  • Why now: Specs 297 and 298 already did the cutover and terminology cleanup work. The next safe move is to close the topic with one final seal package before unrelated features reintroduce tenant-first runtime or workspace/environment drift.
  • Why not local: The remaining risk spans canonical links, intended URL handling, navigation registration, workspace overview copy, guard tests, browser smokes, and explicit allowlists. A one-file cleanup would not make the cutover traceable or durable.
  • Approval class: Cleanup
  • Red flags triggered: cross-cutting final hardening across routes, navigation, tests, and copy. Defense: the scope is intentionally closure-only, tied to already prepared Specs 297 and 298, and explicitly forbids reopening broader rename or architecture work.
  • Score: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 2 | Wiederverwendung: 2 | Gesamt: 11/12
  • Decision: approve

Start Condition

  • Spec 299 implementation may start only after Spec 298 changes are either committed/merged into the implementation base or explicitly isolated in a separate clean worktree/session branch.
  • Do not begin 299 implementation on a dirty intermediate 298 state.
  • Before runtime edits, run git status --short --branch and git diff --stat, then document any pre-existing changes that are intentionally carried into the 299 implementation branch.

Summary

Spec 299 is the final seal package for the managed-environment cutover. It does not open a new product lane. It proves and, only if necessary, finishes the current product truth:

  • no active /admin/t/... or /admin/tenants/... runtime paths
  • no active runtime link generators back to retired tenant surfaces
  • no workspace-level environment navigation leak from stale session or Filament::getTenant() state
  • no callable retired setTenantPanelContext() helper
  • no product-facing tenant-first wording on the touched active cutover surfaces
  • an explicit allowlist for remaining technical, provider-specific, guard-only, or historical Tenant references
  • a final proof pack that keeps the cutover sealed

Spec Scope Fields (mandatory)

  • Scope: canonical-view
  • Primary Routes:
    • Retired and forbidden as active product truth: /admin/t/..., /admin/tenants/...
    • Canonical workspace home: /admin/workspaces/{workspace}
    • Canonical managed-environment list/detail: /admin/workspaces/{workspace}/environments, /admin/workspaces/{workspace}/environments/{environment}
    • Canonical environment child routes: /admin/workspaces/{workspace}/environments/{environment}/required-permissions, /diagnostics, /access-scopes, and other repo-real child routes
    • Canonical workspace operations: /admin/workspaces/{workspace}/operations and /admin/workspaces/{workspace}/operations/{run}
  • Data Ownership:
    • No persistence change.
    • Workspace remains the primary SaaS context.
    • Managed environment remains the secondary managed target context.
    • Internal Tenant model/class/table naming may remain technical implementation truth where a structural rename is out of scope.
  • RBAC:
    • Workspace membership remains the primary access boundary.
    • Managed-environment access scope remains narrowing-only and must not become role authority.
    • Non-member or out-of-scope access remains 404.
    • Established member missing capability remains 403.

For canonical-view specs:

  • Default filter behavior when tenant-context is active: remembered environment context may survive as a secondary drill-down hint, but route scope decides navigation, intended URL acceptance, and which surface is primary. Workspace surfaces remain workspace-scoped even if an environment is remembered.
  • Explicit entitlement checks preventing cross-tenant leakage: WorkspaceIntendedUrl and WorkspaceRedirectResolver must reject retired tenant paths, ManagedEnvironmentLinks must derive canonical URLs from explicit workspace/environment scope, and any canonical environment or operations route must keep existing workspace and managed-environment entitlement checks.

Goals

G1 - Final active legacy scan is clean

The final route/source scans must show no active runtime hits for /admin/t/..., /admin/tenants/..., TenantPanelProvider, retired tenant panel IDs, retired runtime URL generators, or setTenantPanelContext() in the runtime app tree.

G2 - Workspace/environment navigation is sealed

Workspace surfaces may expose workspace-owned navigation only. Environment-owned primary navigation must appear only on canonical environment routes.

Runtime links must stay owned by ManagedEnvironmentLinks, RequiredPermissionsLinks, OperationRunLinks, or the current canonical route owner. Retired tenant route generators must not become active product truth again.

G4 - Intended URL handling cannot revive retired paths

Stored intended URLs must reject retired tenant paths and only normalize safe canonical workspace operations routes.

G5 - Product-facing tenant terminology is bounded

Touched active product surfaces should use environment-first wording where the subject is a managed environment. Provider-specific Microsoft/Entra tenant wording remains allowed only when the external provider is the subject.

G6 - Guard pack prevents regression

The final proof pack must make it difficult to reintroduce retired tenant routes, tenant-panel helper semantics, or workspace/environment navigation leaks.

Required Artifact

Create or update:

specs/299-managed-environment-cutover-final-seal/final-cutover-audit.md

This audit must track:

  • active runtime legacy findings
  • test legacy findings
  • copy findings
  • allowed references
  • final route/source scan results
  • final validation commands and outcomes

Cross-Cutting / Shared Pattern Reuse (mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, alerts, navigation entry points, evidence/report viewers, or any other existing shared operator interaction family; otherwise write N/A - no shared interaction family touched)

  • Cross-cutting feature?: yes
  • Interaction class(es): navigation registration, canonical environment links, intended URL handling, workspace overview summary metrics and copy, guard tests, browser smokes, and allowlist auditing.
  • Systems touched:
    • 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
    • resource/page shouldRegisterNavigation() owners under apps/platform/app/Filament/**
    • apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php
    • apps/platform/resources/views/filament/pages/workspace-overview.blade.php
    • apps/platform/tests/Pest.php
    • apps/platform/tests/Feature/Filament/PanelNavigationSegregationTest.php
    • focused guard/browser tests that still mention retired tenant routes or technical Tenant* owners
  • Existing pattern(s) to extend: ManagedEnvironmentLinks, WorkspaceIntendedUrl, WorkspaceRedirectResolver, OperationRunLinks, TenantPageCategory, existing navigation registration closures, setAdminEnvironmentContext(), and the current guard-test pattern.
  • Shared contract / presenter / builder / renderer to reuse: the existing canonical route helpers and route-scope navigation owners named above; no new shared framework is justified.
  • Why the existing shared path is sufficient or insufficient: the runtime app tree is already mostly aligned to the canonical owners. The missing closure is one final proof/audit layer, plus narrow fixes only if the final baseline still exposes a live seam.
  • Allowed deviation and why: technical Tenant class/model/table names, provider-specific Microsoft/Entra tenant language, and guard-regex strings may remain when explicitly classified in final-cutover-audit.md.
  • Consistency impact: runtime links, workspace/environment navigation, intended URL handling, workspace overview copy, and the focused proof pack must all agree on the same workspace-first / environment-drilldown product truth.
  • Review focus: reviewers must verify that 299 does not reopen broader rename work, does not preserve compatibility routes, and does not leave any unclassified product-facing tenant-first seams.
  • Touches OperationRun start/completion/link UX?: yes, link and redirect ownership only.
  • Shared OperationRun UX contract/layer reused: OperationRunLinks plus ManagedEnvironmentLinks::operationsUrl(...) for workspace-scoped operations entry points.
  • Delegated start/completion UX behaviors: no new toast, status, or notification behavior. The only required proof is that legacy intended URLs do not restore retired tenant-scoped operation paths and that workspace operations remain canonical.
  • Local surface-owned behavior that remains: workspace overview and environment detail surfaces keep their current local labels and calls to the shared link owners.
  • Queued DB-notification policy: N/A.
  • Terminal notification path: unchanged.
  • Exception required?: none.

Provider Boundary / Platform Core Check (mandatory when the feature changes shared provider/platform seams, identity scope, governed-subject taxonomy, compare strategy selection, provider connection descriptors, or operator vocabulary that may leak provider-specific semantics into platform-core truth; otherwise write N/A - no shared provider/platform boundary touched)

  • Shared provider/platform boundary touched?: yes
  • Boundary classification: mixed
  • Seams affected: operator vocabulary, provider connection scope language, required-permissions wording, workspace/environment route labels, and allowed technical Tenant references.
  • Neutral platform terms preserved or introduced: workspace, managed environment, environment, provider connection, required permissions, diagnostics, access scope, operation, finding, evidence, review.
  • Provider-specific semantics retained and why: Microsoft tenant ID, Entra tenant ID, and provider target-tenant wording remain allowed only where the external provider is the subject.
  • Why this does not deepen provider coupling accidentally: the spec narrows tenant wording to provider-owned or technical-only seams while keeping platform-core navigation and operator UI environment-first.
  • Follow-up path: document-in-feature for allowed technical/provider references; follow-up-spec only for future structural DB/model rename.

UI / Surface Guardrail Impact (mandatory when operator-facing surfaces are changed; otherwise write N/A)

Surface / Change Operator-facing surface change? Native vs Custom Shared-Family Relevance State Layers Touched Exception Needed? Low-Impact / N/A Note
Workspace overview and sidebar scope yes Native Filament + shared builders navigation, summary metrics, context copy shell, page no closure-only; no redesign
Canonical environment detail/readiness surfaces yes Native Filament + shared route helpers environment navigation, page/back links, detail copy page, detail no prove the current environment drill-down remains canonical
Final cutover audit and guard pack no direct operator surface N/A guard tests, scans, audit evidence docs, tests no repo-proof only

Decision-First Surface Role (mandatory when operator-facing surfaces are changed)

Surface Decision Role Human-in-the-loop Moment Immediately Visible for First Decision On-Demand Detail / Evidence Why This Is Primary or Why Not Workflow Alignment Attention-load Reduction
Workspace overview and sidebar scope Primary Decision Surface Operator chooses whether to stay at workspace scope or drill into one environment workspace summary, allowed workspace navigation, explicit environment drill-down affordance environment details, diagnostics, and evidence remain on child surfaces Primary because the workspace home is the first scope decision after the cutover Workspace first, environment second prevents stale environment context from hijacking workspace navigation
Canonical environment detail/readiness surfaces Secondary Context Surface Operator follows one selected environment into detail, permissions, or diagnostics selected environment identity and current environment-owned navigation diagnostics, provider detail, raw support content Secondary because the environment route supports a decision already made at workspace scope explicit drill-down from workspace to environment avoids mixed workspace/environment affordances on the same page

Audience-Aware Disclosure (mandatory when operator-facing surfaces are changed)

Surface Audience Modes In Scope Decision-First Default-Visible Content Operator Diagnostics Support / Raw Evidence One Dominant Next Action Hidden / Gated By Default Duplicate-Truth Prevention
Workspace overview and sidebar scope operator-MSP, support-platform workspace summary metrics, calmness/attention framing, workspace-owned navigation environment-specific follow-up only through explicit drill-down none beyond existing support tools choose environment or view workspace operations environment-owned navigation on workspace surfaces one scope truth per route
Canonical environment detail/readiness surfaces operator-MSP, support-platform selected environment context, current readiness or workload state provider readiness, diagnostics, evidence provider/raw support detail only where already allowed continue environment workflow on the current canonical route workspace-only actions remain secondary or absent current environment route owns the environment story

UI/UX Surface Classification (mandatory when operator-facing surfaces are changed)

Surface Action Surface Class Surface Type Likely Next Operator Action Primary Inspect/Open Model Row Click Secondary Actions Placement Destructive Actions Placement Canonical Collection Route Canonical Detail Route Scope Signals Canonical Noun Critical Truth Visible by Default Exception Type / Justification
Workspace overview and sidebar scope Dashboard / Navigation Workspace-first overview choose environment or review operations direct page load on workspace home N/A current summary drill-downs and navigation items unchanged; existing destructive actions stay elsewhere /admin/workspaces/{workspace} N/A workspace only Workspace / Environment workspace-first scope and allowed nav none
Canonical environment detail/readiness surfaces Detail / Readiness Environment-scoped detail open the current environment area or remediate readiness canonical environment route N/A existing detail/header actions unchanged and still confirmation-gated where destructive /admin/workspaces/{workspace}/environments /admin/workspaces/{workspace}/environments/{environment} workspace + environment Environment / Managed environment selected environment and current child navigation none

Operator Surface Contract (mandatory when operator-facing surfaces are changed)

Surface Primary Persona Decision / Operator Action Supported Surface Type Primary Operator Question Default-visible Information Diagnostics-only Information Status Dimensions Used Mutation Scope Primary Actions Dangerous Actions
Workspace overview and sidebar scope Workspace operator Decide whether to stay at workspace scope or drill into one environment overview What needs attention in this workspace before I narrow scope? workspace summary metrics, allowed navigation, scope framing none beyond existing linked surfaces calmness, attention, activity none Choose environment, View operations none added
Canonical environment detail/readiness surfaces Workspace operator Continue environment-specific investigation or remediation environment detail/readiness What needs action in this environment? environment identity, environment navigation, current readiness/action context provider detail, diagnostics, support/raw detail readiness, governance result, activity existing environment-owned actions only existing page-owned actions existing destructive actions only

Proportionality Review (mandatory when structural complexity is introduced)

  • New source of truth?: no
  • New persisted entity/table/artifact?: yes, one spec-local audit artifact only
  • New abstraction?: no application abstraction by default; the implementation may only extend existing route-scope helpers if a live seam is confirmed
  • New enum/state/reason family?: no
  • New cross-domain UI framework/taxonomy?: no
  • Current operator problem: without one final proof package, the cutover can quietly drift back toward retired tenant routes or mixed workspace/environment truth.
  • Existing structure is insufficient because: Specs 297 and 298 prepared and cleaned the main seams, but the remaining test, copy, and regression burden is spread across multiple owners and lacks one final acceptance artifact.
  • Narrowest correct implementation: one closure spec that proves the app tree stays clean, fixes only confirmed remaining seams, and classifies everything else.
  • Ownership cost: one audit file plus focused guard maintenance.
  • Alternative intentionally rejected: a broad rename or another foundational cutover spec. That would reopen work already intentionally kept out of scope.
  • Release truth: current-release closure in a pre-production environment.

Compatibility posture

This feature assumes a pre-production environment.

Backward compatibility routes, legacy helper aliases, migration shims, historical fixture preservation for runtime behavior, and compatibility-specific runtime tests are out of scope unless they already exist as explicit negative regression guards.

Canonical replacement or explicit rejection is preferred over preservation.

User Scenarios & Testing (mandatory)

User Story 1 - Retired Tenant Runtime Stays Sealed (Priority: P1)

As a maintainer, I need the final cutover proof to show that no active runtime route or link generator revives /admin/t/... or /admin/tenants/... behavior.

Why this priority: This is the core cutover promise. If it regresses, the product truth is no longer workspace-first.

Independent Test: Run the focused route/source/guard proof pack and verify representative retired paths return 404 while canonical environment and workspace operations links remain valid.

Acceptance Scenarios:

  1. Given an authenticated workspace member, When they request a representative retired tenant path such as /admin/t/{id} or /admin/tenants/{id}, Then the response is 404.
  2. Given the runtime app tree, When the final legacy scan runs, Then no active retired route/helper pattern remains under apps/platform/app, apps/platform/resources, or apps/platform/routes.

User Story 2 - Workspace Navigation Wins Over Stale Environment Context (Priority: P1)

As an operator, I need workspace pages to stay workspace-scoped even when the session remembers an environment or Filament::getTenant() still holds one.

Why this priority: Mixed workspace/environment navigation makes the cutover feel unfinished and can mislead operators about scope.

Independent Test: Exercise workspace overview and canonical environment routes with remembered environment context and verify the sidebar changes by route scope, not by stale environment state.

Acceptance Scenarios:

  1. Given a remembered environment and a workspace overview request, When the page renders, Then only workspace-owned navigation is visible.
  2. Given the canonical environment detail route, When the page renders, Then environment-owned navigation appears again.

User Story 3 - Remaining Tenant References Are Honest And Bounded (Priority: P2)

As a reviewer, I need every remaining Tenant reference to be either fixed or explicitly classified so future work can tell the difference between product drift and allowed technical/provider/historical wording.

Why this priority: The remaining legacy footprint is broadest in tests and copy. Unclassified references create noisy audits and invite accidental regressions.

Independent Test: Refresh the final audit, run the copy/test scans, and verify every remaining hit is marked fixed, allowed-provider-term, allowed-internal-model, allowed-historical, or allowed-regression-guard.

Acceptance Scenarios:

  1. Given an active product-facing workspace or environment surface, When the cutover copy scan runs, Then remaining tenant-first wording is either removed or intentionally allowed because it is provider-specific.
  2. Given a technical test or guard, When it still mentions TenantResource, TenantDashboard, /admin/t, or setTenantPanelContext, Then the final audit states why that reference remains safe.

Edge Cases

  • What happens when a remembered environment belongs to the current workspace but the current route is workspace-only? The page must stay workspace-scoped and suppress environment-owned navigation.
  • What happens when an intended URL points to /admin/operations with query data? It may normalize only to the canonical workspace operations route, not to any retired tenant-scoped operations path.
  • What happens when a string contains tenant but the subject is Microsoft/Entra provider identity? The wording may remain only when the external provider is the actual subject.

Functional Requirements

  • FR-001 No active retired tenant routes: route:list and focused request tests must prove that /admin/t/... and /admin/tenants/... are not active product routes.
  • FR-002 Tenant runtime owners stay technical-only or retired: if TenantResource, TenantDashboard, or TenantRequiredPermissions remain in code, they must not restore primary admin navigation, global search entries, or retired route families.
  • FR-003 Canonical managed-environment link ownership is preserved: runtime environment links remain owned by ManagedEnvironmentLinks, RequiredPermissionsLinks, OperationRunLinks, or the current canonical route owner.
  • FR-004 Workspace intended URL rejection is final: WorkspaceIntendedUrl and WorkspaceRedirectResolver must reject retired tenant paths and only normalize safe workspace operations routes.
  • FR-005 Route-scope-first navigation is final: workspace routes render workspace-only navigation, canonical environment routes render environment-owned navigation, and stale remembered environment context does not override route scope.
  • FR-006 Retired tenant-panel helper remains retired: no callable setTenantPanelContext() alias may exist; remaining string hits may survive only inside explicit forbidden-pattern guards.
  • FR-007 Product-facing tenant terminology is bounded: touched active UI surfaces use environment-first wording where the subject is a managed environment.
  • FR-008 Remaining tenant references are explicitly allowlisted: the final audit must classify every remaining Tenant reference that survives the final scans.
  • FR-009 No broad refactors: the implementation must not reopen DB/model rename, provider refactor, package execution, guided operations, or generic historical-doc cleanup.
  • FR-010 Final cutover audit is maintained: final-cutover-audit.md must capture baseline findings, final findings, validation commands, and the final decision string.

Non-Functional Requirements

  • The validation mix must stay focused to guard/feature/browser anchors relevant to the cutover; no raw full suite is required unless explicitly requested.
  • Filament v5 / Livewire v4 compliance remains explicit, and provider registration stays in apps/platform/bootstrap/providers.php.
  • The package must stay implementation-bounded: fix only confirmed remaining seams and document everything else.
  • Final proof commands must be explicit, reproducible, and small enough for a bounded implementation loop.

Out Of Scope

  • Database, model, namespace, or table rename from Tenant to ManagedEnvironment
  • Migration or historical data rewrite
  • Reintroducing compatibility routes or compatibility aliases
  • New product features, new operations workflows, or new navigation families
  • Broad localization project or historical docs/spec rewrite
  • Provider architecture refactor or new RBAC model
  • Raw full-suite enforcement without explicit user instruction

Acceptance Criteria

  • AC-001: route:list does not expose /admin/t or /admin/tenants as active routes.
  • AC-002: no active runtime route/helper pattern for retired tenant surfaces remains under apps/platform/app, apps/platform/resources, or apps/platform/routes.
  • AC-003: ManagedEnvironmentLinks, WorkspaceIntendedUrl, and WorkspaceRedirectResolver remain the canonical owners for environment detail, intended URLs, and workspace operations redirects.
  • AC-004: workspace overview does not show environment-owned navigation, even with remembered environment session data or Filament::getTenant() state.
  • AC-005: canonical environment routes still show the intended environment-owned navigation entries.
  • AC-006: no callable setTenantPanelContext() helper remains.
  • AC-007: touched active product-facing copy no longer uses tenant-first wording when the subject is a managed environment.
  • AC-008: every remaining Tenant reference that survives final scans is documented as allowed technical, provider-specific, historical, or regression-guard only.
  • AC-009: the focused proof pack, feature lanes, browser anchors, final route/source scans, Pint, and git diff --check all pass or the failure is explicitly recorded as a blocker.
  • AC-010: the final report ends with one explicit decision string for the cutover seal.

Success Criteria

  • Reviewers can answer "is the managed-environment cutover sealed?" from one spec package without reopening 297 or 298.
  • The final audit distinguishes active product drift from allowed technical/provider/historical references.
  • The implementation loop can stop with a clear decision instead of vague residual cleanup.

Risks

  • Spec 298 runtime changes may not yet be landed in the exact implementation base, so 299 could otherwise mix closure work with unfinished navigation/copy cleanup.
  • The remaining test surface is broad and uses technical Tenant* owners heavily; without disciplined classification, the audit can become noisy or overreach.
  • Workspace overview copy and navigation are easy to drift because they mix workspace summary, environment drill-down, and operations entry points.

Assumptions

  • Specs 297 and 298 remain authoritative context and must not be rewritten back into preparation-only state.
  • The runtime app tree already follows the canonical route owners unless the final baseline uncovers a concrete exception.
  • Internal Tenant model/class naming is still allowed as technical implementation detail for this release.

Open Questions

  • None blocking. The only prerequisite boundary is implementation timing: Spec 298 changes must be committed or cleanly isolated before 299 runtime work begins.

Definition Of Done

Spec 299 is done when:

  1. The baseline audit is recorded in final-cutover-audit.md.
  2. Any confirmed active runtime legacy seam is fixed without restoring compatibility paths.
  3. Workspace/environment navigation segregation is re-proven.
  4. Intended URL rejection is re-proven.
  5. Touched active product copy is environment-first.
  6. Remaining Tenant references are classified in the allowlist.
  7. The focused proof pack, lanes, browser anchors, scans, Pint, and diff check are recorded.
  8. The final decision string is explicit.

Final Output Required

At implementation close-out, report:

  1. Commands run and outcomes.
  2. Runtime legacy closure findings.
  3. Workspace vs environment navigation classification.
  4. Remaining allowed Tenant references and why they remain.
  5. Test results.
  6. One final 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