# Implementation Plan: Global Context Shell Contract

**Branch**: `199-global-context-shell-contract` | **Date**: 2026-04-18 | **Spec**: `specs/199-global-context-shell-contract/spec.md`
**Input**: Feature specification from `specs/199-global-context-shell-contract/spec.md`

**Note**: This plan keeps the work inside the existing Filament v5 / Livewire v4 admin and tenant panels, reuses `WorkspaceContext` as the session-backed storage owner, promotes one request-scoped shell resolution contract over the current split logic, and explicitly avoids new persistence, panel proliferation, or a generic context framework.

## Summary

Cut one explicit workspace-first global shell contract for `/admin` and `/admin/t/{external_id}` by keeping workspace session ownership in `WorkspaceContext`, consolidating active workspace and tenant resolution behind one request-scoped shell contract consumed by `OperateHubShell`, aligning switch/select/clear controllers and `EnsureFilamentTenantSelected` to the same precedence and fallback rules, and reducing the shared `context-bar` partial to a pure consumer and dispatcher of resolved context. Preserve tenant-safe global search, deny-as-not-found isolation, intended-URL handling, and existing Filament panel topology while replacing scattered partial, controller, middleware, and panel-state heuristics with one documented source-of-truth hierarchy and one explicit invalid-context recovery model.

## Contract Ownership

- **Source inventory owner**: `specs/199-global-context-shell-contract/data-model.md` contains the canonical `Context Source Inventory` for every in-scope workspace and tenant context source.
- **Documented recovery destinations**:
  - missing or unrecoverable workspace truth falls back to `/admin/choose-workspace`
  - generic referrer-free or sentinel cleanup falls back to `admin.operations.index`
  - tenant-scoped evidence cleanup falls back to `admin.evidence.overview`
  - tenant-bound cleanup with a valid workspace falls back to `admin.workspace.managed-tenants.index`
  - tenant-bound cleanup without recoverable workspace falls back to `admin.home`
  - tenantless-capable workspace routes and canonical workspace record viewers remain on their current route when entitlement remains valid
- **Workspace switch destination set**:
  - safe intended `/admin...` URL when present and still valid
  - `admin.workspace.managed-tenants.index` when the resolved workspace has zero selectable tenants
  - `/admin/choose-tenant` when the resolved workspace has multiple selectable tenants
  - tenant dashboard route under `/admin/t/{external_id}` when the resolved workspace has exactly one selectable tenant
- **Explicit page-category exceptions**:
  - `/admin/choose-workspace` is the `workspace_chooser_exception` route
  - `/admin/evidence/...` except `/admin/evidence/overview` is treated as `tenant_scoped_evidence` for recovery behavior

## Technical Context

**Language/Version**: PHP 8.4.15  
**Primary Dependencies**: Laravel 12, Filament v5, Livewire v4, Pest v4, Tailwind CSS v4, existing `WorkspaceContext`, `OperateHubShell`, `EnsureFilamentTenantSelected`, `WorkspaceRedirectResolver`, `WorkspaceIntendedUrl`, `TenantPageCategory`, and `ResolvesPanelTenantContext`  
**Storage**: PostgreSQL unchanged plus existing Laravel session keys `current_workspace_id`, `workspace_intended_url`, and `workspace_last_tenant_ids`; no schema change planned  
**Testing**: Pest unit and feature tests, existing Filament or Livewire page tests, and manual shell smoke validation through Laravel Sail; browser automation remains optional and not the proving default  
**Validation Lanes**: fast-feedback, confidence  
**Target Platform**: Laravel monolith web application under `apps/platform`, running via Sail locally, with shared operator shells on `/admin` and `/admin/t/{external_id}` and isolated `/system` remaining out of scope  
**Project Type**: web application  
**Performance Goals**: Keep shell context resolution request-scoped, DB-and-session-only at render time, avoid any outbound HTTP or queued work during shell hydration, avoid additional N+1 tenant lookups in the topbar, and keep context-bar rendering within existing operator-page latency expectations  
**Constraints**: No new persisted truth, no generic context engine, no cross-plane auth redesign, no hidden page-state ownership inside the shell contract, no global navigation rewrite, no dependency changes, and no new asset pipeline requirements  
**Scale/Scope**: 2 shared operator panels, 1 shared context-bar partial, 3 context mutation endpoints, 5 existing core support classes or middleware seams, targeted updates across existing workspace, monitoring, RBAC, and tenant-RBAC feature seams, and 2 to 4 new narrow regression files for shell resolution and recovery

