# Feature Specification: Workspace Hub Navigation Context Contract

**Feature Branch**: `314-workspace-hub-navigation-context-contract`
**Created**: 2026-05-16
**Status**: Draft
**Input**: User-supplied Spec 314 draft plus Spec 313 audit results.
**Runtime posture**: Hard cutover. No backwards compatibility layer. No legacy query alias support for sidebar/global workspace hub entry.

## Spec Candidate Check *(mandatory - SPEC-GATE-001)*

- **Problem**: Workspace-scoped admin hubs can inherit stale Managed Environment context from shell state, remembered environment state, query params, Filament tenant state, Livewire table state, and persisted filters.
- **Today's failure**: Spec 313 browser evidence shows operators can see "No environment selected" or "All environments" while rows remain environment-filtered. Provider Connections, Finding Exceptions Queue, Customer Review Workspace, Operations, Review Register, Governance Inbox, and Decision Register are the highest-risk surfaces.
- **User-visible improvement**: Sidebar/global navigation into workspace hubs becomes deterministic: selected Workspace remains active, active Managed Environment context is cleared, URLs are clean, and rows are workspace-wide by default.
- **Smallest enterprise-capable version**: One canonical workspace hub contract used by sidebar/global navigation and the affected workspace hub pages to strip environment query state and neutralize environment-like persisted filters on workspace hub entry.
- **Explicit non-goals**: No Environment Dashboard CTA contract, no universal clear-filter contract, no product IA redesign, no route alias compatibility, no data migration, no seed/backfill work, no broad environment-page conversion.
- **Permanent complexity imported**: A narrow workspace hub registry/contract and focused Pest/Livewire/Browser coverage. No new persisted tables, models, enums, status families, OperationRun types, or asset bundles.
- **Why now**: Spec 313 completed browser verification and explicitly recommends Spec 314 first because sidebar/global workspace hub entry must be safe before Environment CTA filters and clear-filter semantics are standardized.
- **Why not local**: Page-by-page URL fixes would keep context ownership fragmented. The failure crosses navigation generation, shell resolution, query parameters, resource `getUrl()` overrides, and persisted Filament table filters.
- **Approval class**: Core Enterprise.
- **Red flags triggered**: New registry abstraction; provider-adjacent Provider Connections scope; broad surface count. Defense: the abstraction is narrow, current-release, and required for workspace isolation and navigation safety across more than two concrete surfaces.
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 2 | Wiederverwendung: 2 | **Gesamt: 11/12**
- **Decision**: approve.

## Spec Scope Fields *(mandatory)*

- **Scope**: canonical-view.
- **Primary routes**:
  - `/admin`
  - `/admin/workspaces/{workspace}/overview`
  - `/admin/workspaces/{workspace}/operations`
  - `/admin/provider-connections`
  - `/admin/finding-exceptions/queue`
  - `/admin/evidence/overview`
  - `/admin/reviews`
  - `/admin/reviews/workspace`
  - `/admin/governance/inbox`
  - `/admin/governance/decisions`
  - `/admin/audit-log`
  - `/admin/alerts`
  - `/admin/alerts/alert-deliveries`
  - `/admin/alerts/alert-rules`
  - `/admin/alerts/alert-destinations`
  - `/admin/settings/workspace`
  - `/admin/workspaces`
  - `/admin/workspaces/{workspace}/environments`
- **Data ownership**: No ownership model changes. Workspace-owned and tenant-owned records keep existing ownership. Workspace hub views must enforce workspace membership and managed-environment entitlement before revealing tenant-owned rows.
- **RBAC**: Workspace membership remains required. Existing capability checks remain in force. Non-member workspace/environment access remains deny-as-not-found. Member-but-missing-capability remains 403 where the current policy/capability contract uses 403.

For canonical-view specs:

- **Default filter behavior when tenant-context is active**: Sidebar/global workspace hub entry ignores active or remembered Managed Environment context and opens workspace-wide. Explicit Environment CTA filtering remains allowed only where already present and is standardized later in Spec 315.
- **Explicit entitlement checks preventing cross-tenant leakage**: Workspace-wide data queries must include current workspace scope and must limit environment-bound rows to the Managed Environments the actor is entitled to access.

## Summary

Implement the canonical Workspace Hub Navigation Context Contract for TenantPilot.

