# Implementation Plan: Workspace / Environment Surface Scope Contract **Branch**: `311-workspace-environment-surface-scope-contract` | **Date**: 2026-05-15 | **Spec**: `specs/311-workspace-environment-surface-scope-contract/spec.md` **Input**: Feature specification from `/specs/311-workspace-environment-surface-scope-contract/spec.md` ## Summary Implement the global admin surface scope contract: route scope controls shell/navigation, page filters control data. Explicit workspace-wide surfaces remain tenantless in the shell even with query filters or remembered/Filament tenant context. Canonical environment routes remain environment-bound. Legacy tenant-owned admin lists keep their existing data scoping until a separate route cutover handles them. ## Technical Context **Language/Version**: PHP 8.4, Laravel 12, Filament v5, Livewire v4 **Primary Dependencies**: Existing Filament panel, `TenantPageCategory`, `NavigationScope`, `OperateHubShell`, `CanonicalAdminTenantFilterState` **Storage**: No database changes **Testing**: Pest v4 / Livewire component tests / HTTP feature tests **Validation Lanes**: focused feature/unit tests, Pint dirty, `git diff --check` **Target Platform**: TenantPilot admin panel **Project Type**: Laravel monorepo **Performance Goals**: No extra database work beyond existing widget/list queries **Constraints**: No migrations, no RBAC changes, no Customer Review Workspace product completion, no broad navigation rebuild, no sidebar query magic **Scale/Scope**: Representative workspace-wide surfaces, canonical environment routes, and legacy tenant-owned regression coverage ## UI / Surface Guardrail Plan - **Guardrail scope**: shell scope, topbar labels, sidebar classification, and table/widget filter defaults. - **Native vs custom classification summary**: Filament-native pages/resources/widgets only; no custom styling. - **Shared-family relevance**: global admin navigation shell and workspace-wide monitoring/governance/reporting surfaces. - **State layers in scope**: route path, query filter values, table filter session state, remembered tenant session, Filament tenant context. - **Audience modes in scope**: workspace operator/admin only. - **Decision/diagnostic/raw hierarchy plan**: N/A. - **Raw/support gating plan**: N/A. - **One-primary-action / duplicate-truth control**: prevent duplicate truth by making shell route-owned and filters page-owned. - **Handling modes by drift class or surface**: explicit workspace-wide surfaces become tenantless shell; canonical environment routes remain tenant-bound; legacy tenant-owned lists remain current behavior. - **Repository-signal treatment**: test-first red/green on representative surfaces and parity tests. - **Special surface test profiles**: Livewire tests must set a realistic `referer` when asserting route-derived shell behavior. - **Required tests or manual smoke**: focused Pest/Livewire tests; browser smoke not required because no styling/layout change. - **Exception path and spread control**: future workspace-wide surfaces must be added to `TenantPageCategory` and covered by the surface matrix. - **Active feature PR close-out entry**: Workspace / Environment Surface Scope Contract. ## Shared Pattern & System Fit - **Cross-cutting feature marker**: admin shell/navigation contract. - **Systems touched**: route taxonomy, shell context, workspace-wide filters, monitoring/alerts widgets. - **Shared abstractions reused**: `TenantPageCategory`, `TenantInteractionLane`, `OperateHubShell`, `NavigationScope`, `CanonicalAdminTenantFilterState`. - **New abstraction introduced? why?**: No new service or registry. Existing enum gains `WorkspaceWideSurface`. - **Why the existing abstraction was sufficient or insufficient**: The existing taxonomy already owns page category; it needed one extra category to separate explicit workspace-wide hubs from legacy workspace-scoped tenant-owned lists. - **Bounded deviation / spread control**: explicit path matching stays centralized in `TenantPageCategory`. ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: Yes, Operations list/KPI scope only. - **Central contract reused**: `OperationRunLinks` and existing Operations page remain. - **Delegated UX behaviors**: no start/completion changes. - **Surface-owned behavior kept local**: Operations tabs/table query remain local. - **Queued DB-notification policy**: unchanged. - **Terminal notification path**: unchanged. - **Exception path**: none. ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: provider connections and alerts as workspace-wide/provider-level surfaces. - **Provider-owned seams**: Microsoft-specific inventory/policy/backup legacy tenant-owned lists remain out of this minimal cutover. - **Platform-core seams**: workspace, environment, provider connection, alert delivery, audit log, governance/workspace hubs. - **Neutral platform terms / contracts preserved**: workspace-wide, environment-bound, provider connection, environment filter. - **Retained provider-specific semantics and why**: legacy tenant-owned direct lists retain current tenant data context pending their own route migration. - **Bounded extraction or follow-up path**: 312 Customer Review Workspace v1 Completion follows after this contract; tenant-owned route cutover remains separate. ## Constitution Check - Inventory-first: PASS. No inventory truth changes. - Read/write separation: PASS. Read-only shell/list/widget behavior only. - Graph contract path: PASS. No Graph calls changed. - Deterministic capabilities: PASS. No capability mapping changes. - Workspace isolation: PASS. Workspace query scopes remain enforced. - Tenant isolation: PASS. Environment-bound routes and legacy tenant-owned lists remain protected. - Run observability: PASS. OperationRun data visibility remains entitlement-scoped. - Test governance: PASS. Focused tests plus parity regression; no new heavy family. - Proportionality: PASS. One enum category in an existing taxonomy is narrower than a registry or navigation rebuild. - No premature abstraction: PASS. No new service/interface/framework. - Persisted truth: PASS. No persisted runtime truth. - Behavioral state: PASS. Route category affects shell behavior only. - Shared pattern first: PASS. Existing shell/taxonomy path reused. - Provider boundary: PASS. Platform-core route contract stays provider-neutral. - Filament-native UI: PASS. No assets, no view publishing. ## Test Governance Check - **Test purpose / classification by changed surface**: Feature tests for admin shell and Livewire pages/widgets; Unit test for route category classification. - **Affected validation lanes**: focused Feature/Unit lane. - **Why this lane mix is narrowest sufficient proof**: The bug is route/shell/filter behavior, provable by HTTP and Livewire component tests without browser layout verification. - **Narrowest proving command(s)**: - Focused contract and neighboring surface tests under `tests/Feature/...` - `tests/Unit/Tenants/TenantPageCategoryTest.php` - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - `git diff --check` - **Fixture / helper / factory / seed / context cost risks**: Reuses existing factories/helpers; no new heavy fixture family. - **Expensive defaults or shared helper growth introduced?**: no. - **Heavy-family additions, promotions, or visibility changes**: none. - **Surface-class relief / special coverage rule**: Browser smoke not required; no visual layout/styling change. - **Closing validation and reviewer handoff**: Verify representative workspace-wide surfaces, environment-bound routes, and legacy tenant-owned parity tests. - **Budget / baseline / trend follow-up**: none expected. - **Review-stop questions**: any per-page shell exception, query-driven sidebar, RBAC change, migration, or Customer Review product logic. - **Escalation path**: remaining legacy route taxonomy questions belong to a follow-up route cutover/audit spec. - **Active feature PR close-out entry**: Workspace / Environment Surface Scope Contract. ## Project Structure ```text apps/platform/app/Support/Tenants/TenantPageCategory.php apps/platform/app/Support/Tenants/TenantInteractionLane.php apps/platform/app/Support/OperateHub/OperateHubShell.php apps/platform/app/Filament/Pages/Reviews/* apps/platform/app/Filament/Resources/AlertDeliveryResource.php apps/platform/app/Filament/Resources/ProviderConnectionResource.php apps/platform/app/Filament/Widgets/Alerts/AlertsKpiHeader.php apps/platform/app/Filament/Widgets/Operations/OperationsKpiHeader.php apps/platform/tests/Feature/** apps/platform/tests/Unit/Tenants/TenantPageCategoryTest.php specs/311-workspace-environment-surface-scope-contract/ ``` **Structure Decision**: Extend existing taxonomy and tests in place. Do not introduce a new surface registry. ## Complexity Tracking | Violation | Why Needed | Simpler Alternative Rejected Because | |---|---|---| | Add enum category | Existing `WorkspaceScoped` combined explicit workspace hubs with legacy tenant-owned lists | Forcing all `WorkspaceScoped` tenantless regressed legacy tenant-owned resource data scoping; local page exceptions would spread | ## Proportionality Review - **Current operator problem**: Workspace hubs can display environment context in the shell while also showing page-level environment filters. - **Existing structure is insufficient because**: `WorkspaceScoped` was too broad for both workspace hubs and legacy tenant-owned direct lists. - **Narrowest correct implementation**: Add `WorkspaceWideSurface` to the existing category enum and force tenantless shell only there. - **Ownership cost created**: Future workspace-wide routes must be added centrally with tests. - **Alternative intentionally rejected**: CRW-only patch, `?tenant` sidebar switching, broad nav rewrite, or converting all legacy tenant-owned routes in this branch. - **Release truth**: Current platform shell contract. ## Phase 0: Read-Only Findings - Operations already behaved correctly because it had explicit all-environments/page-filter semantics. - Customer Review Workspace, Review Register, Audit Log, Alerts, and Alert Delivery could inherit remembered/Filament tenant through shell or filter defaults. - Provider Connections defaulted its list filter from the resolved scoped tenant instead of explicit query state. - Legacy tenant-owned resource pages still rely on remembered tenant data context; this branch preserves them and protects them with parity tests. ## Implementation Notes - `TenantPageCategory::fromRequest()` now uses Livewire referer paths for Livewire update requests so shell resolution matches browser route scope. - `WorkspaceWideSurface` covers explicit workspace-wide admin surfaces, including Operations, Reviews workspace/register, Governance Inbox/Decision Register, Evidence Overview, Audit Log, Provider Connections, Alerts, and Workspace Overview. - `OperateHubShell` returns tenantless workspace context before query/Filament/remembered tenant resolution for `WorkspaceWideSurface`. - Customer Review Workspace and Review Register no longer default their environment filters from remembered tenant and no longer clear global last-tenant state when clearing page filters. - Alert Delivery list and Alerts KPI are workspace-wide and no longer use shell tenant as data default. - Operations KPI now counts the workspace entitlement scope when the shell is tenantless. - Provider Connection list filter defaults only from explicit request state, not remembered/global context. ## Validation Plan Run the focused contract and neighboring tests, then Pint and whitespace checks: ```bash cd apps/platform ./vendor/bin/sail artisan test --compact ./vendor/bin/sail bin pint --dirty --format agent cd ../.. git diff --check ``` ## Implementation Close-Out - **Changed runtime areas**: route taxonomy, shell resolution, workspace-wide page filter defaults, Operations KPI, Alerts KPI/list, Provider Connections filter default. - **Changed tests**: focused shell/navigation, Operations, Customer Review Workspace, Review Register, Audit Log, Alerts, Provider Connections, tenant-owned parity, and route category coverage. - **Validation completed**: - `cd apps/platform && ./vendor/bin/sail artisan test --compact ...` for the focused 311 selection: 172 passed, 703 assertions. - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`: pass. - `git diff --check`: pass. - **No migrations**: confirmed. - **No RBAC changes**: confirmed. - **No Customer Review Workspace product logic**: confirmed; only shell/filter-scope behavior changed. - **No asset changes**: confirmed. - **Follow-up**: 312 can continue Customer Review Workspace v1 Completion against this shell contract. ## Filament v5 Output Contract 1. **Livewire v4.0+ compliance**: This app uses Livewire v4 with Filament v5; tests mount Filament Livewire pages/widgets. 2. **Provider registration**: No panel provider registration changes. Laravel 11+/12 provider registration remains in `apps/platform/bootstrap/providers.php`. 3. **Global search**: No globally searchable resource behavior changed. Provider Connection remains globally searchable disabled; Alert Delivery changes do not enable search. 4. **Destructive actions**: No destructive actions added or changed. 5. **Assets**: No assets added or changed; `filament:assets` deployment process unchanged. 6. **Testing**: HTTP feature tests, Livewire component tests, and route category unit tests cover the contract.