# Research: Tenant Selector and Remembered Context Enforcement ## Decision 1: Keep active-lane selector eligibility anchored in `TenantOperabilityService` **Decision**: Use `App\Services\Tenants\TenantOperabilityService` as the single authoritative rule for standard selector membership and require the header selector, choose-tenant page, and selection controllers to converge on that service. **Rationale**: The service already encapsulates lifecycle-aware operability and exposes `canSelectAsContext()` and `filterSelectable()`. Spec 147 needs consistency, not a second selector rule. Reusing this service directly keeps Spec 143 lifecycle semantics intact and avoids per-surface drift. **Alternatives considered**: - Build a new selector-specific eligibility service: rejected because it would duplicate `canSelectAsContext()` semantics and create a new place for lifecycle drift. - Let each surface query `status = active` independently: rejected because it would bypass existing operability semantics and repeat the exact fragmentation this spec is intended to remove. ## Decision 2: Centralize remembered tenant revalidation in `WorkspaceContext` **Decision**: Make `App\Support\Workspaces\WorkspaceContext` the authoritative place that validates, returns, clears, and invalidates remembered tenant context for active-lane use. **Rationale**: `WorkspaceContext` already owns the session map keyed by workspace and already clears stale remembered IDs when workspace or lifecycle checks fail. It is the natural home for enforcing the workspace-scoped preference contract required by Spec 147. **Alternatives considered**: - Revalidate remembered tenant context separately in controllers, Livewire pages, and Blade partials: rejected because it preserves scattered raw-session truth assumptions. - Move remembered-context validation into `OperateHubShell`: rejected because shell resolution should consume validated context, not become the storage owner. ## Decision 3: Keep the custom workspace-first shell instead of reverting to Filament's default tenant switcher **Decision**: Continue using the existing custom context bar and custom choose-tenant page, but align both to one active-lane rule set. **Rationale**: The product architecture is explicitly workspace first. Filament's tenant switcher is tenant-menu-centric, while this app already uses a workspace-scoped shell, explicit workspace switching, and canonical workspace-level routes. Docs confirm Filament tenant menu customization exists, but the custom shell is already the correct product pattern here. **Alternatives considered**: - Replace the custom selector with Filament's built-in tenant switcher: rejected because it would pull the product back toward a tenant-first mental model and would not solve the workspace-scoped remembered-context rules already present in the app. - Keep the custom shell but allow it to diverge from the choose-tenant page: rejected because Spec 147 explicitly requires shared semantics between both selector surfaces. ## Decision 4: Treat route authority and shell context as separate layers **Decision**: Preserve route-authority semantics for tenant-bound and canonical routes and use shell context only for convenience, not for legitimacy. **Rationale**: `OperationRunPolicy` already authorizes canonical runs by workspace membership, tenant entitlement, and capability checks. `TenantlessOperationRunViewer` already renders non-blocking context banners. Spec 147 should extend this pattern consistently through shell resolution instead of reintroducing tenant-context-coupled validity at the page level. **Alternatives considered**: - Use selected tenant equality as a fast validity shortcut for tenant-bound or canonical pages: rejected because it conflicts with Specs 143 and 144 and causes false invalidity. - Auto-switch the selected tenant to match the route record: rejected because it makes page rendering mutate user context implicitly and hides the distinction between route subject and current active lane. ## Decision 5: “No tenant selected” is a first-class valid shell state **Decision**: Treat no-selected-tenant as the correct fallback state for workspace-level pages after invalidation, workspace switch, or explicit clear. **Rationale**: Workspace-level surfaces such as `/admin` and `/admin/operations` are legitimate without an active tenant. Spec 147 requires graceful degradation to a valid workspace-wide view instead of hidden failure when remembered context becomes stale. **Alternatives considered**: - Force tenant reselection before allowing workspace-level pages: rejected because it would contradict the workspace-first architecture. - Keep stale remembered tenant until the user manually clears it: rejected because it would preserve hidden authority and inconsistent page behavior. ## Decision 6: No schema change is required for this feature **Decision**: Implement Spec 147 as behavior consolidation over existing session-backed workspace tenant preferences and existing user preference persistence paths. **Rationale**: The app already stores current workspace in session and last tenant IDs in a workspace-keyed session map, with supplemental persistence through `users.last_tenant_id` or `user_tenant_preferences`. The problem is validation and consumption semantics, not missing storage. **Alternatives considered**: - Introduce a new tenant-context table or richer persisted context model: rejected because the spec explicitly says remembered tenant context is a convenience preference, not a durable parallel ownership model. - Persist no tenant preference at all: rejected because remembered context remains a supported convenience feature within the workspace-scoped shell.