Workspace-scoped hubs must open workspace-wide when reached through sidebar/global navigation. They must not inherit Managed Environment context through route/query params, Filament tenant state, remembered environment state, Livewire mounted state, persisted Filament table filters, or page-specific URL builders.

Canonical behavior:

```text
Sidebar / global navigation -> workspace-scoped hub -> workspace-wide state
```

Environment-specific filtering from Environment Dashboard CTAs is not productized in this spec. It belongs to Spec 315.

## Product Context

TenantPilot is workspace-first. Workspace is the primary operating context. Managed Environment is a secondary operational context inside a Workspace.

Workspace hubs are portfolio/workspace surfaces. They may display tenant-owned rows, but their entry point is workspace-wide and entitlement-filtered, not environment-owned.

Environment pages remain environment-owned and are not converted by this spec.

## Cross-Cutting / Shared Pattern Reuse *(mandatory)*

- **Cross-cutting feature?**: yes.
- **Interaction class(es)**: navigation, shell/context state, table filter state, canonical links.
- **Systems touched**: `WorkspaceSidebarNavigation`, `AdminPanelProvider`, `TenantPageCategory`, `NavigationScope`, `OperateHubShell`, `WorkspaceContext`, `CanonicalAdminTenantFilterState`, page/resource URL builders, and high-risk Filament pages/resources from Spec 313.
- **Existing pattern(s) to extend**: existing workspace navigation builder, `TenantPageCategory::WorkspaceWideSurface`, `NavigationScope`, `WorkspaceContext`, and `CanonicalAdminTenantFilterState`.
- **Shared contract / presenter / builder / renderer to reuse**: reuse existing navigation and shell/context helpers where safe; introduce one narrow `WorkspaceHubRegistry` only for workspace hub identity and environment-param/filter neutralization rules.
- **Why the existing shared path is sufficient or insufficient**: existing paths know pieces of the contract but no single path answers whether a page is a workspace hub, whether environment params must be stripped, and whether environment-like persisted filters must be ignored on sidebar/global entry.
- **Allowed deviation and why**: introduce a narrow registry because more than two concrete workspace hubs need the same decision and because isolation/navigation correctness is security-relevant current-release truth.
- **Consistency impact**: all sidebar/global workspace hub URLs must use the same forbidden query-param list and the same remembered-environment bypass behavior.
- **Review focus**: verify no page-specific `getUrl()` override or helper can inject environment params into sidebar/global workspace hub URLs.

## OperationRun UX Impact *(mandatory)*

- **Touches OperationRun start/completion/link UX?**: no OperationRun start, completion, queuing, dedupe, status, outcome, terminal notification, or run lifecycle semantics are changed.
- **Shared OperationRun UX contract/layer reused**: `OperationRunLinks::index()` may be adjusted only for clean workspace hub navigation; OperationRun start UX is not in scope.
- **Delegated start/completion UX behaviors**: N/A.
- **Local surface-owned behavior that remains**: existing Operations list and operation detail behavior remain.
- **Queued DB-notification policy**: N/A.
- **Terminal notification path**: N/A.
- **Exception required?**: none.

## Provider Boundary / Platform Core Check *(mandatory)*

- **Shared provider/platform boundary touched?**: yes, Provider Connections and provider-adjacent links are in scope.
- **Boundary classification**: mixed. Provider Connections records are provider-adjacent, but the navigation context contract is platform-core.
- **Seams affected**: Provider Connection list URL generation, provider connection environment prefilter behavior, `managed_environment_id` query semantics, remembered environment fallback.
- **Neutral platform terms preserved or introduced**: Workspace, Managed Environment, provider connection, workspace hub.
- **Provider-specific semantics retained and why**: Microsoft-specific provider details remain inside existing provider connection records/actions. This spec must not introduce Microsoft-shaped platform navigation truth.
- **Why this does not deepen provider coupling accidentally**: the contract removes hidden environment/provider-specific query inference from workspace hub navigation instead of adding a provider framework.
- **Follow-up path**: Spec 315 standardizes explicit Environment CTA filtering; Spec 317 removes remaining legacy tenant/environment naming and alias drift.

## UI / Surface Guardrail Impact *(mandatory)*