## Constitution Check

*GATE: Passed before Phase 0 research. Re-checked after Phase 1 design and still passing.*

| Principle | Pre-Research | Post-Design | Notes |
|-----------|--------------|-------------|-------|
| Inventory-first / snapshots-second | PASS | PASS | The feature changes shell context truth only. It does not alter inventory, snapshot, or backup product truth. |
| Read/write separation | PASS | PASS | The work changes session-backed scope selection and recovery behavior only. No new Microsoft tenant write, queued work, or operational mutation is introduced. |
| Graph contract path | N/A | N/A | No Microsoft Graph call path is added or modified. |
| Deterministic capabilities | PASS | PASS | Existing workspace and tenant entitlement checks remain authoritative. No new capability strings or auth planes are introduced. |
| Workspace + tenant isolation | PASS | PASS | The design strengthens workspace-first isolation by preventing tenant truth from surviving outside a valid workspace and by standardizing 404 versus tenantless fallback rules. |
| RBAC-UX authorization semantics | PASS | PASS | Non-members remain 404, members without capability remain 403 only after scope is established, and shell context cleanup must not surface inaccessible tenant or workspace truth. |
| Run observability / Ops-UX | PASS | PASS | No `OperationRun` is introduced or changed. Shell resolution and display remain synchronous request work. |
| Data minimization | PASS | PASS | No new persistence, cache mirror, or derived artifact is added; remembered values remain support state only. |
| Proportionality / anti-bloat | PASS WITH JUSTIFIED SOURCE CONTRACT | PASS WITH JUSTIFIED SOURCE CONTRACT | The feature introduces one bounded source-of-truth hierarchy and one bounded runtime state vocabulary because multiple existing classes already resolve the same context with competing rules. It explicitly avoids a generic engine or persisted context model. |
| UI semantics / few layers | PASS | PASS | The plan keeps one thin request-scoped contract and removes partial-owned context logic instead of adding a presenter or UI framework layer. |
| Filament-native UI | PASS | PASS | Existing Filament panels, routes, middleware, and shared partials remain the implementation path. No hand-built alternate shell system is introduced. |
| Filament v5 / Livewire v4 compliance | PASS | PASS | All touched surfaces remain on Filament v5 and Livewire v4 semantics only. |
| Provider registration location | PASS | PASS | No provider registration change is required. Laravel 11+ provider registration remains in `bootstrap/providers.php`. |
| Global search hard rule | PASS | PASS | No new globally searchable resource is introduced. Existing searchable resources keep their View or Edit pages, and the contract explicitly preserves tenant-safe global search behavior under resolved shell scope. |
| Destructive action safety | PASS | PASS | No new destructive Filament action is added. Context reset via `clear-tenant-context` remains a scope action, not a record-destruction action. |
| Asset strategy | PASS | PASS | No new assets or build steps are planned. Existing `cd apps/platform && php artisan filament:assets` deployment handling remains sufficient. |

## Filament-Specific Compliance Notes

