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