# Implementation Plan: Tenant-Owned Surface Route Audit

**Branch**: `302-tenant-owned-surface-route-audit` | **Date**: 2026-05-14 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/302-tenant-owned-surface-route-audit/spec.md`

## Summary

Produce a repo-verified audit matrix for tenant-owned admin surfaces after the Inventory navigation cutover. The implementation is docs/spec-artifact only: create `surface-route-audit.md`, classify each audited surface against existing route/navigation/context/global-search/RBAC contracts, cite current tests or gaps, and recommend a bounded follow-up repair order. No application runtime code changes are in scope.

## Technical Context

**Language/Version**: PHP 8.4.15 for inspected application code; Markdown for delivered audit artifact
**Primary Dependencies**: Laravel 12.52.0, Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1
**Storage**: PostgreSQL in the application; N/A for this docs-only audit slice
**Testing**: Existing Pest feature tests; no new tests required by this spec
**Validation Lanes**: confidence for focused existing Filament tests; `git diff --check` for artifact hygiene
**Target Platform**: Laravel Sail local development; Dokploy deployment unaffected
**Project Type**: Laravel/Filament application with Spec Kit artifacts under `specs/`
**Performance Goals**: N/A; no runtime behavior changes
**Constraints**: No application code changes; no route enablement; no navigation changes; no global-search enablement; no migrations; no assets
**Scale/Scope**: Tenant-owned admin surface inventory, starting from `TenantOwnedModelFamilies` and admin Filament resources/pages/tests

## UI / Surface Guardrail Plan

- **Guardrail scope**: no operator-facing surface change; audit/prep artifact only
- **Native vs custom classification summary**: N/A for runtime; existing surfaces are inspected, not changed
- **Shared-family relevance**: navigation, route generation, global search, authorization, relation entry points
- **State layers in scope**: route context, shell/navigation posture, global-search scope, RBAC posture as audited facts only
- **Audience modes in scope**: internal product owner / implementer / reviewer
- **Decision/diagnostic/raw hierarchy plan**: default-visible matrix fields first; source-file and test evidence second
- **Raw/support gating plan**: N/A; no product data or raw tenant payloads included
- **One-primary-action / duplicate-truth control**: one recommended next action per surface row
- **Handling modes by drift class or surface**: document-in-feature for contained findings; follow-up-spec for runtime repair; reject-or-split for broad migration bundles
- **Repository-signal treatment**: review-mandatory for stale navigation/search/RBAC signals; report-only for unrelated code quality findings
- **Special surface test profiles**: standard-native-filament for referenced existing surfaces
- **Required tests or manual smoke**: existing focused Pest tests only; no browser smoke because no UI changes
- **Exception path and spread control**: no runtime exception; document-only classification labels stay inside the audit artifact
- **Active feature PR close-out entry**: Guardrail

## Shared Pattern & System Fit

- **Cross-cutting feature marker**: yes, audit touches shared route/navigation/search/RBAC concepts
- **Systems touched**:
  - `apps/platform/app/Support/WorkspaceIsolation/TenantOwnedModelFamilies.php`
  - `apps/platform/app/Filament/Concerns/WorkspaceScopedTenantRoutes.php`
  - `apps/platform/app/Support/Navigation/NavigationScope.php`
  - `apps/platform/app/Filament/Concerns/ScopesGlobalSearchToTenant.php`
  - `apps/platform/app/Support/OperateHub/OperateHubShell.php`
  - `apps/platform/routes/web.php`
  - `apps/platform/app/Filament/Resources/`
  - `apps/platform/app/Filament/Pages/`
  - `apps/platform/tests/Feature/Filament/`
- **Shared abstractions reused**: N/A at runtime; the audit measures each surface against the existing helpers above
- **New abstraction introduced? why?**: none
- **Why the existing abstraction was sufficient or insufficient**: the audit records sufficiency per surface; it must not introduce replacement machinery
- **Bounded deviation / spread control**: document-only migration-state labels; no executable classification layer

## OperationRun UX Impact

- **Touches OperationRun start/completion/link UX?**: no
- **Central contract reused**: N/A
- **Delegated UX behaviors**: N/A
- **Surface-owned behavior kept local**: existing run links may be mentioned as evidence but are not changed
- **Queued DB-notification policy**: N/A
- **Terminal notification path**: N/A
- **Exception path**: none

## Provider Boundary & Portability Fit

- **Shared provider/platform boundary touched?**: no runtime boundary change
- **Provider-owned seams**: Entra Groups and provider-specific diagnostics may appear as audited surface names only
- **Platform-core seams**: workspace/environment route context, navigation scope, tenant-owned global-search scope, RBAC semantics
- **Neutral platform terms / contracts preserved**: workspace, managed environment, tenant-owned surface, route posture, navigation posture, repair blocker
- **Retained provider-specific semantics and why**: provider-specific surface names remain contextual to the audited resource/page
- **Bounded extraction or follow-up path**: follow-up-spec if the audit finds provider-specific semantics leaking into platform-core route or search contracts

## Constitution Check

*GATE: Must pass before implementation. Re-check after audit artifact is produced.*

- Inventory-first: audit only; no Inventory, snapshot, backup, or provider truth changes.
- Read/write separation: read-only repo audit; no write/change function.
- Graph contract path: no Microsoft Graph calls or contract changes.
- Deterministic capabilities: audit records existing capability posture; no resolver changes.
- RBAC-UX: audit must record non-member 404 versus member-missing-capability 403 expectations and server-side proof separately from UI visibility.
- Workspace isolation: audit must distinguish workspace-home cleanliness from environment-bound visibility.
- Tenant isolation: audit must identify tenant-owned surfaces that need workspace plus managed-environment entitlement.
- Run observability: no `OperationRun` creation or lifecycle change.
- Test governance: existing focused tests are evidence; missing proof is documented as a gap, not hidden by new broad tests.
- Proportionality: one audit artifact is narrower than a route/navigation framework or broad migration.
- No premature abstraction: no new registry, resolver, strategy, or framework.
- Persisted truth: no runtime persistence; the audit is repair evidence only.
- Behavioral state: migration-state labels are document-only and must not become product state.
- Shared pattern first: the audit measures current usage of existing shared helpers before recommending any new work.
- Provider boundary: provider-specific surfaces remain named only where current repo truth requires them.
- Filament-native UI: no UI is changed; future repairs must preserve Filament v5 and Livewire v4 conventions.
- Filament v5 / Livewire v4 compliance: the plan does not introduce Livewire v3 references or legacy Filament APIs.
- Provider registration location: no provider registration changes; Laravel provider registration remains in `apps/platform/bootstrap/providers.php`.
- Global search rule: the audit must record every globally searchable resource's Edit/View-page eligibility or disabled posture.
- Destructive actions: none are added or changed; any surface with destructive actions is inspected only for follow-up risk.
- Asset strategy: no assets are registered; deploy-time `filament:assets` requirements are unchanged.

## Test Governance Check

- **Test purpose / classification by changed surface**: N/A for runtime; confidence evidence from existing Feature tests
- **Affected validation lanes**: confidence and diff-check only
- **Why this lane mix is the narrowest sufficient proof**: the deliverable is an audit artifact; existing feature tests and source references prove current posture
- **Narrowest proving command(s)**:
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/PanelNavigationSegregationTest.php tests/Feature/Filament/AdminTenantSurfaceParityTest.php tests/Feature/Filament/AdminSharedSurfacePanelParityTest.php tests/Feature/Filament/TenantOwnedResourceScopeParityTest.php tests/Feature/Filament/EntraGroupAdminScopeTest.php tests/Feature/Filament/EntraGroupGlobalSearchScopeTest.php tests/Feature/Filament/PolicyResourceAdminSearchParityTest.php tests/Feature/Filament/PolicyVersionAdminSearchParityTest.php`
  - `git diff --check`