- **Livewire v4.0+ compliance**: The implementation stays on Filament v5 and Livewire v4 pages, middleware, support classes, and shared Blade partials. No legacy Livewire or Filament APIs are introduced.
- **Provider registration location**: No panel or provider registration changes are planned. Provider registration remains in `bootstrap/providers.php`.
- **Global search**: No new searchable resources are added. Existing searchable resources remain `TenantResource` and `PolicyResource`, both of which already have View pages, and the shell contract must preserve existing tenant-safe and workspace-safe global search semantics.
- **Destructive actions**: The feature introduces no destructive record actions. Existing shell actions `Switch workspace`, `Select tenant`, and `Clear tenant context` remain scope-setting flows only. Any existing destructive actions elsewhere remain unchanged and continue to require confirmation and authorization under current resource contracts.
- **Asset strategy**: No new JS or CSS assets are planned. Existing deployment handling of `cd apps/platform && php artisan filament:assets` remains unchanged.
- **Testing plan**: Extend or reuse `WorkspaceContextRememberedTenantTest`, `WorkspaceContextTopbarAndTenantSelectionTest`, `WorkspaceContextRecoveryDisplayTest`, `SelectTenantControllerTest`, `ChooseTenantPageTest`, `ChooseWorkspacePageTest`, `ChooseWorkspaceRedirectsToChooseTenantTest`, `WorkspaceRedirectResolverTest`, `WorkspaceSwitchUserMenuTest`, `SwitchWorkspaceRedirectsToTenantRegistrationWhenNoTenantsTest`, `SwitchWorkspaceControllerTest`, `GlobalContextShellContractTest`, `EnsureWorkspaceSelectedMiddlewareTest`, `WorkspacesResourceIsTenantlessTest`, `OperationsIndexHeaderTest`, `AdminGlobalSearchContextSafetyTest`, `TenantSwitcherScopeTest`, `TenantActionSurfaceConsistencyTest`, `OperationsDbOnlyRenderTest`, and `OperationsActionsEnqueueRunTest` so the contract is proven without introducing a new browser or heavy-governance family.

## Test Governance Check

- **Test purpose / classification by changed surface**: Unit for runtime context resolution and invalidation rules in support classes; Feature for controller flows, middleware behavior, panel entry routes, and shared shell rendering.
- **Affected validation lanes**: fast-feedback, confidence.
- **Why this lane mix is the narrowest sufficient proof**: The feature changes request-time scope resolution, redirects, session mutation, and rendered shell truth. These are best proven with unit tests around the support layer plus feature tests over routes and rendered pages. A browser lane is not required unless later implementation introduces client-only shell behavior that feature tests cannot observe.
- **Narrowest proving command(s)**:
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/Workspaces/WorkspaceContextRememberedTenantTest.php`
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/OperateHub/OperateHubShellResolutionTest.php`
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/WorkspaceContextTopbarAndTenantSelectionTest.php`
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Workspaces/SelectTenantControllerTest.php`
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Workspaces/ChooseTenantPageTest.php`
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Workspaces/ChooseWorkspacePageTest.php`
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Workspaces/WorkspaceRedirectResolverTest.php`
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Spec085/OperationsIndexHeaderTest.php`
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Monitoring/OperationsDbOnlyRenderTest.php`
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Monitoring/OperationsActionsEnqueueRunTest.php`
- **Fixture / helper / factory / seed / context cost risks**: Moderate but bounded. Tests need workspace membership, tenant membership, workspace session state, remembered tenant session state, and selective Filament tenant seeding. No new provider bootstraps, seeds, queues, or browser fixtures are expected.
- **Expensive defaults or shared helper growth introduced?**: No. Existing helper seams such as `createUserWithTenant()` and targeted session seeding stay opt-in. The plan should avoid introducing a global full-shell fixture as the new default.
- **Heavy-family additions, promotions, or visibility changes**: none.
- **Non-functional shell-render proof**: Reuse `OperationsDbOnlyRenderTest` and `OperationsActionsEnqueueRunTest` so the shell-anchor workspace surfaces stay DB-only and non-enqueuing during render.
- **Closing validation and reviewer handoff**: Reviewers should confirm that new tests stay in unit and feature lanes, that invalid-context recovery is proven without browser escalation, that shell display and actual resolved context match, and that remembered-tenant invalidation remains explicit in test names and assertions.
- **Budget / baseline / trend follow-up**: none beyond a small increase in focused unit and feature runtime.
- **Review-stop questions**: Is the new proof actually feature-level? Did any helper make full workspace or tenant context implicit by default? Did the implementation create a second source of truth in tests or UI? Did any browser-only assertion sneak in without necessity?
- **Escalation path**: document-in-feature.
- **Why no dedicated follow-up spec is needed**: Test cost remains feature-local as long as the work stays in the existing support layer, controllers, middleware, and shared shell partials without introducing a new test harness or a new browser family.

