# 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.