From 3c3daae405eafaf89301e26fb0dc1b668e0ba7c6 Mon Sep 17 00:00:00 2001 From: ahmido Date: Sun, 22 Mar 2026 12:13:34 +0000 Subject: [PATCH] feat: normalize operator outcome taxonomy (#186) ## Summary - introduce a shared operator outcome taxonomy with semantic axes, severity bands, and next-action policy - apply the taxonomy to operations, evidence/review completeness, baseline semantics, and restore semantics - harden badge rendering, tenant-safe filtering/search behavior, and operator-facing summary/notification wording - add the spec kit artifacts, reference documentation, and regression coverage for diagnostic-vs-primary state handling ## Testing - focused Pest coverage for taxonomy registry and badge guardrails - operations presentation and notification tests - evidence, baseline, restore, and tenant-scope regression tests ## Notes - Livewire v4.0+ compliance is preserved in the existing Filament v5 stack - panel provider registration remains unchanged in bootstrap/providers.php - no new globally searchable resource was added; adopted resources remain tenant-safe and out of global search where required - no new destructive action family was introduced; existing actions keep their current authorization and confirmation behavior - no new frontend asset strategy was introduced; existing deploy flow with filament:assets remains unchanged Co-authored-by: Ahmed Darrazi Reviewed-on: https://git.cloudarix.de/ahmido/TenantAtlas/pulls/186 --- .github/agents/copilot-instructions.md | 3 +- .specify/memory/constitution.md | 72 +- .specify/templates/plan-template.md | 6 + .specify/templates/spec-template.md | 17 + .specify/templates/tasks-template.md | 7 + app/Filament/Pages/Monitoring/Operations.php | 3 + .../TenantlessOperationRunViewer.php | 8 +- app/Filament/Pages/Reviews/ReviewRegister.php | 9 +- .../Resources/BaselineSnapshotResource.php | 51 +- .../Resources/EvidenceSnapshotResource.php | 68 +- .../Resources/OperationRunResource.php | 19 +- app/Filament/Resources/RestoreRunResource.php | 6 +- .../Resources/TenantReviewResource.php | 18 +- .../Widgets/Dashboard/RecentOperations.php | 4 +- .../Workspace/WorkspaceRecentOperations.php | 2 + app/Notifications/OperationRunQueued.php | 4 +- .../BaselineSnapshotPresenter.php | 57 +- .../SnapshotRendering/FidelityState.php | 6 +- .../SnapshotRendering/GapSummary.php | 39 +- app/Support/Badges/BadgeCatalog.php | 21 + app/Support/Badges/BadgeSpec.php | 44 ++ .../Domains/BaselineSnapshotFidelityBadge.php | 12 +- .../BaselineSnapshotGapStatusBadge.php | 8 +- .../Domains/EvidenceCompletenessBadge.php | 12 +- .../Domains/OperationRunOutcomeBadge.php | 16 +- .../Domains/OperationRunStatusBadge.php | 8 +- .../Domains/RestoreCheckSeverityBadge.php | 10 +- .../Domains/RestorePreviewDecisionBadge.php | 14 +- .../Domains/RestoreResultStatusBadge.php | 18 +- .../Badges/Domains/RestoreRunStatusBadge.php | 30 +- .../TenantReviewCompletenessStateBadge.php | 12 +- .../Badges/OperatorNextActionPolicy.php | 17 + .../Badges/OperatorOutcomeTaxonomy.php | 646 ++++++++++++++++++ app/Support/Badges/OperatorSemanticAxis.php | 51 ++ .../Badges/OperatorStateClassification.php | 16 + app/Support/Filament/FilterOptionCatalog.php | 6 +- app/Support/OpsUx/OperationUxPresenter.php | 151 ++-- app/Support/OpsUx/SummaryCountsNormalizer.php | 12 +- .../Workspaces/WorkspaceOverviewBuilder.php | 4 + docs/HANDOVER.md | 3 +- docs/product/operator-semantic-taxonomy.md | 155 +++++ docs/product/principles.md | 14 +- docs/product/spec-candidates.md | 53 +- docs/product/standards/README.md | 4 +- docs/ui/operator-ux-surface-standards.md | 521 ++++++++++++++ .../components/restore-run-checks.blade.php | 12 +- .../baseline-snapshot-groups.blade.php | 8 +- .../baseline-snapshot-summary-table.blade.php | 4 +- .../entries/restore-preview.blade.php | 16 +- .../entries/restore-results.blade.php | 14 +- .../monitoring/evidence-overview.blade.php | 20 +- .../pages/monitoring/operations.blade.php | 12 +- .../system/pages/ops/view-run.blade.php | 15 +- .../recent-operations-summary.blade.php | 36 +- .../workspace-recent-operations.blade.php | 6 + .../checklists/requirements.md | 35 + ...or-state-presentation.logical.openapi.yaml | 186 +++++ .../operator-taxonomy-entry.schema.json | 187 +++++ .../data-model.md | 151 ++++ specs/156-operator-outcome-taxonomy/plan.md | 183 +++++ .../quickstart.md | 118 ++++ .../156-operator-outcome-taxonomy/research.md | 92 +++ specs/156-operator-outcome-taxonomy/spec.md | 176 +++++ specs/156-operator-outcome-taxonomy/tasks.md | 208 ++++++ .../Evidence/EvidenceSnapshotResourceTest.php | 13 +- .../BaselineSnapshotAuthorizationTest.php | 7 + ...BaselineSnapshotFidelityVisibilityTest.php | 18 +- .../BaselineSnapshotListFiltersTest.php | 6 +- .../RecentOperationsSummaryWidgetTest.php | 4 +- ...gsCatalogRestoreApplySettingsPatchTest.php | 4 +- .../TenantGlobalSearchLifecycleScopeTest.php | 11 + .../Guards/NoAdHocStatusBadgesTest.php | 2 +- .../Guards/NoDiagnosticWarningBadgesTest.php | 43 ++ .../Monitoring/OperationsTenantScopeTest.php | 32 +- .../OperationRunNotificationTest.php | 11 +- ...ionRunBlockedExecutionPresentationTest.php | 5 +- .../TenantlessOperationRunViewerTest.php | 5 +- tests/Feature/OpsUx/QueuedToastCopyTest.php | 4 +- ...TerminalNotificationFailureMessageTest.php | 3 +- tests/Unit/Badges/BadgeCatalogTest.php | 10 + tests/Unit/Badges/OperationRunBadgesTest.php | 18 +- .../Badges/OperatorOutcomeTaxonomyTest.php | 58 ++ tests/Unit/Badges/RestoreRunBadgesTest.php | 28 +- tests/Unit/Badges/RestoreUiBadgesTest.php | 28 +- .../BaselineSnapshotPresenterTest.php | 2 +- .../FallbackSnapshotTypeRendererTest.php | 3 +- .../Evidence/EvidenceSnapshotBadgeTest.php | 8 + .../BaselineSnapshotRenderingBadgeTest.php | 10 +- .../TenantReview/TenantReviewBadgeTest.php | 7 +- 89 files changed, 3757 insertions(+), 319 deletions(-) create mode 100644 app/Support/Badges/OperatorNextActionPolicy.php create mode 100644 app/Support/Badges/OperatorOutcomeTaxonomy.php create mode 100644 app/Support/Badges/OperatorSemanticAxis.php create mode 100644 app/Support/Badges/OperatorStateClassification.php create mode 100644 docs/product/operator-semantic-taxonomy.md create mode 100644 docs/ui/operator-ux-surface-standards.md create mode 100644 specs/156-operator-outcome-taxonomy/checklists/requirements.md create mode 100644 specs/156-operator-outcome-taxonomy/contracts/operator-state-presentation.logical.openapi.yaml create mode 100644 specs/156-operator-outcome-taxonomy/contracts/operator-taxonomy-entry.schema.json create mode 100644 specs/156-operator-outcome-taxonomy/data-model.md create mode 100644 specs/156-operator-outcome-taxonomy/plan.md create mode 100644 specs/156-operator-outcome-taxonomy/quickstart.md create mode 100644 specs/156-operator-outcome-taxonomy/research.md create mode 100644 specs/156-operator-outcome-taxonomy/spec.md create mode 100644 specs/156-operator-outcome-taxonomy/tasks.md create mode 100644 tests/Feature/Guards/NoDiagnosticWarningBadgesTest.php create mode 100644 tests/Unit/Badges/OperatorOutcomeTaxonomyTest.php diff --git a/.github/agents/copilot-instructions.md b/.github/agents/copilot-instructions.md index 8b0d2d7..7847cb9 100644 --- a/.github/agents/copilot-instructions.md +++ b/.github/agents/copilot-instructions.md @@ -96,6 +96,7 @@ ## Active Technologies - PostgreSQL with new tenant-owned exception tables and JSONB-backed supporting metadata (001-finding-risk-acceptance) - PHP 8.4, Laravel 12, Livewire 4, Filament 5 + Filament resources/pages/actions, Eloquent models, queued Laravel jobs, existing `EvidenceSnapshotService`, existing `ReviewPackService`, capability registry, `OperationRunService` (155-tenant-review-layer) - PostgreSQL with JSONB-backed summary payloads and tenant/workspace ownership columns (155-tenant-review-layer) +- PostgreSQL-backed existing domain records; no new business-domain table is required for the first slice; shared taxonomy reference will live in repository documentation and code-level metadata (156-operator-outcome-taxonomy) - PHP 8.4.15 (feat/005-bulk-operations) @@ -115,8 +116,8 @@ ## Code Style PHP 8.4.15: Follow standard conventions ## Recent Changes +- 156-operator-outcome-taxonomy: Added PHP 8.4.15 + Laravel 12, Filament v5, Livewire v4, PostgreSQL, Laravel Sail, Pest v4 - 155-tenant-review-layer: Added PHP 8.4, Laravel 12, Livewire 4, Filament 5 + Filament resources/pages/actions, Eloquent models, queued Laravel jobs, existing `EvidenceSnapshotService`, existing `ReviewPackService`, capability registry, `OperationRunService` - 001-finding-risk-acceptance: Added PHP 8.4.15 + Laravel 12, Filament v5, Livewire v4, Pest v4, existing Finding, AuditLog, EvidenceSnapshot, CapabilityResolver, WorkspaceCapabilityResolver, and UiEnforcement patterns -- 153-evidence-domain-foundation: Added PHP 8.4.15 + Laravel 12, Filament v5, Livewire v4, Pest v4, existing `StoredReport`, `Finding`, `OperationRun`, and `AuditLog` infrastructure diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md index 81e72a5..b8476e1 100644 --- a/.specify/memory/constitution.md +++ b/.specify/memory/constitution.md @@ -3,12 +3,17 @@ - Version change: 1.11.0 → 1.12.0 - Modified principles: - - Scope & Ownership Clarification (SCOPE-001) -- Added sections: - None +- Added sections: + - Operator Surface Principles (OPSURF-001) - Removed sections: None - Templates requiring updates: - - None + - ✅ .specify/templates/spec-template.md + - ✅ .specify/templates/plan-template.md + - ✅ .specify/templates/tasks-template.md + - ✅ docs/product/principles.md + - ✅ docs/product/standards/README.md + - ✅ docs/HANDOVER.md - Follow-up TODOs: - None. --> @@ -330,6 +335,65 @@ ### Operator-facing UI Naming Standards (UI-NAMING-001) - The visible run label for that action MUST be `Policy sync`. - The audit prose for that action MUST be `{actor} queued policy sync`. +### Operator Surface Principles (OPSURF-001) + +Goal: operator-facing surfaces MUST optimize for the primary working audience rather than raw implementation visibility. + +Operator-first default surfaces +- `/admin` is operator-first. +- Default-visible content MUST use operator-facing language, clear scope, and actionable status communication. +- Raw implementation details MUST NOT be default-visible on primary operator surfaces. + +Progressive disclosure for diagnostics +- Diagnostic detail MAY be available where needed, but it MUST be secondary and explicitly revealed. +- JSON payloads, raw IDs, internal field names, provider error details, and low-level technical metadata belong in diagnostics surfaces, drawers, tabs, accordions, or modals rather than primary content. +- A surface MUST NOT require operators to parse raw JSON or provider-specific field names to understand the primary state or next action. + +Distinct status dimensions +- Operator-facing surfaces MUST distinguish at least the following dimensions when they all exist in the domain: + - execution outcome + - data completeness + - governance result + - lifecycle or readiness state +- These dimensions MUST NOT be collapsed into a single ambiguous status model. +- If a surface summarizes multiple status dimensions, the default-visible presentation MUST label each dimension explicitly. + +Explicit mutation scope +- Every action that changes state MUST communicate before execution whether it affects: + - TenantPilot only + - the Microsoft tenant + - simulation only +- Mutation scope MUST be understandable from the action label, helper text, confirmation copy, preview, or nearby status copy before the operator commits. +- A mutating action MUST NOT rely on hidden implementation knowledge to communicate its blast radius. + +Safe execution for dangerous actions +- Dangerous actions MUST follow a consistent safe-execution pattern: + - configuration + - safety checks or simulation + - preview + - hard confirmation where required + - execute +- One-click destructive actions are not acceptable for high-blast-radius operations. +- When a full multi-step flow is not feasible, the spec MUST document the explicit exemption and the replacement safeguards. + +Explicit workspace and tenant context +- Workspace and tenant scope MUST remain explicit in navigation, actions, and page semantics. +- Tenant-scoped surfaces MUST NOT silently expose workspace-wide actions. +- Canonical workspace views that reference tenant-owned records MUST make the workspace and tenant context legible before the operator acts. + +Page contract requirement +- Every new or materially refactored operator-facing page MUST define: + - primary persona + - surface type + - primary operator question + - default-visible information + - diagnostics-only information + - status dimensions used + - mutation scope + - primary actions + - dangerous actions +- This page contract MUST be recorded in the governing spec and kept in sync when the page semantics materially change. + Spec Scope Fields (SCOPE-002) - Every feature spec MUST declare: @@ -387,4 +451,4 @@ ### Versioning Policy (SemVer) - **MINOR**: new principle/section or materially expanded guidance. - **MAJOR**: removing/redefining principles in a backward-incompatible way. -**Version**: 1.11.0 | **Ratified**: 2026-01-03 | **Last Amended**: 2026-03-10 +**Version**: 1.12.0 | **Ratified**: 2026-01-03 | **Last Amended**: 2026-03-21 diff --git a/.specify/templates/plan-template.md b/.specify/templates/plan-template.md index da2e36b..b8326be 100644 --- a/.specify/templates/plan-template.md +++ b/.specify/templates/plan-template.md @@ -50,6 +50,12 @@ ## Constitution Check - Data minimization: Inventory stores metadata + whitelisted meta; logs contain no secrets/tokens - Badge semantics (BADGE-001): status-like badges use `BadgeCatalog` / `BadgeRenderer`; no ad-hoc mappings; new values include tests - UI naming (UI-NAMING-001): operator-facing labels use `Verb + Object`; scope (`Workspace`, `Tenant`) is never the primary action label; source/domain is secondary unless disambiguation is required; runs/toasts/audit prose use the same domain vocabulary; implementation-first terms do not appear in primary operator UI +- Operator surfaces (OPSURF-001): `/admin` defaults are operator-first; default-visible content avoids raw implementation detail; diagnostics are explicitly revealed secondarily +- Operator surfaces (OPSURF-001): execution outcome, data completeness, governance result, and lifecycle/readiness are modeled as distinct status dimensions when all apply; they are not collapsed into one ambiguous status +- Operator surfaces (OPSURF-001): every mutating action communicates whether it changes TenantPilot only, the Microsoft tenant, or simulation only before execution +- Operator surfaces (OPSURF-001): dangerous actions follow configuration → safety checks/simulation → preview → hard confirmation where required → execute, unless a spec documents an explicit exemption and replacement safeguards +- Operator surfaces (OPSURF-001): workspace and tenant context remain explicit in navigation, actions, and page semantics; tenant surfaces do not silently expose workspace-wide actions +- Operator surfaces (OPSURF-001): each new or materially refactored operator-facing page defines a page contract covering persona, surface type, operator question, default-visible info, diagnostics-only info, status dimensions, mutation scope, primary actions, and dangerous actions - Filament UI Action Surface Contract: for any new/modified Filament Resource/RelationManager/Page, define Header/Row/Bulk/Empty-State actions, ensure every List/Table has a record inspection affordance (prefer `recordUrl()` clickable rows; do not render a lone View row action), keep max 2 visible row actions with the rest in “More”, group bulk actions, require confirmations for destructive actions (typed confirmation for large/bulk where applicable), write audit logs for mutations, enforce RBAC via central helpers (non-member 404, member missing capability 403), and ensure CI blocks merges if the contract is violated or not explicitly exempted - Filament UI UX-001 (Layout & IA): Create/Edit uses Main/Aside (3-col grid, Main=columnSpan(2), Aside=columnSpan(1)); all fields inside Sections/Cards (no naked inputs); View uses Infolists (not disabled edit forms); status badges use BADGE-001; empty states have specific title + explanation + 1 CTA; max 1 primary + 1 secondary header action; tables provide search/sort/filters for core dimensions; shared layout builders preferred for consistency ## Project Structure diff --git a/.specify/templates/spec-template.md b/.specify/templates/spec-template.md index aed1ef7..0d96318 100644 --- a/.specify/templates/spec-template.md +++ b/.specify/templates/spec-template.md @@ -17,6 +17,14 @@ ## Spec Scope Fields *(mandatory)* - **Default filter behavior when tenant-context is active**: [e.g., prefilter to current tenant] - **Explicit entitlement checks preventing cross-tenant leakage**: [Describe checks] +## Operator Surface Contract *(mandatory when operator-facing surfaces are changed)* + +If this feature adds a new operator-facing page or materially refactors one, fill out one row per affected page/surface. + +| Surface | Primary Persona | Surface Type | Primary Operator Question | Default-visible Information | Diagnostics-only Information | Status Dimensions Used | Mutation Scope | Primary Actions | Dangerous Actions | +|---|---|---|---|---|---|---|---|---|---| +| e.g. Tenant policies page | Tenant operator | List/detail | What needs action right now? | Policy health, drift, assignment coverage | Raw payloads, provider IDs, low-level API details | lifecycle, data completeness, governance result | TenantPilot only / Microsoft tenant / simulation only | Sync policies, View policy | Restore policy | + ## User Scenarios & Testing *(mandatory)*