| Surface / Change | Operator-facing surface change? | Native vs Custom | Shared-Family Relevance | State Layers Touched | Exception Needed? | Low-Impact / `N/A` Note |
|---|---|---|---|---|---|---|
| Workspace hub sidebar/global entry | yes | Native Filament navigation + existing shell | navigation / shell / table filters | shell, URL-query, page, session filters | no | State-contract hardening only; no redesign. |
| Provider Connections / Integrations | yes | Native Filament Resource | navigation / provider connection list | URL-query, table query, remembered env | no | Must open workspace-wide from sidebar/global entry. |
| Finding Exceptions Queue | yes | Native Filament Page | navigation / queue | URL-query, table filters, session filters | no | Sidebar/global entry must not use `tenant`. |
| Operations | yes | Native Filament Page | monitoring state page | URL-query, table filters, shell | no | Sidebar/global entry must not carry `managed_environment_id`. |
| Decision Register / Governance Inbox | yes | Native Filament Pages | governance navigation | URL-query, access check, filters | no | Clean workspace Decision Register URL must open for authorized users. |
| Customer Reviews / Reviews / Evidence | yes | Native Filament Pages | reporting / evidence viewers | URL-query, table filters, session filters | no | Sidebar/global entry must neutralize stale environment filters. |

## Decision-First Surface Role *(mandatory when operator-facing surfaces are changed)*

| Surface | Decision Role | Human-in-the-loop Moment | Immediately Visible for First Decision | On-Demand Detail / Evidence | Why This Is Primary or Why Not | Workflow Alignment | Attention-load Reduction |
|---|---|---|---|---|---|---|---|
| Workspace hub sidebar/global navigation | Secondary Context | Operator moves between workspace work areas | Workspace selected, no environment selected, workspace-wide rows | Existing page diagnostics | Not a new decision surface; it ensures existing surfaces start from truthful scope | Workspace-first navigation | Removes hidden stale environment state from routine navigation. |
| Critical workspace hubs | Existing role unchanged | Existing per-page decisions remain | Existing per-page content, now with correct default scope | Existing page details | Spec changes entry scope, not page purpose | Workspace hubs remain workspace-wide | Prevents operators from reconstructing hidden filters. |

## Audience-Aware Disclosure *(mandatory when operator-facing surfaces are changed)*

| Surface | Audience Modes In Scope | Decision-First Default-Visible Content | Operator Diagnostics | Support / Raw Evidence | One Dominant Next Action | Hidden / Gated By Default | Duplicate-Truth Prevention |
|---|---|---|---|---|---|---|---|
| Workspace hub entry state | operator-MSP, support-platform | Workspace selected; no environment selected; no hidden environment filter | Existing filter controls and page diagnostics | Existing support/raw areas unchanged | Open selected workspace hub | Raw query/table state is not surfaced as a product feature | Shell and data scope must agree. |

## UI/UX Surface Classification *(mandatory when operator-facing surfaces are changed)*

| Surface | Action Surface Class | Surface Type | Likely Next Operator Action | Primary Inspect/Open Model | Row Click | Secondary Actions Placement | Destructive Actions Placement | Canonical Collection Route | Canonical Detail Route | Scope Signals | Canonical Noun | Critical Truth Visible by Default | Exception Type / Justification |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Workspace hub navigation contract | Navigation / Context | Workspace hub entry | Open hub workspace-wide | Existing page-defined model | Existing behavior | Existing page-defined placement | Existing page-defined placement | See registry table | Existing page-defined routes | Workspace active, Environment none | Workspace hub | No hidden environment filter from sidebar/global entry | none |

## Operator Surface Contract *(mandatory when operator-facing surfaces are changed)*

| Surface | Primary Persona | Decision / Operator Action Supported | Surface Type | Primary Operator Question | Default-visible Information | Diagnostics-only Information | Status Dimensions Used | Mutation Scope | Primary Actions | Dangerous Actions |
|---|---|---|---|---|---|---|---|---|---|---|
| Workspace hub entry state | MSP operator | Move from any page to a workspace hub without stale environment scope | Navigation/context contract | Which workspace context am I operating in? | Current workspace, no selected environment, workspace-wide list state | Existing page-specific diagnostics | Scope only | N/A | Open hub | None added or changed |

## Proportionality Review *(mandatory when structural complexity is introduced)*

