## Summary - amend the operator UI constitution and related SpecKit templates for the new UI/UX governance rules - add Spec 168 artifacts plus the tenant governance aggregate implementation used by the tenant dashboard, banner, and baseline compare landing surfaces - normalize Filament action surfaces around clickable-row inspection, grouped secondary actions, and explicit action-surface declarations across enrolled resources and pages - fix post-suite regressions in membership cache priming, finding workflow state refresh, tenant review derived-state invalidation, and tenant-bound backup-set related navigation ## Commit Series - `docs: amend operator UI constitution` - `spec: add tenant governance aggregate contract` - `feat: add tenant governance aggregate contract` - `refactor: normalize filament action surfaces` - `fix: resolve post-suite state regressions` ## Testing - `vendor/bin/sail artisan test --compact` - Result: `3176 passed, 8 skipped (17384 assertions)` ## Notes - Livewire v4 / Filament v5 stack remains unchanged - no provider registration changes; `bootstrap/providers.php` remains the relevant location - no new global-search resources or asset-registration changes in this branch Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #199
9.5 KiB
Phase 1 Data Model: Tenant Governance Aggregate Contract
Overview
This feature does not add a database table or persisted summary artifact. It formalizes the existing persistent source truths that already drive tenant governance posture and adds one derived runtime contract plus request-scoped reuse rules for the shared summary family.
Persistent Source Truths
Tenant
Purpose: The tenant is the scope boundary for the aggregate and for every covered surface.
Key fields:
idworkspace_idexternal_id
Validation rules:
- Aggregate resolution is allowed only for one explicit tenant scope at a time.
- Workspace membership and tenant entitlement remain authoritative before any summary surface renders.
BaselineTenantAssignment and BaselineProfile
Purpose: Define whether the tenant has an assigned baseline and which profile and snapshot chain determine compare availability.
Key fields:
baseline_tenant_assignments.tenant_idbaseline_tenant_assignments.baseline_profile_idbaseline_profiles.idbaseline_profiles.namebaseline_profiles.active_snapshot_id
Validation rules:
- Missing assignment and missing snapshot remain derived availability states, not new persisted governance states.
BaselineSnapshot
Purpose: Supplies consumable compare-snapshot truth for the assigned baseline profile.
Key fields:
idbaseline_profile_id- lifecycle/completion fields already used by
BaselineSnapshotTruthResolver
Validation rules:
- Snapshot usability remains governed by existing compare truth logic.
- The aggregate must not invent a second snapshot-availability rule set.
OperationRun
Purpose: Supplies baseline-compare progress, completion, failure, and freshness context.
Key fields:
idtenant_idworkspace_idtypestatusoutcomecompleted_atcontext
Validation rules:
- Only existing baseline-compare runs influence compare posture in this slice.
- The aggregate does not introduce a new run type or a second operational state model.
Finding and FindingException
Purpose: Supply overdue workflow state, visible drift pressure, and accepted-risk governance validity.
Key fields:
findings.tenant_idfindings.statusfindings.severityfindings.due_atfinding_exceptions.current_validity_state
Validation rules:
- Overdue, expiring, lapsed, active-non-new, and high-severity-active counts remain derived from current findings truth.
- The aggregate must not redefine accepted-risk validity semantics.
Existing Runtime Source Objects
BaselineCompareStats
Purpose: Existing query-backed compare truth object that already combines compare availability, diagnostics, and governance-attention counts for one tenant.
Key fields consumed by this feature:
stateprofileNameoperationRunIdfindingsCountlastComparedHumanlastComparedIsoreasonCodeoverdueOpenFindingsCountexpiringGovernanceCountlapsedGovernanceCountactiveNonNewFindingsCounthighSeverityActiveFindingsCount
Relationship to the new aggregate:
- The aggregate is built from one
BaselineCompareStatsresolution. - Landing diagnostics continue to read
BaselineCompareStatsdirectly.
BaselineCompareSummaryAssessment
Purpose: Existing summary interpretation object that maps BaselineCompareStats to posture family, tone, headline, supporting message, and next-action target.
Key fields consumed by this feature:
stateFamilyheadlinesupportingMessagetonepositiveClaimAllowedreasonCodenextActionTarget()nextActionLabel()
Relationship to the new aggregate:
- The aggregate uses the summary assessment as its summary-semantics input.
- The feature must not fork a second state-family interpretation path.
New Derived Runtime Entities
TenantGovernanceAggregate
Purpose: One tenant-scoped operator summary contract that owns the shared posture, count family, and next-action intent for tenant-governance summary surfaces.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
tenant_id |
int | yes | Tenant scope for the aggregate |
workspace_id |
int | yes | Workspace scope for request-local reuse safety |
profile_name |
string nullable | no | Assigned baseline profile name when available |
compare_state |
string | yes | Existing compare availability or execution state from BaselineCompareStats |
state_family |
string | yes | Existing summary posture family from BaselineCompareSummaryAssessment |
tone |
string | yes | Existing tone family used by covered summary surfaces |
headline |
string | yes | Operator-facing summary headline |
supporting_message |
string nullable | no | Secondary operator-facing explanation |
reason_code |
string nullable | no | Summary reason code when available |
last_compared_label |
string nullable | no | Human-readable freshness label |
visible_drift_findings_count |
int | yes | Visible drift findings count from compare stats |
overdue_open_findings_count |
int | yes | Overdue open findings count |
expiring_governance_count |
int | yes | Accepted-risk governance nearing expiry |
lapsed_governance_count |
int | yes | Accepted-risk governance no longer valid |
active_non_new_findings_count |
int | yes | Active non-new findings pressure |
high_severity_active_findings_count |
int | yes | High-severity active findings pressure |
next_action_label |
string | yes | Stable operator-facing next-step label |
next_action_target |
enum(findings,run,landing,none) |
yes | Stable next-action intent; surfaces map this to local URLs |
positive_claim_allowed |
bool | yes | Whether the current summary posture qualifies as a trustworthy all-clear |
stats |
BaselineCompareStats |
yes | Embedded source truth used when a consumer also needs compare diagnostics |
summary_assessment |
BaselineCompareSummaryAssessment |
yes | Embedded summary truth used by all covered surfaces |
Validation rules
- The aggregate must be built from exactly one
BaselineCompareStatsinstance and exactly oneBaselineCompareSummaryAssessmentderived from that stats instance. - Count fields must be copied from the same stats instance; surfaces must not recompute them locally.
- Final URLs, local badges, and layout-specific copy remain outside the aggregate.
TenantGovernanceAggregateResolver
Purpose: Service seam that resolves one TenantGovernanceAggregate per tenant scope and handles request-local reuse.
Fields / Inputs
| Field | Type | Required | Description |
|---|---|---|---|
tenant |
Tenant nullable |
yes | Target tenant; nullable only for explicit no-tenant handling paths |
workspace_id |
int nullable | no | Optional explicit scope input for guardable key composition |
surface_variant |
string | yes | Stable consumer variant used when request-local reuse or guard declarations need surface-specific context |
Validation rules
- The resolver must stay derived-only.
- Reuse must be request-local only.
- A no-tenant or wrong-tenant path must never reuse a previous tenant’s aggregate.
DerivedStateFamily::TenantGovernanceAggregate
Purpose: Extends the existing Spec 167 request-scoped derived-state contract so the aggregate follows the same consumer-declaration and guard rules as other supported deterministic families.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
family |
enum value | yes | Stable family identifier for request-local aggregate reuse |
default_freshness_policy |
enum | yes | Expected to remain invalidate_after_mutation for landing refresh paths |
allows_negative_result_cache |
bool | yes | Aggregate resolution should be reusable for deterministic no-tenant or unavailable states only if the final key contract explicitly supports it |
Consumer Mapping
| Consumer | Aggregate responsibility | Local responsibility |
|---|---|---|
NeedsAttention |
Overdue, expiring, lapsed, high-severity counts; baseline posture headline; next-action intent | Operations-in-progress count and widget-specific healthy fallback layout |
BaselineCompareNow |
Baseline posture family, headline, supporting message, next-action intent | Tenant-panel URL mapping for findings, run detail, and landing drill-down |
BaselineCompareCoverageBanner |
Banner visibility posture family, tone, headline, supporting message, next-action intent | Banner-specific show/hide threshold and local URL mapping |
BaselineCompareLanding |
Default-visible posture zone and next-action intent | Compare diagnostics, evidence-gap detail, duplicate-name detail, and existing Compare now action |
Derived State Lifecycle
- A covered tenant summary surface asks the resolver for the current tenant aggregate.
- The resolver resolves or reuses one request-scoped aggregate for that tenant scope.
- Covered surfaces read the same posture family, count family, and next-action intent from the shared aggregate.
- If an in-request mutation or refresh path makes the current aggregate stale, the resolver uses explicit invalidation or fresh-resolution semantics.
- The next request builds a new aggregate from current source truth.
Migration Notes
- No schema migration is required.
- Existing
BaselineCompareStatstests remain the low-level source-truth tests. - If the implementation adds a new derived-state family, it must also extend the Spec 167 consumer-declaration contract and guard test.