## Phase 0 Research

Research outcomes are captured in `specs/199-global-context-shell-contract/research.md`.

Key decisions:

- Keep `WorkspaceContext` as the session-backed owner of workspace selection and remembered tenant storage, but stop treating it and `OperateHubShell` as parallel visible truths.
- Use one request-scoped resolved shell contract to unify route tenant, Filament tenant, remembered tenant, and tenantless fallback semantics instead of repeating those rules in controllers, partials, and middleware.
- Preserve the existing effective precedence for active tenant on admin surfaces: valid route tenant first, then explicit tenant selection, then validated query-backed tenant hints only on explicitly allowed workspace-scoped routes, then validated Filament tenant, then remembered tenant only on workspace-scoped pages, with tenant-bound pages rejecting query-hint and remembered fallback.
- Reduce `context-bar.blade.php` to a pure consumer and dispatcher of resolved context instead of letting it re-discover state on its own.
- Make invalid-context recovery explicit and page-category-aware so missing workspace, missing tenant, incompatible tenant, and inaccessible tenant produce deterministic fallback rather than mixed 404, silent clear, or stale shell display behavior.
- Extend existing unit and feature seams instead of introducing a browser-first shell test family.

## Phase 1 Design

Design artifacts are created under `specs/199-global-context-shell-contract/`:

- `research.md`: shell source-of-truth decisions, risks, and rejected alternatives
- `data-model.md`: runtime shell-context entities, validation rules, and state transitions
- `contracts/global-context-shell.logical.openapi.yaml`: internal logical HTTP contract for shell context entry and mutation flows
- `quickstart.md`: implementation and verification workflow for Spec 199

Design highlights:

- Keep the contract derived and request-scoped. No new table or persisted shell artifact is introduced.
- Preserve `WorkspaceContext` as the storage owner and existing route controllers as explicit mutation entry points, but make them consume one resolved shell contract instead of each re-defining fallback behavior.
- Treat `OperateHubShell` as the canonical shared shell resolver for admin-facing context, with tenant-panel-native semantics remaining route-bound and panel-native where appropriate.
- Keep the workspace chooser flow as the explicit current-release `workspace_chooser_exception` instead of letting missing-workspace handling stay implicit.
- Encode invalid-context recovery as explicit outcome types tied to route requirements and `TenantPageCategory`, instead of leaving recovery scattered across `context-bar.blade.php`, `ClearTenantContextController`, and middleware heuristics.
- Keep page-local filters, tabs, inspect state, and other page-state concerns out of the shell contract so tenant-prefilter behavior remains explicit and opt-in.
- Keep `EnsureFilamentTenantSelected` and `ResolvesPanelTenantContext` as consumers of the contract so shared panel behavior does not drift.

## Phase 1 - Agent Context Update

Executed command:

- `.specify/scripts/bash/update-agent-context.sh copilot`

This feature does not add a new language or framework, but the agent-context refresh still runs after design artifacts are complete so the current feature context is recorded in the agent guidance files.

## Project Structure

### Documentation (this feature)

```text
specs/199-global-context-shell-contract/
├── spec.md
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│   └── global-context-shell.logical.openapi.yaml
├── checklists/
│   └── requirements.md
└── tasks.md
```

### Source Code (repository root)

