TenantAtlas/specs/169-action-surface-v11/data-model.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

195 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase 1 Data Model: Action Surface Contract v1.1
## Overview
This feature does not add a database table, persisted artifact, or cache. It extends the existing runtime action-surface contract with one new declaration-level enum and codifies the derived rules that govern discovery, inspect behavior, and overflow ordering for the enrolled reference surfaces.
## Existing Runtime Source Objects
### ActionSurfaceDeclaration v1.0
**Purpose**: Existing declaration object used by Resources, Pages, and RelationManagers to describe action-surface requirements.
**Current fields**:
- `version`
- `componentType`
- `profile`
- `defaults`
- `slots`
- `exemptions`
- `metadata`
**Current behavior**:
- Declares slot satisfaction or exemption.
- Stores ad hoc metadata such as list row primary action limit.
- Does not currently encode constitution surface type explicitly.
### ActionSurfaceProfile
**Purpose**: Existing slot-requirement family used by `ActionSurfaceProfileDefinition`.
**Current values**:
- `CrudListAndEdit`
- `CrudListAndView`
- `ListOnlyReadOnly`
- `RunLog`
- `RelationManager`
**Validation role**:
- Drives which slots are required.
- Does not safely express whether a surface must be clickable-row, explicit-inspect, or edit-as-inspect.
### ActionSurfaceDiscovery and ActionSurfaceDiscoveredComponent
**Purpose**: Discover the repositorys in-scope declaration-backed components and pass them to the validator.
**Current fields on discovered component**:
- `className`
- `componentType`
- `panelScopes`
**Current limitation**:
- The main discovery pass covers declaration-backed tenant/admin surfaces but still excludes the enrolled system-panel list pages and cannot yet enforce the constitution behavior split precisely enough on the reference surfaces.
### ActionSurfaceValidationIssue and ActionSurfaceValidationResult
**Purpose**: Existing validator output used by the guard suite.
**Current role**:
- Reports missing declarations, missing required slots, invalid inspect-affordance tokens, missing exemption reasons, and invalid read-only export defaults.
## New Runtime Entities
### ActionSurfaceType
**Purpose**: First-class constitution-aligned behavioral classification used to determine the allowed primary inspect model for a surface.
#### Values
| Value | Description | Allowed primary inspect model |
|-------|-------------|-------------------------------|
| `CrudListFirstResource` | Standard list-first CRUD resource where open and mutate decisions happen after entering the record | Clickable row by default; `PrimaryLinkColumn` only with explicit reason |
| `ReadOnlyRegistryReport` | Scan-first registry or report surface with read-mostly or immutable records | Clickable row by default; `PrimaryLinkColumn` only with explicit reason |
| `QueueReview` | Queue where the operator reviews an item in context and continues the queue | Explicit inspect / same-page selected detail; row click forbidden by default |
| `HistoryAudit` | Immutable history or audit surface where chronology and context must be preserved | Explicit inspect / same-page selected detail; row click forbidden by default |
| `ConfigLite` | Low-cardinality configuration where edit is the primary inspect surface | Edit-as-inspect allowed by default; no parallel View surface |
#### Validation rules
- Every declaration-backed component enrolled in the v1.1 reference pack must declare one `ActionSurfaceType`.
- `ActionSurfaceType` determines inspect-model compatibility; `ActionSurfaceProfile` continues to determine required slots.
- `PrimaryLinkColumn` is valid only when a concrete reason explains why row click is not the correct primary inspect model.
### ActionSurfaceDeclaration v1.1
**Purpose**: Extended declaration contract that combines slot requirements with explicit constitution behavior.
#### Fields
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `version` | int | yes | Contract version |
| `componentType` | enum | yes | Resource, Page, or RelationManager |
| `profile` | `ActionSurfaceProfile` | yes | Existing slot-requirement family |
| `surfaceType` | `ActionSurfaceType` | yes | New constitution-aligned behavior family |
| `defaults` | `ActionSurfaceDefaults` | yes | Shared defaults such as `moreGroupLabel` |
| `slots` | map<ActionSurfaceSlot, ActionSurfaceSlotRequirement> | yes | Slot requirements and satisfied declarations |
| `exemptions` | map<ActionSurfaceSlot, ActionSurfaceExemption> | no | Explicit exemptions with reasons |
| `metadata` | map<string, mixed> | no | Existing narrow metadata storage |
| `listRowPrimaryActionLimit` | int nullable | no | Existing row-action budget metadata |
| `primaryLinkColumnReason` | string nullable | no | Required when the inspect affordance is `PrimaryLinkColumn` |
#### Relationships
- One declaration belongs to exactly one component class.
- One declaration has exactly one `ActionSurfaceProfile` and one `ActionSurfaceType`.
- One declaration contains many slot requirements and optional slot exemptions.
#### Validation rules
- `surfaceType` is required for all components inside the v1.1 primary discovery scope.
- `surfaceType` and `InspectAffordance` must be compatible.
- `defaults.moreGroupLabel` must remain `More`.
- Empty or reasonless exemptions remain invalid.
### InspectDecisionRule
**Purpose**: Derived rule family that maps `surfaceType` to allowed inspect behavior.
#### Fields
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `surfaceType` | `ActionSurfaceType` | yes | Surface family being governed |
| `allowedAffordances` | list<`ActionSurfaceInspectAffordance`> | yes | Allowed inspect affordance values |
| `forbiddenRedundantView` | bool | yes | Whether a lone row `View` action is forbidden |
| `requiresPrimaryLinkReason` | bool | yes | Whether `PrimaryLinkColumn` must include a concrete reason |
#### Validation rules
- CRUD and registry surfaces must expose one obvious open path and may not render a redundant lone `View` row action.
- Queue and audit surfaces must preserve context through explicit inspect.
- Config-lite surfaces may open edit as inspect but may not add a competing View surface.
### ActionOrderingRule
**Purpose**: Derived rule family that governs `ActionGroup` and `BulkActionGroup` content on governed surfaces.
#### Fields
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `groupLabel` | string | yes | Must remain `More` for governed overflow groups |
| `inspectionHelpersFirst` | bool | yes | Navigation and safe inspection helpers come first |
| `workflowAfterNavigation` | bool | yes | Non-destructive lifecycle and workflow actions follow safe helpers |
| `destructiveLast` | bool | yes | Destructive actions sort last |
| `emptyGroupForbidden` | bool | yes | Empty `ActionGroup` and `BulkActionGroup` placeholders are invalid |
#### Validation rules
- Overflow groups must not exist only as placeholders.
- Inspection and navigation helpers must lead the group when present.
- Non-destructive lifecycle and workflow actions must follow safe helpers and must not trail destructive actions.
- Destructive actions must sort last.
- Ordering checks are enforced through representative rendered guard tests rather than generic runtime reflection across every surface.
### PrimaryDiscoveryScope
**Purpose**: Defines which repository surfaces the primary validator must discover.
#### Included families
- Enrolled monitoring and reporting pages under `app/Filament/Pages/**`
- Enrolled representative CRUD and read-only registry resources under `app/Filament/Resources/**`
- Declared, table-backed pages under `app/Filament/System/Pages/**` for the six enrolled system list surfaces
#### Excluded families
- Widgets
- Auth pages
- Dashboards
- Choosers and onboarding wizards
- Deferred or non-table system tooling such as Runbooks
- Any class kept under explicit baseline exemption until a later spec enrolls it
#### Validation rules
- Discovery must not require new baseline exemptions for already enrolled system pages.
- Out-of-scope families must remain explicitly excluded rather than silently swept in.
## Representative Surface Mapping
| Surface | Profile | Surface type | Inspect affordance | Ordering anchor |
|---------|---------|--------------|--------------------|-----------------|
| `Monitoring/Operations` | `RunLog` | `ReadOnlyRegistryReport` | `ClickableRow` | No row actions; row click is the anchor |
| `Monitoring/AuditLog` | `RunLog` | `HistoryAudit` | Explicit inspect | No row click; context-preserving inspect is the anchor |
| `Monitoring/FindingExceptionsQueue` | `RunLog` | `QueueReview` | Explicit inspect | Selected-record workflow actions stay off the standard list row |
| `BaselineProfileResource` | `CrudListAndView` | `CrudListFirstResource` | `ClickableRow` | `More` contains safe actions first and archive last |
| `System/Ops/Runs` | `RunLog` | `ReadOnlyRegistryReport` | `ClickableRow` to canonical system run detail | Cross-panel registry coverage anchor that preserves the canonical `Operations / Run` noun |
| `System/Security/AccessLogs` | `RunLog` | `HistoryAudit` | Explicit inspect | System audit reference anchor |
## Migration Notes
- No schema migration is required.
- No new queue, notification, or asset behavior is introduced.
- The final validator state requires explicit `surfaceType` on every discovered declaration-backed surface.