# Research: Workspace-first Managed Environment Core Cutover **Date**: 2026-05-06 **Branch**: `279-workspace-managed-environment-core` ## Decision 1: Use one breaking in-place cutover with no `Tenant` compatibility layer - **Decision**: Replace `Tenant` as the active managed-target core directly instead of introducing alias models, dual-read paths, or dual-write migrations. - **Rationale**: The repo is still pre-production, the constitution explicitly rejects speculative compatibility paths, and the current coupling spans too many seams for an adapter layer to stay honest. - **Alternatives considered**: - `Tenant` wrapper over `ManagedEnvironment`: rejected because it would preserve the wrong core truth and spread mixed nouns. - dual columns (`tenant_id` plus `managed_environment_id`): rejected because it would violate the pre-production lean doctrine and make later specs harder, not easier. ## Decision 2: Keep the current `/admin/t/{environment}` path temporarily as the only bounded exception - **Decision**: Allow the existing public `/admin/t/{environment}` path family to remain temporarily while rebinding it to `ManagedEnvironment`. - **Rationale**: The current cutover already replaces the core entity, memberships, query helpers, and panel binding. Folding the full workspace-first public route rewrite into the same slice would collapse Spec `280` into `279` and make the first cutover package too broad. - **Alternatives considered**: - immediate public route-family rewrite: rejected because it belongs to Spec `280` and would widen review scope too far. - second compatibility route family: rejected because the cutover must not carry two public path families at once. ## Decision 3: Replace current tenant-context helpers in place instead of layering new adapters - **Decision**: Retarget or rename the existing tenant-context seams (`WorkspaceContext`, Filament panel binding, resource query helpers, global-search helpers, route builders) in place. - **Rationale**: The current helper seams are the correct ownership points. A new parallel `ManagedEnvironmentContext` layer wrapped around tenant helpers would create drift immediately. - **Alternatives considered**: - keep tenant helpers and add environment adapters: rejected because it creates a second context vocabulary. - local page-by-page context replacement: rejected because the problem is cross-cutting and shared. ## Decision 4: Keep `ManagedEnvironment` provider-neutral and defer provider extraction to Spec `281` - **Decision**: `ManagedEnvironment` owns neutral managed-target identity only. Provider-specific fields such as Entra tenant IDs, Graph configuration, domains, or consent details stay outside the new root entity. - **Rationale**: The whole point of the cutover is to stop provider-specific semantics from defining the platform core. The repo already has provider-owned seams that can carry this data until Spec `281` normalizes them. - **Alternatives considered**: - copy current `Tenant` provider fields to `ManagedEnvironment`: rejected because it would deepen Microsoft coupling. - extract provider profiles in the same slice: rejected because Spec `281` already owns that follow-up. ## Decision 5: Retarget membership semantics without broad RBAC redesign - **Decision**: Replace current tenant-membership truth with managed-environment membership truth while preserving current workspace and capability semantics. - **Rationale**: The cutover needs environment-scoped access control to keep current pages safe, but a broader RBAC scope redesign is already reserved for Spec `285`. - **Alternatives considered**: - leave memberships tenant-shaped temporarily: rejected because the active root model would still leak tenant-core assumptions. - widen capabilities or role families now: rejected because that would collapse Spec `285` into the core cutover. ## Decision 6: Use unit + feature + browser + guard checks as the narrowest honest proof - **Decision**: Plan one managed-environment unit family, one feature family, one browser smoke, and one legacy-core guard family. - **Rationale**: The cutover changes both internal identity rules and end-to-end context selection. Feature tests alone are not enough to prove the shell/chooser still works, and browser coverage alone would hide legacy-core drift. - **Alternatives considered**: - feature tests only: rejected because the cutover changes end-to-end context entry. - heavy-governance or multi-browser rollout: rejected because the slice is core infrastructure, not new multi-surface behavior. ## Final Research Outcome - `279` should remain the breaking core entity cutover only. - The only allowed public-path deviation is temporary `/admin/t/{environment}` retention while it binds `ManagedEnvironment`. - Existing tenant-context seams should be replaced in place, not wrapped. - `ManagedEnvironment` must stay provider-neutral. - Membership semantics move with the core entity, but broader RBAC redesign remains deferred. - Unit, feature, browser, and guard coverage together are the narrowest honest proof.