TenantAtlas/specs/169-action-surface-v11/research.md
ahmido 37c6d0622c feat: implement spec 169 action surface contract v1.1 (#200)
## Summary
- implement the Action Surface Contract v1.1 runtime changes for Spec 169
- add the new explicit ActionSurfaceType contract, validator/discovery updates, and enrolled surface declarations
- update Filament action-surface documentation, focused guard tests, and spec artifacts for the completed feature

## Included
- clickable-row vs explicit-inspect enforcement across monitoring, reporting, CRUD, and system reference surfaces
- helper-first, workflow-next, destructive-last overflow ordering checks
- system panel list discovery in the primary action-surface validator
- Spec 169 artifacts: spec, plan, tasks, research, data model, quickstart, and logical contract

## Verification
- focused Pest verification pack completed for:
  - tests/Feature/Guards/ActionSurfaceValidatorTest.php
  - tests/Feature/Guards/ActionSurfaceContractTest.php
  - tests/Feature/Rbac/TenantActionSurfaceConsistencyTest.php
- integrated browser smoke test completed for admin-side reference surfaces:
  - /admin/operations
  - /admin/audit-log
  - /admin/finding-exceptions/queue
  - /admin/reviews
  - /admin/tenants

## Notes
- system panel browser smoke coverage could not be exercised in the same session because /system routes require platform authentication in the integrated browser
- Livewire target remains v4-compliant and no provider registration or asset strategy changes are introduced by this PR

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #200
2026-03-30 09:21:39 +00:00

57 lines
5.3 KiB
Markdown

# Phase 0 Research: Action Surface Contract v1.1
## Decision: Add a first-class `ActionSurfaceType` enum to `ActionSurfaceDeclaration` while keeping `ActionSurfaceProfile`
**Rationale**: `ActionSurfaceProfile` currently governs which slots are required, but it does not distinguish constitution-level interaction semantics. The repo needs to tell the difference between clickable-row CRUD or registry surfaces and legitimate explicit-inspect queue or audit surfaces. A first-class `surfaceType` field makes that distinction explicit without forcing slot requirements and behavioral rules into the same enum.
**Alternatives considered**:
- Replace `ActionSurfaceProfile` entirely: rejected because slot requirements and constitution surface semantics are different concerns and existing declarations already rely on the profile model.
- Derive surface type from metadata or inferred heuristics: rejected because the clarified spec requires a first-class declaration-level field and because inference would keep validator failures ambiguous.
## Decision: Keep inspect-model compatibility rules close to the existing contract stack
**Rationale**: The narrowest implementation is one new enum plus validator logic and small helper methods where needed. That keeps the feature inside the current `ActionSurfaceDeclaration` / `ActionSurfaceValidator` architecture and avoids introducing a second action-governance registry or policy layer.
**Alternatives considered**:
- Create a new `ActionSurfaceTypeDefinition` registry or service: rejected because the slice does not justify another framework layer.
- Enforce the new rules in tests only: rejected because the main validator must become the primary contract gate, not just the rendered tests.
## Decision: Extend primary discovery to declared system-panel table pages only
**Rationale**: The six enrolled system list pages already have declarations and targeted tests, but the main discovery pass still excludes them. The safest extension is to scan `app/Filament/System/Pages/**` narrowly for declared, table-backed pages so the main validator covers them without accidentally enrolling auth, dashboard, widget, or other deferred system surfaces.
**Alternatives considered**:
- Hardcode an allowlist of six system classes: rejected because it would preserve a parallel discovery model and create more manual maintenance.
- Broadly discover every page under `app/Filament/System/Pages`: rejected because it would sweep in deferred surfaces such as auth, runbooks, and break-glass tooling.
## Decision: Keep current panel-scope metadata unchanged for this slice
**Rationale**: The feature needs system-panel discovery coverage, not a new panel taxonomy. The current codebase does not have an active consumer that requires a `System` panel scope enum, so adding one now would widen the slice without solving the immediate operator problem.
**Alternatives considered**:
- Add `ActionSurfacePanelScope::System`: rejected because no current validation or runtime rule depends on it, and the spec does not require it.
- Infer system scope through panel providers and extend all scope tests: rejected as unnecessary expansion beyond the current feature goal.
## Decision: Split enforcement between fast validator tests and representative Livewire render tests
**Rationale**: Validator tests are the right seam for declaration-time rules such as required `surfaceType`, allowed affordance combinations, and required exception reasons. Livewire render tests are the right seam for business-visible behavior such as row click actually existing, explicit inspect actually preserving context, and `More` groups actually rendering helpers first, workflow actions next, and destructive actions last.
**Alternatives considered**:
- Declaration-only guard coverage: rejected because the constitution explicitly rejects declaration-only conformance when rendered behavior drifts.
- Browser-only coverage: rejected because it would be slower, broader, and less precise than the current Livewire table guard pattern already used in the repo.
## Decision: Treat `PrimaryLinkColumn` as an exception path that requires an explicit reason
**Rationale**: The spec needs stronger control over linked-column inspect affordances, but the repo does not need a dedicated exception object or secondary taxonomy for that. Requiring an explicit reason on the declaration is enough to keep the exception visible and reviewable.
**Alternatives considered**:
- Allow `PrimaryLinkColumn` anywhere the enum is present: rejected because the constitution requires a concrete reason when row click is not the correct primary inspect model.
- Add a new exception class hierarchy: rejected because it would add structure without a separate current-release problem to solve.
## Decision: Keep the two reference docs in lockstep with validator behavior
**Rationale**: The repo already has two developer-facing references for this domain: `docs/ui/action-surface-contract.md` and `docs/product/standards/filament-actions-ux.md`. The feature should update both together so implementation guidance, spec language, and guard behavior stay aligned.
**Alternatives considered**:
- Update only the constitution: rejected because day-to-day implementation guidance lives in the shorter reference docs.
- Update only one doc and let the other lag: rejected because that would recreate the ambiguity the feature is meant to remove.