# 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.