- **New source of truth?**: no persisted source of truth.
- **New persisted entity/table/artifact?**: no.
- **New abstraction?**: yes, a narrow workspace hub registry/contract.
- **New enum/state/reason family?**: no.
- **New cross-domain UI framework/taxonomy?**: no.
- **Current operator problem**: sidebar/global navigation into workspace hubs can silently inherit stale environment context and show filtered rows under a workspace-wide shell.
- **Existing structure is insufficient because**: page category, shell resolution, navigation builders, URL helpers, and table filter helpers each own partial state decisions; no single shared contract owns workspace hub identity and entry cleanup.
- **Narrowest correct implementation**: one static/support registry listing workspace hub routes/pages and the environment-like query/filter keys to strip or ignore on sidebar/global entry.
- **Ownership cost**: maintain hub membership when workspace hubs are added or reclassified; add contract tests that fail when a workspace hub URL leaks environment-like params.
- **Alternative intentionally rejected**: page-by-page patches without a registry, because Spec 313 proves the same drift across Provider Connections, Operations, Finding Exceptions, Reviews, Evidence, Governance, Alerts, and Audit.
- **Release truth**: current-release truth. Spec 313 browser evidence makes this a present safety issue, not future preparation.

### Compatibility posture

This feature assumes a pre-production environment. Backward compatibility, legacy aliases, migration shims, historical fixtures, and compatibility-specific tests are out of scope. Canonical replacement is preferred over preservation.

No legacy `tenant`, `tenant_id`, `managed_environment_id`, `environment_id`, `tenant_scope`, or `tableFilters` behavior is preserved for sidebar/global workspace hub entry.

## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*

- **Test purpose / classification**: Feature, Filament/Livewire, and Browser.
- **Validation lane(s)**: confidence for focused Feature/Livewire tests; browser for critical user flows; `git diff --check`; focused route/navigation tests.
- **Why this classification and these lanes are sufficient**: URL generation and shell/data scope can be proven with Feature and Livewire tests; browser verification is required because Spec 313 showed persisted Filament table state, reload, and back/forward behavior can drift after hydration.
- **New or expanded test families**: bounded Spec 314 navigation context tests and one focused browser smoke. No broad suite rebaseline.
- **Fixture / helper cost impact**: tests may need explicit workspace, two Managed Environments, memberships, and rows for the covered pages. Helpers must stay feature-local or opt-in.
- **Heavy-family visibility / justification**: Browser coverage is explicit and limited to critical flows inherited from Spec 313.
- **Special surface test profile**: global-context-shell + monitoring-state-page + exception-coded-surface.
- **Standard-native relief or required special coverage**: no styling/layout verification; special state-contract coverage required.
- **Reviewer handoff**: reviewers must confirm lane fit, no hidden heavy helper defaults, and no broad browser family beyond the named Spec 314 smoke.
- **Budget / baseline / trend impact**: none expected; document if browser lane expands materially.
- **Escalation needed**: document-in-feature.
- **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage.
- **Planned validation commands**:
  - `cd apps/platform && ./vendor/bin/sail artisan test --filter=WorkspaceHub`
  - `cd apps/platform && ./vendor/bin/sail artisan test --filter=ProviderConnectionsWorkspaceHub`
  - `cd apps/platform && ./vendor/bin/sail artisan test --filter=FindingExceptionsQueueWorkspaceHub`
  - `cd apps/platform && ./vendor/bin/sail artisan test --filter=OperationsWorkspaceHub`
  - `cd apps/platform && ./vendor/bin/sail artisan test --filter=DecisionRegisterWorkspaceHub`
  - `cd apps/platform && ./vendor/bin/sail artisan test --filter=CustomerReviewWorkspaceHub`
  - `cd apps/platform && ./vendor/bin/sail artisan test --filter=EvidenceOverviewWorkspaceHub`
  - `cd apps/platform && ./vendor/bin/sail artisan test --filter=Spec314WorkspaceHubNavigationContextSmoke`
  - `git diff --check`

## User Scenarios & Testing *(mandatory)*

### User Story 1 - Sidebar workspace hubs always open workspace-wide (Priority: P1)

As an MSP operator working inside an active Managed Environment, I can click a workspace-scoped hub in the sidebar/global navigation and land on a workspace-wide version of that hub without hidden environment filters.

**Why this priority**: This removes the most dangerous Spec 313 mismatch: shell says no environment selected while page data is still environment-filtered.

