## Summary
- add the full Spec 195 residual action-surface design package under `specs/195-action-surface-closure`
- implement residual surface inventory and validator enforcement for uncatalogued system and special Filament pages
- add focused regression coverage for residual guards, system directory pages, managed-tenants landing, and readonly register-tenant / tenant-dashboard access
- fix the system workspace detail surface by loading tenant route keys and disabling lazy system database notifications to avoid the Livewire 404 on `/system/directory/workspaces/{workspace}`
## Testing
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/System/Spec195/SystemDirectoryResidualSurfaceTest.php tests/Feature/Filament/DatabaseNotificationsPollingTest.php`
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
## Notes
- branch: `195-action-surface-closure`
- target: `dev`
- no new assets, migrations, or provider-registration changes
Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #230
103 lines
7.7 KiB
Markdown
103 lines
7.7 KiB
Markdown
# Research: Action Surface Enforcement, Enrollment, and Exception Closure
|
||
|
||
## Decision: Preserve the current primary discovery boundary and close the gap with a supplemental residual inventory
|
||
|
||
### Rationale
|
||
|
||
`ActionSurfaceDiscovery` already has a clear shape: it discovers resources, relation managers, normal pages, and system pages only when those system pages are declaration-backed table surfaces. The real problem in Spec 195 is not that this boundary exists, but that the repo does not currently make the boundary explicit enough for residual system/detail/workflow surfaces that live outside it.
|
||
|
||
Keeping the primary discovery boundary stable avoids turning the generic contract into a catch-all framework and lets Spec 195 solve the actual problem: uncatalogued outliers.
|
||
|
||
### Alternatives considered
|
||
|
||
- Auto-discover every class under `app/Filament/System/Pages`: rejected because many of those pages are not list/detail contract surfaces and would force the generic contract into shapes it does not currently model well.
|
||
- Expand `ActionSurfaceDiscovery` to scan every wizard, dashboard, and selector page in all namespaces: rejected because it would blur the difference between generic contract coverage and legitimate special workflows.
|
||
|
||
## Decision: Add a parallel `spec195ResidualSurfaceInventory()` instead of refactoring `baseline()` or stretching `ActionSurfaceDeclaration()`
|
||
|
||
### Rationale
|
||
|
||
The existing `baseline()` API is a simple string-reason allowlist for discovered pages that intentionally lack declarations. It is useful, but too narrow for Spec 195 because Spec 195 must also classify non-discovered system/detail pages and distinguish closure outcomes like `separately_governed`, `harmless_special_case`, and `retired_no_longer_relevant`.
|
||
|
||
The narrowest solution is to add one parallel inventory specifically for residual closure. That keeps the current baseline exemption behavior stable while giving the validator the structured data it needs.
|
||
|
||
### Alternatives considered
|
||
|
||
- Change `baseline()` into a structured object registry: rejected because it would create avoidable churn in existing tests and validator behavior for a problem that only Spec 195 needs to solve.
|
||
- Encode the entire Spec 195 closure model inside `ActionSurfaceDeclaration()`: rejected because many residual surfaces are not natural declaration-backed list/detail surfaces.
|
||
|
||
## Decision: Represent closure decisions and reason categories as validator-checked strings, not new PHP enums or persisted data
|
||
|
||
### Rationale
|
||
|
||
Spec 195 adds review and CI truth, not product-domain behavior. The closure states matter for planning and enforcement, but they do not need to become persisted entities or first-class runtime business state.
|
||
|
||
Using validator-checked string values in the inventory mirrors the existing Spec 192 and Spec 193 inventory style and avoids adding new runtime types whose only purpose would be internal categorization.
|
||
|
||
### Alternatives considered
|
||
|
||
- Add new PHP enums for closure decisions and reason categories: rejected because the validator can enforce the allowed string values without importing extra runtime structure.
|
||
- Persist residual closure rows in the database: rejected because this is repository governance truth, not user-facing data truth.
|
||
|
||
## Decision: Default residual system pages to `separately_governed` or `harmless_special_case` instead of forcing generic contract enrollment
|
||
|
||
### Rationale
|
||
|
||
The system residuals called out by the spec do not currently behave like the declaration-backed table/resource surfaces that Specs 192 and 193 govern. `ViewRun` is a system decision detail page, `Runbooks` is a workflow utility hub, `RepairWorkspaceOwners` is a break-glass repair utility, and the directory detail pages are read-mostly context pages.
|
||
|
||
Existing focused tests already exercise many of these surfaces directly. The narrowest correct implementation is therefore explicit classification plus explicit evidence, not generic normalization for its own sake.
|
||
|
||
### Alternatives considered
|
||
|
||
- Enroll `ViewRun`, `Runbooks`, and `RepairWorkspaceOwners` into the current `actionSurfaceDeclaration()` system immediately: rejected because the current contract is list/detail-slot oriented and would fit some of these surfaces awkwardly.
|
||
- Leave the system pages uncatalogued because dedicated tests already exist: rejected because that is exactly the gray zone Spec 195 exists to close.
|
||
|
||
## Decision: Use existing focused test suites as closure evidence and add only gap tests
|
||
|
||
### Rationale
|
||
|
||
The repo already has strong dedicated coverage for `Runbooks`, `ViewRun`, `RepairWorkspaceOwners`, registration, choosers, onboarding, and dashboard behavior. Spec 195 should leverage that fact instead of duplicating equivalent tests under a new surface framework.
|
||
|
||
The only clear weak spot from current evidence is `ManagedTenantsLanding`, and system directory detail pages also need more explicit closure-level assertions than they have today.
|
||
|
||
### Alternatives considered
|
||
|
||
- Add one brand-new comprehensive browser suite over every residual surface: rejected because many of these surfaces are already deeply covered through feature or Livewire tests.
|
||
- Add only inventory validation with no page-level follow-up: rejected because the weakest residuals still need focused proof.
|
||
|
||
## Decision: Treat `BreakGlassRecovery` as a stale-exemption candidate rather than assuming it is still an active governed surface
|
||
|
||
### Rationale
|
||
|
||
The current `BreakGlassRecovery` page has `canAccess()` returning false and no header actions. That is strong evidence that it may no longer be an action-bearing surface in the way the old baseline exemption reason implies.
|
||
|
||
Spec 195 should explicitly verify whether it is still a live residual surface. If not, it should be retired from the active exemption set instead of remaining as historical noise.
|
||
|
||
### Alternatives considered
|
||
|
||
- Keep the existing exemption reason unchanged because it references dedicated security specs: rejected because the current code suggests the page may no longer be a live action surface.
|
||
- Force the page into the residual inventory as a live intentional exemption without re-auditing the code: rejected because stale exemptions are one of the spec’s explicit problems.
|
||
|
||
## Decision: Keep selectors and dashboard shells outside the generic contract but classify them explicitly
|
||
|
||
### Rationale
|
||
|
||
`ChooseWorkspace`, `ChooseTenant`, and `TenantDashboard` are real operator surfaces, but they are not contract-style list/detail pages in the sense governed by the earlier specs. Selectors are routing surfaces; the dashboard page is a shell whose meaningful actions live in widgets and downstream routes.
|
||
|
||
Spec 195 should classify them explicitly so they are no longer invisible to review, while still avoiding artificial normalization.
|
||
|
||
### Alternatives considered
|
||
|
||
- Treat selectors and dashboards as non-surfaces and ignore them: rejected because they clearly influence operator workflows and currently appear in the residual exemption tail.
|
||
- Enroll them in the generic contract anyway: rejected because the generic contract is not the right fit for routing-only or widget-shell surfaces.
|
||
|
||
## Decision: No new provider, asset, route, or persistence work is needed
|
||
|
||
### Rationale
|
||
|
||
All evidence points to Spec 195 being a repository-governance and test-hardening slice. The existing pages, routes, panels, and tests already provide the runtime behavior. The missing part is explicit closure inventory and regression enforcement.
|
||
|
||
### Alternatives considered
|
||
|
||
- Add a new service provider or config file just for residual-surface closure: rejected because the existing action-surface support layer already provides the correct home.
|
||
- Add new assets or UI primitives for special surfaces: rejected because the implementation does not need new rendering infrastructure. |