- **Fixture / helper / factory / seed / context cost risks**: none
- **Expensive defaults or shared helper growth introduced?**: no
- **Heavy-family additions, promotions, or visibility changes**: none
- **Surface-class relief / special coverage rule**: standard-native-filament relief; no new browser proof
- **Closing validation and reviewer handoff**: reviewers should verify the matrix evidence, runtime no-change boundary, and follow-up split
- **Budget / baseline / trend follow-up**: none
- **Review-stop questions**: Did any task edit app code? Does every row cite repo evidence? Are runtime bugs documented as follow-ups?
- **Escalation path**: document-in-feature for audit findings; follow-up-spec for runtime repair
- **Active feature PR close-out entry**: Guardrail
- **Why no dedicated follow-up spec is needed**: this spec is the audit; surface-specific repairs become separate specs only after the matrix identifies them

## Project Structure

### Documentation (this feature)

```text
specs/302-tenant-owned-surface-route-audit/
├── checklists/
│   └── requirements.md
├── plan.md
├── spec.md
├── surface-route-audit.md   # Created during implementation, not preparation
└── tasks.md
```

### Source Code (repository root)

```text
apps/platform/app/Filament/
├── Concerns/
├── Pages/
└── Resources/

apps/platform/app/Support/
├── Navigation/
├── OperateHub/
└── WorkspaceIsolation/

apps/platform/routes/web.php
apps/platform/tests/Feature/Filament/
```

**Structure Decision**: The implementation edits only the spec package. Application files and tests are inspected as evidence and remain unchanged.

## Complexity Tracking

| Violation | Why Needed | Simpler Alternative Rejected Because |
|---|---|---|
| Document-only classification labels | The audit needs consistent row states to compare surfaces | Freeform prose would make repair ordering harder to review |

## Implementation Phases

### Phase 1 - Preparation and Scope Lock

Confirm Spec 301 is completed context, verify no `302` package existed before this branch, and keep the implementation boundary to the spec package.

### Phase 2 - Surface Inventory

Build the initial surface set from `TenantOwnedModelFamilies::firstSlice()`, residual inventory, scope exceptions, Filament resources/pages, route files, and focused tests.

### Phase 3 - Posture Classification

For each surface, classify route posture, navigation posture, context source, global-search posture, RBAC posture, evidence, blocker, migration state, and recommended next action.

### Phase 4 - Repair Order

Convert findings into a bounded repair order. Keep Entra Groups cutover, navigation contract split, tenant-panel dead-code retirement, and any surface-specific repairs as separate recommendations.

### Phase 5 - Validation and Close-Out

Run the existing focused tests when available, run `git diff --check`, verify no application files changed, and record any failures as audit findings or blockers.

## Rollout Considerations

- No environment variables.
- No database migrations.
- No queues or scheduled workers.
- No storage or volume changes.
- No Dokploy runtime impact.
- No `filament:assets` change.
- Staging/production validation is N/A unless a later repair spec changes runtime behavior.

## Risk Controls

- Stop if implementation requires runtime code changes; promote a separate repair spec instead.
- Do not treat document classification labels as product states.
- Do not revive `/admin/t/{tenant}` or `/admin/tenants/{tenant}` routes.
- Do not change tests that encode current behavior; document stale tests as findings.
- Keep all follow-up recommendations scoped as bounded candidates.