**Independent Test**: From an Environment Dashboard state with a remembered environment, generate/open each registry workspace hub sidebar URL and assert it has no forbidden environment query params and renders with no active environment shell context.

**Acceptance Scenarios**:

1. **Given** a selected Workspace and remembered Managed Environment, **When** the operator opens Provider Connections through sidebar/global navigation, **Then** the URL is clean and provider connection rows are workspace-wide across entitled environments.
2. **Given** a selected Workspace and active Environment Dashboard state, **When** the operator opens Finding Exceptions Queue, Operations, Decision Register, Customer Reviews, Reviews, Evidence, Governance Inbox, Audit Log, Alerts, Workspace Settings, or Manage Workspaces through sidebar/global navigation, **Then** no environment query params or environment-like table filters define the default scope.

### User Story 2 - Remembered environment is not a workspace hub data boundary (Priority: P1)

As an MSP operator, my last used Managed Environment may still help the switcher, but it must not silently filter workspace hubs.

**Why this priority**: Spec 313 shows remembered environment state can leak into links and shell decisions.

**Independent Test**: Seed two environments in one workspace, remember Environment A, then open workspace hub URLs and assert Environment A is not used as a URL param, shell context, default table filter, or data query boundary.

**Acceptance Scenarios**:

1. **Given** Environment A is remembered for a workspace, **When** sidebar/global Provider Connections URL is generated, **Then** it does not include `managed_environment_id`.
2. **Given** Environment A is remembered and rows exist for Environment A and B, **When** a workspace hub opens from sidebar/global navigation, **Then** entitled rows are not filtered to Environment A.

### User Story 3 - Persisted environment filters cannot override sidebar intent (Priority: P2)

As an operator returning to a workspace hub after previous filtering, sidebar/global entry must be workspace-wide even if a page persisted an environment-like table filter earlier.

**Why this priority**: Spec 313 found reload and back/forward behavior can revive stale filters.

**Independent Test**: Persist an environment table filter for Customer Reviews, Finding Exceptions Queue, Evidence, Provider Connections, and Operations where applicable; navigate away; then enter through sidebar/global clean URL and assert environment-like persisted filters are absent or ignored.

**Acceptance Scenarios**:

1. **Given** Customer Reviews was filtered to Environment A, **When** the operator enters Customer Reviews through sidebar/global navigation, **Then** the page opens workspace-wide and reload remains workspace-wide.
2. **Given** Evidence Overview or Finding Exceptions Queue had a persisted environment-like table filter, **When** the operator enters through workspace hub navigation, **Then** that filter does not define the default row scope.

### User Story 4 - Decision Register clean workspace URL is a valid workspace hub entry (Priority: P2)

As an authorized workspace user, I can open Decision Register through its clean workspace URL without needing an environment filter.

**Why this priority**: Spec 313 found the clean Decision Register route returned 403 while a filtered URL opened.

**Independent Test**: Seed a workspace user with decision visibility and open `/admin/governance/decisions` without environment query params; assert it is not forbidden and does not require a Managed Environment query.

**Acceptance Scenarios**:

1. **Given** an authorized workspace user with visible decision register access, **When** they open the clean Decision Register URL, **Then** the page opens without `managed_environment_id`.
2. **Given** no open decisions exist but the user is authorized to the workspace register, **When** they open the clean Decision Register URL, **Then** the page shows a truthful empty workspace state rather than requiring an environment filter.

### Edge Cases

- A workspace hub direct URL is opened with forbidden query params. The page may still support explicit CTA filters until Spec 315, but sidebar/global navigation must not generate those params.
- Browser back returns to an old filtered URL. This spec verifies sidebar/global re-entry and focused back/forward behavior; full universal clear-filter behavior belongs to Spec 316.
- A page is actually environment-owned. It must not be put in the workspace hub registry; environment pages remain outside this spec.
- A user lacks workspace membership. Existing deny-as-not-found behavior remains.
- A user is a workspace member but lacks a capability needed for a hub. Existing capability semantics remain; this spec must not bypass authorization.

## Requirements *(mandatory)*

### Functional Requirements

