# Admin Surface Scope and Shell Context Audit

## 1. Executive Summary

The workspace hub lifecycle introduced by Specs 314-317 is mostly solved for registered workspace hubs. Decision Register, Governance Inbox, Operations, Finding Exceptions Queue, Provider Connections, Evidence Overview, Review Register, and Customer Review Workspace behaved correctly across clean entry, filtered entry, clear filter, reload, and browser back/forward.

The remaining issue is partly page-specific and partly a classifier gap. Pages outside WorkspaceHubRegistry that remain AdminSurfaceScope::WorkspaceScoped can restore remembered environment shell context on clean workspace-style URLs. Baseline Compare is the highest-risk case because it is product-environment-scoped but not route-environment-bound, and environment_id is not self-sufficient after context clear.

- Browser state captures: 161.
- Screenshots: 161.
- Named surfaces classified: 61.
- Matrix statuses: OK 135, blocked 1, dead/unreachable 1, mismatch 24.
- Highest-risk mismatches: Baseline Compare URL/shell/context mismatch, Baseline Profiles/Snapshots workspace data with environment shell, Alerts/Audit filtered URL contract gaps, and unregistered workspace analysis pages inheriting remembered environment context.

## 2. Final Surface Classification

See surface-inventory.md for the full classified inventory. No discovered surface is silently skipped. Routes with no local fixture record are marked blocked with reason. Auth/callback/local/system routes are marked out of scope or system/platform scoped with reason.

## 3. Workspace Hub Verification

Registered workspace hubs in WorkspaceHubRegistry force environmentless shell on clean entry and strip legacy environment query state. Verified clean workspace hubs include Workspace Overview, Operations, Finding Exceptions Queue, Governance Inbox, Decision Register, Provider Connections, Evidence Overview, Review Register, Customer Review Workspace, Audit Log, Workspace Settings, Manage Workspaces, and Managed Environments.

Filtered workspace hub behavior is correct for Operations, Finding Exceptions Queue, Governance Inbox, Decision Register, Provider Connections, Evidence Overview, Review Register, and Customer Review Workspace: URL contains environment_id=4, shell remains workspace-first/no active environment, a visible environment filter chip appears, and clear filter returns to a clean URL.

Alerts and Audit Log are the exceptions found in filtered direct-url verification. /admin/alerts?environment_id=4 redirects to /admin/alerts/alert-deliveries and drops the query. Alert child routes with environment_id=4 show no chip and still say All environments. /admin/audit-log?environment_id=4 preserves the query, but no visible environment chip was present.

## 4. Environment Page Verification

Route-bound environment pages under /admin/workspaces/{workspace}/environments/{environment} consistently show workspace plus active environment shell. Verified pages include Environment Dashboard, Required Permissions, Diagnostics, Access Scopes, Inventory Items, Policies, Policy Versions, Inventory Coverage, Backup Schedules, Backup Sets, Restore Runs, Groups, Findings, Risk Exceptions, Evidence Snapshots, Environment Reviews, Stored Reports, Review Packs, and create pages for backup/restore where reachable.

For these pages, wording such as this environment is justified because URL route ownership, shell context, breadcrumbs, and page scope align. Empty local data limited row-level proof for several detail pages; those are marked blocked by fixture absence, not skipped.

## 5. Scope Mismatch Findings

See mismatch-findings.md. Mismatches are grouped as shell vs data scope, URL vs shell, breadcrumb/copy vs page scope, sidebar placement vs page scope, and registry/classifier vs actual behavior.

## 6. Baseline Compare Finding

Current classification from browser behavior: environment-scoped page with an unbound workspace-style URL.

Code evidence: BaselineCompareLanding registers under Governance, shouldRegisterNavigation() only for environment navigation, canAccess() requires resolveTenantContextForCurrentPanel() to return a ManagedEnvironment, and stats are loaded through BaselineCompareStats::forTenant(). UsesAdminEnvironmentFilterQueryParameter emits environment_id for links, but OperateHubShell::resolveQueryTenantHint() resolves tenant and managed_environment_id, not canonical environment_id.

Browser evidence: from environment sidebar, /admin/baseline-compare-landing works with shell YPTW2 (DEV) because remembered context exists. After clearing environment context, both /admin/baseline-compare-landing and /admin/baseline-compare-landing?environment_id=4 return 403. Reload preserves the remembered shell when present.

Conclusion: Baseline Compare should be explicitly environment-scoped. The recommended fix is a route-bound environment URL rather than a workspace-style URL that depends on remembered context.

## 7. Decision Register Finding

Current classification: workspace-scoped hub with optional filtered workspace hub state.

Code evidence: DecisionRegister is listed in WorkspaceHubRegistry, uses ClearsWorkspaceHubEnvironmentFilterState, and resolves visible filter state through WorkspaceHubEnvironmentFilter.

Browser evidence: clean workspace sidebar opens /admin/governance/decisions with shell No environment selected. Environment sidebar opens the same clean URL with no active environment. Filtered entry /admin/governance/decisions?environment_id=4 shows workspace-first shell, visible environment filter chip, and clear filter returns to the clean URL. Reload and back/forward remain consistent.

Conclusion: Decision Register is correctly a workspace hub. No fix is required for the audited contract.

## 8. Code Ownership Map

- WorkspaceHubRegistry: declares workspace hub paths, forbidden legacy query keys, and allowed environment_id filter query key.
- AdminSurfaceScope: classifies request paths and controls remembered environment restore. Unclassified workspace-like pages fall into WorkspaceScoped.
- WorkspaceSidebarNavigation: builds the workspace sidebar using cleaned workspace hub URLs.
- WorkspaceScopedEnvironmentRoutes: creates route-bound environment URLs for environment resources.
- UsesAdminEnvironmentFilterQueryParameter: appends environment_id to Baseline Compare URLs but does not make shell/access resolution self-sufficient.
- OperateHubShell: resolves shell workspace/environment from route, query hints, Filament tenant, or remembered context. Query hints currently include tenant and managed_environment_id, not canonical environment_id.
- CanonicalAdminEnvironmentFilterState and WorkspaceHubEnvironmentFilter: synchronize table/filter state and visible environment filter chips on supported hubs.
- AdminPanelProvider: mixes environment-bound resources and workspace hub links in environment navigation; this is acceptable only when each item declares and tests its scope.
- Page/resource copy and views: provide visible wording such as All environments, Environment filter, this environment, and empty states; these were compared against shell/URL scope in the matrix.

## 9. Recommended Remediation

See recommended-fixes.md. Suggested follow-up specs are Baseline Compare Environment Classification Fix, Workspace-Owned Baseline Registry Contract, Alerts and Audit Log Filter Contract, Admin Surface Scope Regression Guard, and Sidebar Placement / Surface Scope Contract.

## 10. Test / Browser Execution

Commands and tools used: git status, source discovery with rg, Laravel Boost application_info/list_routes/database_schema/database_query, and browser automation through the Codex in-app browser/Node REPL helpers against local Sail-served http://localhost. Screenshots and state captures were written to artifacts/screenshots/ and artifacts/state-captures/.

Tests were not run because this task is analysis-only and no runtime/test code was changed. No destructive Filament actions were executed. No assets were changed; no new deployment filament:assets requirement is introduced.

Filament v5 / Livewire v4 note: the app is Filament 5.2.1 with Livewire 4.1.4. Provider registration is in apps/platform/bootstrap/providers.php.