```text
apps/platform/
├── app/
│   ├── Filament/
│   │   └── Concerns/
│   │       ├── ResolvesPanelTenantContext.php                    # MODIFY
│   │       └── ScopesGlobalSearchToTenant.php                    # REUSE / possible small adjust
│   ├── Http/
│   │   └── Controllers/
│   │       ├── SwitchWorkspaceController.php                     # MODIFY
│   │       ├── SelectTenantController.php                        # MODIFY
│   │       └── ClearTenantContextController.php                  # MODIFY
│   ├── Providers/
│   │   └── Filament/
│   │       ├── AdminPanelProvider.php                            # REUSE / possible small adjust
│   │       └── TenantPanelProvider.php                           # REUSE / possible small adjust
│   └── Support/
│       ├── Middleware/
│       │   └── EnsureFilamentTenantSelected.php                  # MODIFY
│       ├── OperateHub/
│       │   └── OperateHubShell.php                               # MODIFY
│       ├── Tenants/
│       │   └── TenantPageCategory.php                            # MODIFY
│       └── Workspaces/
│           ├── WorkspaceContext.php                              # MODIFY
│           ├── WorkspaceIntendedUrl.php                          # REUSE / possible small adjust
│           └── WorkspaceRedirectResolver.php                     # MODIFY
├── resources/
│   └── views/
│       └── filament/
│           └── partials/
│               └── context-bar.blade.php                         # MODIFY
└── tests/
    ├── Unit/
    │   └── Support/
    │       ├── OperateHub/
    │       │   └── OperateHubShellResolutionTest.php             # NEW
    │       └── Workspaces/
    │           └── WorkspaceContextRememberedTenantTest.php      # MODIFY
    └── Feature/
        ├── Filament/
        │   ├── WorkspaceContextTopbarAndTenantSelectionTest.php  # MODIFY
        │   └── WorkspaceContextRecoveryDisplayTest.php           # NEW
    ├── Monitoring/
    │   ├── OperationsActionsEnqueueRunTest.php               # MODIFY / VERIFY
    │   └── OperationsDbOnlyRenderTest.php                    # MODIFY / VERIFY
    ├── Rbac/
    │   ├── AdminGlobalSearchContextSafetyTest.php            # MODIFY
    │   └── TenantActionSurfaceConsistencyTest.php            # MODIFY
        ├── Spec085/
        │   └── OperationsIndexHeaderTest.php                     # MODIFY
    ├── TenantRBAC/
    │   └── TenantSwitcherScopeTest.php                       # MODIFY
        └── Workspaces/
      ├── ChooseTenantPageTest.php                          # MODIFY
      ├── ChooseWorkspacePageTest.php                       # MODIFY
      ├── ChooseWorkspaceRedirectsToChooseTenantTest.php    # MODIFY
      ├── EnsureWorkspaceSelectedMiddlewareTest.php         # MODIFY
      ├── GlobalContextShellContractTest.php                # NEW
      ├── SelectTenantControllerTest.php                    # MODIFY
      ├── SwitchWorkspaceControllerTest.php                 # NEW
            ├── WorkspaceRedirectResolverTest.php                 # MODIFY
            ├── SwitchWorkspaceRedirectsToTenantRegistrationWhenNoTenantsTest.php # MODIFY
      ├── WorkspaceSwitchUserMenuTest.php                   # MODIFY
      └── WorkspacesResourceIsTenantlessTest.php            # MODIFY
```

**Structure Decision**: Keep the work entirely inside the existing Laravel and Filament monolith under `apps/platform`. Reuse current support classes, controllers, middleware, panel providers, and the shared `context-bar` partial. Add only narrow new tests and, if the implementation proves it necessary, a tiny request-scoped result structure inside the existing support layer rather than a new framework directory.

## Complexity Tracking

| Violation | Why Needed | Simpler Alternative Rejected Because |
|-----------|------------|-------------------------------------|
| Bounded new source-of-truth contract and runtime shell-context taxonomy | Multiple existing classes and the shared shell partial already resolve active workspace and tenant context with competing precedence and recovery rules. The feature needs one explicit request-scoped contract to stop drift now. | Pure controller or partial cleanup would keep resolution logic split across `WorkspaceContext`, `OperateHubShell`, middleware, panel state, and the Blade partial, which would preserve the exact ambiguity Spec 199 exists to remove. |

## Proportionality Review

- **Current operator problem**: Operators and reviewers cannot reliably trust the shell to answer where they are operating, which tenant is active, or what a switch or clear action will do.
- **Existing structure is insufficient because**: The current rules live across `WorkspaceContext`, `OperateHubShell`, controllers, middleware, panel tenancy, and `context-bar.blade.php`, so local cleanup in one place cannot produce one shared source of truth.
- **Narrowest correct implementation**: Keep workspace and remembered-tenant storage in the current session-backed support layer, introduce one explicit resolved shell contract for the request, and make existing shell consumers use it. Do not add persistence or a generic engine.
- **Ownership cost created**: Reviewers must maintain one shared shell source hierarchy, one invalid-context taxonomy, and focused unit and feature regression coverage for switch, select, clear, restore, and recovery.
- **Alternative intentionally rejected**: A generic multi-panel context framework was rejected as overproduction, and a partial-only cleanup was rejected as insufficient.
- **Release truth**: current-release operator trust and scope clarity

