## Summary - add the Spec 194 governance action catalog, friction classes, reason policies, and regression guards - align exception, review, evidence, finding, tenant, provider connection, and system run actions to the shared semantics model - add focused feature, RBAC, audit, unit, and browser coverage, including the tenant detail triage header consistency update ## Verification - ran the focused Spec 194 verification pack from the quickstart and task plan - ran targeted tenant triage coverage after the detail-header update - ran `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` ## Filament Notes - Filament v5 / Livewire v4 compliance preserved - provider registration remains in `apps/platform/bootstrap/providers.php` - globally searchable resources were not changed - destructive actions remain confirmation-gated and server-authorized - no new Filament assets were introduced; the existing `cd apps/platform && php artisan filament:assets` deploy step stays unchanged Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #229
22 KiB
Implementation Plan: Governance Friction Hardening and Operator Vocabulary
Branch: 194-governance-friction-hardening | Date: 2026-04-12 | Spec: /Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/194-governance-friction-hardening/spec.md
Input: Feature specification from /Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/194-governance-friction-hardening/spec.md
Note: This plan keeps the work inside the existing Filament v5 / Livewire v4 surface layer, existing mutation services, existing audit loggers, and the current RBAC helpers. It explicitly avoids introducing a new workflow engine, new persistence, or a broad UI meta-framework.
Summary
Codify one narrow governance-action semantics contract across tenant, workspace, and system surfaces. Introduce a derived governance action catalog that classifies in-scope actions into explicit friction classes, reason rules, danger semantics, and canonical vocabulary; then align the affected Filament pages and existing mutation services so exception, review, evidence, run-triage, finding-lifecycle, and tenant-lifecycle actions behave consistently. Protect the result with a spec-scoped guard, focused feature tests, RBAC regression coverage, and one browser smoke suite.
Technical Context
Language/Version: PHP 8.4.15
Primary Dependencies: Laravel 12, Filament v5, Livewire v4, Pest v4, Tailwind CSS v4, existing UiEnforcement, existing audit loggers (AuditLogger, WorkspaceAuditLogger, SystemConsoleAuditLogger), existing mutation services (FindingExceptionService, FindingWorkflowService, TenantReviewLifecycleService, EvidenceSnapshotService, OperationRunTriageService)
Storage: PostgreSQL through existing workspace-owned and tenant-owned models; no schema change planned
Testing: Pest unit, feature, and browser tests run through Laravel Sail
Target Platform: Laravel monolith web application under apps/platform, with tenant routes under /admin/t/{tenant}/..., workspace routes under /admin/..., and platform routes under /system/...
Project Type: web application
Performance Goals: Preserve current operator interaction speed, keep render-time governance semantics DB-only with no outbound HTTP, avoid adding polling or additional round trips for confirmation flows, and keep any catalog lookups constant-time and local
Constraints: No new persistence, no new workflow states, no panel/provider changes, no raw capability strings, no cross-plane authorization drift, destructive-like actions keep ->requiresConfirmation(), and no new generic execution framework
Scale/Scope: 8 primary operator surfaces across 3 authorization planes, 6 high-priority governance families, 4 medium or low-priority supporting families, focused changes to existing page classes, services, and tests only
Constitution Check
GATE: Passed before Phase 0 research. Re-check after Phase 1 design and still passing.
| Principle | Pre-Research | Post-Design | Notes |
|---|---|---|---|
| Inventory-first / snapshots-second | PASS | PASS | The feature does not alter inventory or snapshot truth. It governs action semantics only. |
| Read/write separation | PASS | PASS | Existing mutations keep confirmation, audit, and tests. No new write domain is introduced. |
| Graph contract path | N/A | N/A | No new Microsoft Graph endpoints or contract-registry changes are planned. |
| Deterministic capabilities | PASS | PASS | Existing capability registries and UiEnforcement remain authoritative. |
| Workspace + tenant isolation | PASS | PASS | Existing scope boundaries remain authoritative on /admin, /admin/t/{tenant}, and /system. |
| RBAC-UX authorization semantics | PASS | PASS | Non-member remains 404, member-without-capability remains 403, and server-side checks remain unchanged. |
| Run observability / Ops-UX | PASS | PASS | Existing OperationRun flows keep their current lifecycle and feedback contract; this feature changes only semantics. |
| Data minimization | PASS | PASS | No new persistence, caches, or semantic mirrors are introduced. |
| Proportionality / anti-bloat | PASS | PASS | The plan adds one narrow derived catalog and guard instead of a new framework or persistence layer. |
| UI semantics / few layers | PASS | PASS | The feature uses direct action semantics and targeted builders instead of a new presenter stack. |
| Filament-native UI | PASS | PASS | Native Filament actions, action groups, and current shared helpers remain the implementation path. |
| Surface taxonomy / decision-first roles | PASS | PASS | Surface roles and action semantics remain aligned with Spec 192 and Spec 193 without reclassifying the affected surfaces. |
| Filament v5 / Livewire v4 compliance | PASS | PASS | All touched surfaces remain inside the existing Filament v5 + Livewire v4 stack. |
| Provider registration location | PASS | PASS | No provider change is needed; Laravel 11+ registration remains in bootstrap/providers.php. |
| Global search hard rule | PASS | PASS | No new globally searchable resource is introduced and search settings are not altered. |
| Destructive action safety | PASS | PASS | Strong actions continue to execute via confirmed Filament actions plus current authorization. |
| Asset strategy | PASS | PASS | No new assets are planned. Existing deployment handling of cd apps/platform && php artisan filament:assets remains sufficient. |
Filament-Specific Compliance Notes
- Livewire v4.0+ compliance: The plan remains on Filament v5 + Livewire v4 and introduces no legacy APIs.
- Provider registration location: No panel or provider changes are required; registration remains in
bootstrap/providers.php. - Global search: This feature does not add new globally searchable resources and does not change current resource search behavior.
- Destructive actions:
Revoke exception,Archive review,Cancel, andArchiveremain execution actions with confirmation and server-side authorization. - Asset strategy: No new global or lazy-loaded assets are planned. Existing
filament:assetsdeployment behavior remains unchanged. - Testing plan: Add one spec-scoped guard layer, focused action and authorization tests, and one browser smoke suite across the highest-risk surfaces.
Phase 0 Research
Research outcomes are captured in /Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/194-governance-friction-hardening/research.md.
Key decisions:
- Reuse existing mutation services and audit loggers; do not add a new governance workflow engine.
- Introduce one narrow derived governance-action catalog instead of page-local constants or a broad action meta-framework.
- Keep action semantics family-first: exception, review, evidence, run-triage, finding-lifecycle, and tenant-lifecycle.
- Treat reason capture as a family contract and extend current services or audit metadata only where the spec requires stronger propagation.
- Use the existing three testing layers already proven in this repo: spec guard, focused feature/RBAC tests, and one browser smoke suite.
Phase 1 Design
Design artifacts are created under /Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/194-governance-friction-hardening/:
research.md: implementation-shape, reason-propagation, and vocabulary decisionsdata-model.md: derived governance family, rule, binding, deviation, and regression modelscontracts/governance-action-semantics.logical.openapi.yaml: internal logical contract for governance-action family rules and surface bindingsquickstart.md: implementation and verification sequence for the feature
Design highlights:
- Keep all new semantics derived, not persisted.
- Model governance rules by action family first, then bind them to concrete page actions.
- Reuse existing services as owners of state change, audit logging, and operation behavior.
- Centralize only the shared semantics that already have multiple real concrete cases.
- Keep surface placement aligned with Spec 192 and Spec 193; Spec 194 governs semantic hardness, not where actions live.
Phase 1 - Agent Context Update
Planned command:
.specify/scripts/bash/update-agent-context.sh copilot
This feature does not introduce a new technology stack, but the required context refresh still runs after the technical context and design artifacts are complete.
Project Structure
Documentation (this feature)
specs/194-governance-friction-hardening/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── spec.md
├── contracts/
│ └── governance-action-semantics.logical.openapi.yaml
└── checklists/
└── requirements.md
Source Code (repository root)
apps/platform/
├── app/
│ ├── Filament/
│ │ ├── Pages/
│ │ │ ├── Monitoring/
│ │ │ │ └── FindingExceptionsQueue.php # MODIFY
│ │ │ └── Operations/
│ │ │ └── TenantlessOperationRunViewer.php # REVIEW / possible minor alignment only
│ │ ├── Resources/
│ │ │ ├── FindingResource.php # MODIFY
│ │ │ ├── FindingResource/
│ │ │ │ └── Pages/
│ │ │ │ └── ViewFinding.php # MODIFY
│ │ │ ├── FindingExceptionResource/
│ │ │ │ └── Pages/
│ │ │ │ └── ViewFindingException.php # MODIFY
│ │ │ ├── EvidenceSnapshotResource.php # MODIFY
│ │ │ ├── EvidenceSnapshotResource/
│ │ │ │ └── Pages/
│ │ │ │ └── ViewEvidenceSnapshot.php # MODIFY
│ │ │ ├── TenantReviewResource/
│ │ │ │ └── Pages/
│ │ │ │ └── ViewTenantReview.php # MODIFY
│ │ │ ├── TenantResource.php # MODIFY
│ │ │ └── TenantResource/
│ │ │ └── Pages/
│ │ │ ├── ViewTenant.php # MODIFY
│ │ │ └── EditTenant.php # MODIFY
│ │ └── System/
│ │ └── Pages/
│ │ └── Ops/
│ │ └── ViewRun.php # MODIFY
│ ├── Services/
│ │ ├── Findings/
│ │ │ ├── FindingExceptionService.php # MODIFY
│ │ │ └── FindingWorkflowService.php # MODIFY
│ │ ├── Evidence/
│ │ │ └── EvidenceSnapshotService.php # MODIFY
│ │ ├── TenantReviews/
│ │ │ └── TenantReviewLifecycleService.php # MODIFY
│ │ └── SystemConsole/
│ │ └── OperationRunTriageService.php # MODIFY
│ ├── Support/
│ │ └── Ui/
│ │ └── GovernanceActions/
│ │ ├── GovernanceActionCatalog.php # NEW
│ │ ├── GovernanceActionRule.php # NEW
│ │ └── Enums/
│ │ ├── GovernanceFrictionClass.php # NEW
│ │ └── GovernanceReasonPolicy.php # NEW
└── tests/
├── Feature/
│ ├── Guards/
│ │ └── Spec194GovernanceActionSemanticsGuardTest.php # NEW
│ ├── Monitoring/
│ │ ├── FindingExceptionsQueueHierarchyTest.php # MODIFY
│ │ └── FindingExceptionsQueueTest.php # MODIFY
│ ├── Findings/
│ │ ├── FindingExceptionWorkflowTest.php # MODIFY
│ │ ├── FindingExceptionRenewalTest.php # MODIFY
│ │ ├── FindingExceptionRevocationTest.php # MODIFY
│ │ ├── FindingWorkflowViewActionsTest.php # MODIFY
│ │ └── FindingAuditLogTest.php # MODIFY
│ ├── Evidence/
│ │ └── EvidenceSnapshotResourceTest.php # MODIFY
│ ├── TenantReview/
│ │ ├── TenantReviewUiContractTest.php # MODIFY
│ │ └── TenantReviewLifecycleTest.php # MODIFY
│ ├── Operations/
│ │ ├── TenantlessOperationRunViewerTest.php # REVIEW / possible extend
│ │ └── SystemRunBlockedExecutionNotificationTest.php # REVIEW / possible extend
│ ├── Rbac/
│ │ ├── TenantLifecycleActionVisibilityTest.php # MODIFY
│ │ ├── EditTenantArchiveUiEnforcementTest.php # MODIFY
│ │ └── TenantResourceAuthorizationTest.php # MODIFY
│ └── Audit/
│ └── TenantLifecycleAuditLogTest.php # MODIFY
├── Unit/
│ └── Ui/
│ └── GovernanceActions/
│ └── GovernanceActionCatalogTest.php # NEW
└── Browser/
│ └── Spec194GovernanceFrictionSmokeTest.php # NEW
Structure Decision: Keep the work entirely inside the existing Laravel or Filament monolith under apps/platform. Add one narrow support namespace for shared governance semantics, then modify the affected page classes, mutation services, and focused tests. Do not introduce new persistence or a second runtime orchestration layer.
Complexity Tracking
| Violation | Why Needed | Simpler Alternative Rejected Because |
|---|---|---|
| New derived friction and reason taxonomy | The feature needs one shared project-wide rule for actions that already exist across multiple surfaces and panels. | Local constants and per-page copy edits would not prevent drift or make regression guardable. |
| New shared governance-action catalog | Multiple concrete families already exist and need one canonical source for friction, reason, vocabulary, and approved deviations. | Keeping all semantics inside individual page classes would duplicate logic, produce inconsistent naming, and make CI enforcement weak. |
Proportionality Review
- Current operator problem: Similar governance actions currently carry different semantic weight, reason burden, and vocabulary depending on the surface.
- Existing structure is insufficient because: Current page-local action definitions and service calls do not provide one guardable source for friction class, reason requirement, or canonical wording across families.
- Narrowest correct implementation: Add a small derived catalog and enums for friction and reason policy, bind existing actions to those rules, and keep all state change in the current services.
- Ownership cost created: One small shared support namespace, one spec-scoped guard test, targeted page and service test updates, and one browser smoke suite.
- Alternative intentionally rejected: A generic governance workflow framework or persisted action matrix was rejected because the repo only needs explicit cross-surface semantics, not a new runtime engine.
- Release truth: current-release operator safety, auditability, and semantic consistency
Implementation Strategy
Phase A - Codify the shared governance semantics contract
Goal: create one derived, testable source for action families without introducing a new workflow engine.
Changes:
- Add
GovernanceFrictionClassandGovernanceReasonPolicyenums. - Add
GovernanceActionRuleplusGovernanceActionCatalogas the canonical mapping of action family, friction, reason policy, danger expectation, and canonical copy. - Declare the current-release indirect risk-acceptance continuity rule so finding exception semantics remain the canonical carrier until a direct risk-acceptance surface exists.
- Add
Spec194GovernanceActionSemanticsGuardTest.phpto ensure every in-scope action family and documented deviation is declared. - Keep the catalog derived only. Do not create DB tables or stored mirrors.
Tests:
- Add
GovernanceActionCatalogTest.phpfor catalog completeness and invariants. - Add
Spec194GovernanceActionSemanticsGuardTest.phpfor project-level inventory and exception coverage.
Phase B - Align the highest-risk governance families
Goal: normalize the surfaces where semantic inconsistency carries the highest operator risk.
Changes:
- Align exception decision and lifecycle actions on
FindingExceptionsQueueandViewFindingException. - Align review publication and archival semantics on
ViewTenantReview. - Align evidence refresh versus expiry on
EvidenceSnapshotResourceandViewEvidenceSnapshot, keepingRefresh evidenceas confirmed F1 with no operator-entered reason. - Align run triage semantics on
System ViewRun, keepingRetryas confirmed F1 with no operator-entered reason whileMark investigatedandCancelkeep stronger rationale rules. - Extend or standardize reason propagation in the owning services and audit loggers where F2 or F3 requires it.
Tests:
- Extend exception workflow and queue tests.
- Extend tenant review lifecycle and UI-contract tests.
- Extend evidence snapshot resource tests.
- Add or extend run-triage tests around
ViewRun-owned actions and audit behavior.
Phase C - Align supporting lifecycle families and preserve calm surfaces
Goal: finish cross-surface consistency without overcorrecting lower-risk actions.
Changes:
- Align finding close and reopen semantics across header, row, and bulk actions in
FindingResource,ViewFinding, andFindingWorkflowService. - Align tenant archive and restore semantics across
ViewTenant,EditTenant,TenantResource, and current audit logging, keepingRestoreas confirmed F1 with no operator-entered reason. - Keep indirect risk-acceptance wording aligned with the exception family and document any allowed alias only in the shared catalog.
- Review
TenantlessOperationRunViewerto ensure it stays context-first and does not drift into a triage surface unless justified. - Keep navigation, export, and related-context actions explicitly outside governance friction.
Tests:
- Extend finding workflow header-, row-, and bulk-action tests, finding audit tests, and finding view-action tests.
- Extend tenant lifecycle RBAC, naming, and audit tests.
- Extend any affected operation viewer tests only if the viewer surface changes semantics.
Phase D - Browser verification and final regression protection
Goal: prove the new semantics in a real browser and prevent new local exceptions from returning.
Changes:
- Add
Spec194GovernanceFrictionSmokeTest.phpcovering exception queue/detail, review detail, evidence detail, system run detail, and tenant lifecycle surfaces. - Ensure the guard layer fails when a new governance action lacks a declared family, friction class, reason rule, or documented deviation.
- Re-run formatting and the focused Sail verification pack.
Tests:
- Browser smoke coverage for visible friction, copy, and danger separation.
- Focused guard, feature, and authorization tests for all changed families.
Risk Assessment
| Risk | Impact | Likelihood | Mitigation |
|---|---|---|---|
| The catalog grows into a general workflow framework | Medium | Low | Keep only friction, reason, vocabulary, and deviation metadata; leave execution in existing services. |
| Reason capture is added inconsistently across services | High | Medium | Make reason policy family-owned and test propagation at service and audit levels. |
| Low-risk actions accidentally inherit F3 semantics | Medium | Medium | Keep explicit F0 and F1 boundaries in the catalog and browser smoke coverage. |
| Surface-specific copy diverges from the family canon | Medium | Medium | Use one catalog source for labels and heading copy where practical and guard with tests. |
| Authorization semantics drift while actions are reworked | High | Low | Reuse existing Policies and UiEnforcement, and extend positive plus negative RBAC tests. |
Test Strategy
- Add
GovernanceActionCatalogTest.phpso friction, reason, and deviation rules remain internally consistent. - Add
Spec194GovernanceActionSemanticsGuardTest.phpto validate that every in-scope family, indirect risk-acceptance alias, and documented exception is declared. - Extend exception queue/detail tests to assert family-consistent reason prompts and semantic separation.
- Extend review, evidence, finding, run, tenant lifecycle, and audit tests where the plan changes semantics or reason propagation, including explicit header-, row-, and bulk-finding lifecycle coverage.
- Reuse existing RBAC feature tests to prove non-member
404, member-without-capability403, and correct disabled-state behavior where UI enforcement remains visible. - Add
Spec194GovernanceFrictionSmokeTest.phpusing the existing spec-based browser smoke pattern already present in the repo. - Run the focused Sail verification commands from
quickstart.md, then runcd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent.
Constitution Check (Post-Design)
Re-check result: PASS.
- Livewire v4.0+ compliance remains intact because all touched surfaces stay inside the existing Filament v5 + Livewire v4 stack.
- Provider registration remains unchanged in
bootstrap/providers.php. - The plan changes no global-search semantics; affected surfaces are existing resource pages or standalone pages whose search behavior is unchanged.
- Destructive and governance-changing actions keep
->requiresConfirmation()plus existing authorization. - No new assets are introduced; existing
filament:assetsdeployment behavior remains sufficient.