- **FR-001**: The implementation MUST create or formalize one canonical workspace hub registry/contract.
- **FR-002**: The registry MUST identify whether a route/page is a workspace-scoped hub.
- **FR-003**: The registry MUST identify whether sidebar/global navigation must clear active Managed Environment shell context for that hub.
- **FR-004**: The registry MUST provide the forbidden sidebar/global query-param list: `tenant`, `tenant_id`, `managed_environment_id`, `environment_id`, `tenant_scope`, and `tableFilters`.
- **FR-005**: The registry MUST provide the environment-like persisted filter keys to neutralize for workspace hub entry: `tenant`, `tenant_id`, `managed_environment_id`, `environment_id`, `environment`, and `tenant_scope`.
- **FR-006**: Sidebar/global URLs for every registry workspace hub MUST be clean and MUST NOT include forbidden environment query params.
- **FR-007**: Sidebar/global workspace hub entry MUST clear or bypass active Managed Environment shell context while preserving selected Workspace context.
- **FR-008**: Remembered Managed Environment state MUST NOT be used as sidebar URL input, workspace hub default data filter, workspace hub authorization boundary, shell context, or fallback route parameter.
- **FR-009**: Workspace hubs MUST NOT use `Filament::getTenant()` or remembered environment as a hidden default data boundary on sidebar/global entry.
- **FR-010**: Environment-like persisted Filament table filters MUST NOT override sidebar/global workspace hub intent.
- **FR-011**: Provider Connections sidebar/global entry MUST be workspace-wide and MUST NOT inject `managed_environment_id` from remembered context.
- **FR-012**: Finding Exceptions Queue sidebar/global entry MUST be workspace-wide and MUST NOT use `tenant` query for sidebar/global entry.
- **FR-013**: Operations sidebar/global entry MUST be workspace-wide and MUST NOT carry `managed_environment_id`, `tenant_scope`, or `tableFilters`.
- **FR-014**: Decision Register clean workspace URL MUST open for authorized workspace users and MUST NOT require an environment filter.
- **FR-015**: Customer Reviews, Reviews, Evidence, Governance Inbox, Audit Log, Alerts, Workspace Settings, Manage Workspaces, and Workspace Overview MUST honor the workspace-wide sidebar/global entry contract.
- **FR-016**: Existing Environment Dashboard CTAs may keep explicit environment filters only where already present; this spec MUST NOT standardize CTA query naming or visible filter chips.
- **FR-017**: Environment-owned pages MUST remain environment-owned and MUST NOT be forced workspace-wide by the registry.
- **FR-018**: No legacy compatibility layer, alias adapter, dual query mapping, migration shim, backfill, or seeder change may be introduced for this contract.

### Workspace Hub Registry Contents

| Registry entry | Route/page identity | Status in Spec 314 |
|---|---|---|
| Workspace Overview | `/admin`, `/admin/workspaces/{workspace}/overview` | include |
| Operations | `/admin/workspaces/{workspace}/operations` | include |
| Provider Connections / Integrations | `/admin/provider-connections` | include |
| Finding Exceptions Queue | `/admin/finding-exceptions/queue` | include |
| Evidence Overview | `/admin/evidence/overview` | include |
| Review Register | `/admin/reviews` | include |
| Customer Review Workspace | `/admin/reviews/workspace` | include |
| Governance Inbox | `/admin/governance/inbox` | include |
| Decision Register | `/admin/governance/decisions` | include |
| Audit Log | `/admin/audit-log` | include |
| Alerts landing | `/admin/alerts` | include |
| Alert Deliveries | `/admin/alerts/alert-deliveries` | include |
| Alert Rules | `/admin/alerts/alert-rules` | include |
| Alert Destinations | `/admin/alerts/alert-destinations` | include |
| Workspace Settings | `/admin/settings/workspace` | include |
| Manage Workspaces | `/admin/workspaces` | include |
| Managed Environments Landing | `/admin/workspaces/{workspace}/environments` | include as workspace environment catalog, not environment-owned dashboard |
| Stored Reports | `/admin/workspaces/{workspace}/environments/{environment}/stored-reports` | exclude; Spec 313 found no workspace-wide reports hub |
| Support Request action | modal/action only | exclude; no workspace-owned list route discovered in Spec 313 |
| Environment Dashboard and child routes | `/admin/workspaces/{workspace}/environments/{environment}...` | exclude; environment-owned |

### Non-Functional Requirements