## Implementation Strategy

### Phase A - Canonicalize one resolved shell context

**Goal**: Replace competing runtime context truths with one request-scoped resolved contract while keeping existing session-backed storage ownership intact.

| Step | File | Change |
|------|------|--------|
| A.0 | `specs/199-global-context-shell-contract/data-model.md` | Maintain the canonical `Context Source Inventory` so every in-scope source has one declared role, one owner, and one validation note. |
| A.1 | `apps/platform/app/Support/OperateHub/OperateHubShell.php` | Expand the shell support seam so it can resolve one canonical shell context for the current request, including workspace, tenant, page category, source precedence, tenantless validity, and invalid-context recovery metadata. |
| A.2 | `apps/platform/app/Support/Workspaces/WorkspaceContext.php` | Keep workspace and remembered-tenant session ownership here, but align helper methods to the canonical contract by making remembered values restore-only and by making invalidation rules explicit and reusable. |
| A.3 | `apps/platform/app/Filament/Concerns/ResolvesPanelTenantContext.php` | Make admin-panel tenant context consumption route through the canonical resolved shell contract instead of ad hoc tenant lookup. |
| A.4 | `apps/platform/tests/Unit/Support/OperateHub/OperateHubShellResolutionTest.php` and `apps/platform/tests/Unit/Support/Workspaces/WorkspaceContextRememberedTenantTest.php` | Add or extend unit coverage for route-first, Filament-tenant, remembered-tenant, tenantless, and invalid remembered-context branches. |

### Phase B - Align explicit scope mutation flows

**Goal**: Make switch, select, clear, restore, and intended-return behavior follow the same source hierarchy and fallback matrix.

| Step | File | Change |
|------|------|--------|
| B.1 | `apps/platform/app/Http/Controllers/SwitchWorkspaceController.php` and `apps/platform/app/Support/Workspaces/WorkspaceRedirectResolver.php` | Ensure workspace switching re-evaluates tenant compatibility deterministically, clears incompatible tenant state, and uses one redirect strategy after intended-URL consumption. |
| B.2 | `apps/platform/app/Http/Controllers/SelectTenantController.php` | Keep explicit tenant selection as the only user-driven tenant activation flow on workspace-level pages, but align it with the canonical shell contract, selector-operability rules, and recovery semantics. |
| B.3 | `apps/platform/app/Http/Controllers/ClearTenantContextController.php` and `apps/platform/app/Support/Tenants/TenantPageCategory.php` | Standardize tenant-clear recovery and route compatibility rules so tenant-required pages, workspace pages, evidence paths, and canonical record viewers resolve either to same-route tenantless workspace state or to the documented destinations `admin.workspace.managed-tenants.index`, `admin.evidence.overview`, `admin.operations.index`, `admin.operations.view`, or `admin.home` as appropriate. |
| B.4 | `apps/platform/app/Support/Workspaces/WorkspaceIntendedUrl.php` | Reuse or slightly refine intended-URL handling so switch and recovery flows return to safe shell-compatible destinations only. |
| B.5 | `apps/platform/tests/Feature/Workspaces/SwitchWorkspaceControllerTest.php`, `SwitchWorkspaceRedirectsToTenantRegistrationWhenNoTenantsTest.php`, `WorkspaceRedirectResolverTest.php`, `SelectTenantControllerTest.php`, and `ChooseWorkspacePageTest.php` | Cover workspace switch redirects, explicit tenant selection, workspace-independent chooser exceptions, tenant compatibility, and invalid or inaccessible context requests. |

### Phase C - Make the shell surfaces consume the contract

**Goal**: Reduce the shared shell UI to one truthful display and action entry point.

| Step | File | Change |
|------|------|--------|
| C.1 | `apps/platform/resources/views/filament/partials/context-bar.blade.php` | Remove partial-owned source precedence and make the topbar display and controls derive only from the canonical resolved shell context and explicit available actions. |
| C.2 | `apps/platform/app/Providers/Filament/AdminPanelProvider.php` and `TenantPanelProvider.php` | Keep the shared render-hook strategy, but adjust only if needed so both panels consume the same shared shell contract without panel-specific truth drift. |
| C.3 | `apps/platform/tests/Feature/Filament/WorkspaceContextTopbarAndTenantSelectionTest.php`, `OperationsIndexHeaderTest.php`, and `WorkspaceContextRecoveryDisplayTest.php` | Cover active tenant display, explicit tenantless display, stale or inaccessible remembered context clearing, and panel-consistent shell output. |

### Phase D - Harden page-category, middleware, and scope-safety behavior

**Goal**: Ensure that route type and access boundaries determine whether tenantless fallback, redirect, or 404 is correct.

| Step | File | Change |
|------|------|--------|
| D.1 | `apps/platform/app/Support/Middleware/EnsureFilamentTenantSelected.php` | Replace ad hoc tenant-selection and navigation heuristics with canonical shell-context checks while preserving tenant-bound route enforcement and workspace isolation. |
| D.2 | `apps/platform/app/Support/Tenants/TenantPageCategory.php` | Tighten route categorization only where current path-pattern rules are too implicit for the new invalid-context matrix, including the explicit `workspace_chooser_exception` and `tenant_scoped_evidence` cases. |
| D.3 | `apps/platform/tests/Feature/Workspaces/GlobalContextShellContractTest.php` | Add focused feature coverage for missing workspace, missing tenant, invalid tenant, inaccessible tenant, tenant-bound route fallback, and workspace-scoped tenantless behavior. |

### Phase E - Close with regression protection and operator verification

**Goal**: Leave the repo with one documented shell contract, narrow regression coverage, and a clear manual validation path.

| Step | File | Change |
|------|------|--------|
| E.1 | Existing unit and feature suites listed above | Extend current tests instead of creating a browser-heavy new family. Keep resolution, redirect, and display assertions explicit in names and expectations. |
| E.2 | `apps/platform/tests/Feature/Monitoring/OperationsDbOnlyRenderTest.php` and `apps/platform/tests/Feature/Monitoring/OperationsActionsEnqueueRunTest.php` | Keep shell-anchor workspace rendering DB-only and non-enqueuing so the contract does not widen runtime behavior accidentally. |
| E.3 | `specs/199-global-context-shell-contract/quickstart.md` | Record implementation order, manual smoke steps, documented fallback targets, and exact verification commands for workspace switch, tenant select, tenant clear, invalid recovery, panel parity, and non-functional render proof. |
| E.4 | `specs/199-global-context-shell-contract/tasks.md` | Break work into dependency-ordered tasks after this plan is accepted. |

## Key Design Decisions

### D-001 - `WorkspaceContext` remains the storage owner, not the visible shell owner

The session-backed workspace and remembered-tenant state already live in `WorkspaceContext`. The right move is to keep it as the storage owner and validation seam, not replace it with persistence or a new framework.

### D-002 - One request-scoped shell contract must replace partial-owned precedence

The shell currently re-discovers scope inside Blade, middleware, and controllers. The plan centralizes that into one request-scoped resolved contract consumed everywhere else.

### D-003 - Route-bound tenant remains strongest on tenant-required surfaces

The existing effective precedence already treats route tenant as strongest, then validated panel tenant, then remembered tenant only on workspace-scoped pages. The plan keeps that precedence but makes it explicit and testable.

### D-004 - Tenant clear and invalid-context recovery need the same route-compatibility matrix

The product currently mixes previous-URL redirecting, silent remembered-context clearing, and 404 behavior. The plan aligns tenant clear and invalid recovery under one page-category-aware outcome matrix.

### D-005 - The context bar becomes a consumer and dispatcher only

The shared shell partial should show the resolved contract and expose explicit switch, select, and clear actions, but it should not be allowed to own a second context truth.