- **NFR-001**: The implementation MUST preserve workspace isolation and managed-environment entitlement checks for every workspace-wide query.
- **NFR-002**: The implementation MUST not introduce Graph calls, queued work, remote calls, or `OperationRun` lifecycle changes.
- **NFR-003**: The implementation MUST use Laravel 12, Filament 5.2.1, Livewire 4.1.4, and Pest 4 conventions.
- **NFR-004**: The implementation MUST prefer direct replacement over legacy compatibility, consistent with LEAN-001.
- **NFR-005**: Browser verification MUST cover the critical Spec 313 flows after runtime changes.
- **NFR-006**: Tests MUST stay focused and must not rebaseline broad navigation or browser suites.

### RBAC / Security Requirements

- **SEC-001**: Workspace non-members remain deny-as-not-found.
- **SEC-002**: Missing capability remains forbidden after workspace membership is established where current policies use 403.
- **SEC-003**: UI visibility must not replace server-side authorization.
- **SEC-004**: Provider Connections credential-adjacent actions are not changed, weakened, or newly exposed.
- **SEC-005**: Workspace-wide pages must never reveal tenant-owned rows from environments outside the actor's entitlement.

### Auditability / Observability Requirements

- **AUD-001**: No new audit events are required because this spec changes read/navigation context only.
- **AUD-002**: Existing audit behavior for mutating actions must remain unchanged.
- **AUD-003**: Implementation close-out must record exact tests, browser verification, and any remaining follow-up for Specs 315/316/317.

### Data / Truth Requirements

- **DATA-001**: No migrations, seeders, data backfills, or persisted compatibility fields are in scope.
- **DATA-002**: The registry is code truth for workspace hub identity, not database truth.
- **DATA-003**: Environment-like persisted filter state is UI/session state only; it must not become a domain model.

## Out of Scope

- Environment CTA explicit filter contract.
- Universal clear-filter behavior.
- Standardizing filter chips or visible scope chips.
- Route alias compatibility.
- Legacy `tenant`/`tenant_id` cleanup outside sidebar/global workspace hub entry.
- Reclassifying all ambiguous pages.
- Product IA redesign.
- Application data migration, seed data, or backfill work.
- New provider abstraction, provider registry, or multi-provider framework.
- New destructive actions or mutating workflows.

## Acceptance Criteria

### Workspace Hub Registry

- [ ] There is one canonical workspace hub registry/contract.
- [ ] All workspace hubs from Spec 313 are represented or explicitly excluded with reason.
- [ ] Registry distinguishes workspace hubs from environment-scoped pages.
- [ ] Registry is used by sidebar/global navigation or the equivalent central contract.

### Sidebar URL Contract

- [ ] Workspace hub sidebar/global URLs contain no `tenant`.
- [ ] Workspace hub sidebar/global URLs contain no `tenant_id`.
- [ ] Workspace hub sidebar/global URLs contain no `managed_environment_id`.
- [ ] Workspace hub sidebar/global URLs contain no `environment_id`.
- [ ] Workspace hub sidebar/global URLs contain no `tenant_scope`.
- [ ] Workspace hub sidebar/global URLs contain no `tableFilters`.
- [ ] Provider Connections no longer injects Environment query params from remembered context.
- [ ] Finding Exceptions Queue no longer uses `tenant` query for sidebar/global entry.

### Shell / Data Scope Contract

- [ ] Sidebar/global entry into workspace hubs clears active shell Managed Environment context.
- [ ] Selected Workspace remains active.
- [ ] Workspace hubs open workspace-wide by default.
- [ ] Shell and data scope do not diverge on critical pages.
- [ ] Remembered Environment is not used as workspace hub data scope.
- [ ] `Filament::getTenant()` is not used as a hidden workspace hub default filter source.

### Persisted Filter Safety

- [ ] Environment-like persisted table filters do not override sidebar/global workspace hub intent.
- [ ] Customer Reviews sidebar/global entry does not restore stale Environment filter.
- [ ] Finding Exceptions Queue sidebar/global entry does not restore stale Environment filter.
- [ ] Evidence sidebar/global entry does not restore stale Environment filter.
- [ ] Provider Connections sidebar/global entry does not restore stale Environment filter.

### Critical Page Fixes

- [ ] Provider Connections workspace hub sidebar/global entry is workspace-wide.
- [ ] Finding Exceptions Queue workspace hub sidebar/global entry is workspace-wide.
- [ ] Operations sidebar/global entry is workspace-wide and does not carry `managed_environment_id`.
- [ ] Decision Register clean workspace URL opens for authorized workspace users.
- [ ] Customer Reviews sidebar/global entry no longer reload-restores stale Environment filter.
- [ ] Evidence sidebar/global entry no longer silently uses stale Environment filter.

### Tests

- [ ] Required tests added.
- [ ] Existing relevant tests updated only if they asserted old broken behavior.
- [ ] No broad test rebaseline.
- [ ] Tests prove sidebar/global navigation contract.
- [ ] Tests prove remembered Environment does not affect workspace hub sidebar/global URLs.
- [ ] Tests prove persisted Environment filters do not override sidebar/global intent.

### Browser Verification

- [ ] Focused browser verification performed for critical pages.
- [ ] Screenshots saved for critical before/after flows where useful.
- [ ] Reload behavior verified.
- [ ] Back/forward behavior checked for high-risk pages.
- [ ] Remaining mismatch documented as follow-up for Spec 315/316/317.

## Filament v5 Output Contract

1. **Livewire v4.0+ compliance**: The app uses Livewire 4.1.4 with Filament 5.2.1. Implementation must not introduce Livewire v3 references or APIs.
2. **Provider registration location**: Admin panel provider remains registered through `apps/platform/bootstrap/providers.php`; do not register providers in `bootstrap/app.php`.
3. **Global search**: Workspace hub registry work must not enable global search. Changed resources must keep existing global-search posture; Provider Connections currently disables global search.
4. **Destructive actions**: No destructive actions are added or changed. Any existing destructive action must retain `->action(...)`, `->requiresConfirmation()`, server-side authorization, audit logging, and tests.
5. **Asset strategy**: No new assets are expected. If implementation unexpectedly registers Filament assets, deployment must include `cd apps/platform && php artisan filament:assets`.
6. **Testing plan**: Feature/Livewire tests for URL/shell/data scope; focused browser smoke for critical flows; no broad UI restyling tests.

## Risks

- Decision Register currently has data-dependent access behavior; the implementation must make clean workspace URL behavior truthful without hiding real authorization failures.
- Persisted Filament filters may have page-specific session keys; implementation must avoid fragile one-off clearing where a shared helper can express the contract.
- Provider Connections currently uses `managed_environment_id` as external id/slug in some paths and database id elsewhere; sidebar/global entry must not preserve this ambiguity.
- Existing Environment CTA links may still pass explicit filters; implementation must not accidentally remove all CTA filtering before Spec 315.
- Browser back/forward may revive old filtered URLs; this spec covers critical re-entry and high-risk flows, while full clear-filter semantics belong to Spec 316.

## Assumptions

- Spec 313 is completed audit context and is the source of truth for page inventory and critical findings.
- Specs 311 and 312 are completed historical dependencies and must not be rewritten.
- There is no production data or production environment to preserve.
- Workspace remains primary context; Managed Environment remains secondary context.
- Provider Connections is workspace/provider-level for sidebar/global entry.
- Decision Register is a workspace hub and clean workspace URL behavior is required.

## Follow-Up Spec Candidates

- **315 - Environment CTA Explicit Filter Contract**: canonical environment filter query key, identifier type, visible scope chips, CTA behavior, and distinction from sidebar/global entry.
- **316 - Workspace Hub Clear Filter Contract**: clear visible chip, query params, Livewire properties, Filament table filters, deferred filters, persisted/session state, reload safety.
- **317 - Legacy Tenant / Environment Context Cleanup**: old `tenant` aliases, hidden `Filament::getTenant()` workspace hub usage, remembered environment as data boundary, stale tenant naming.
- **318 - Browser Regression Coverage / No-Drift Guard**: durable browser/regression guard coverage for this context contract.

## Required Final Report

When implementation completes, report:

```text
Spec 314 completed.

Changed behavior:
...

Files changed:
...

Workspace hub registry contents:
...

Tests:
- command:
- result:

Browser verification:
...

Remaining follow-ups:
- 315:
- 316:
- 317:

Runtime files were changed: yes/no.
No migrations were created.
No seeders were changed.
No backwards compatibility layer was introduced.
No legacy query alias support was preserved for workspace hub sidebar/global entry.
```
