# 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`, and `Archive` remain execution actions with confirmation and server-side authorization. - **Asset strategy**: No new global or lazy-loaded assets are planned. Existing `filament:assets` deployment 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 decisions - `data-model.md`: derived governance family, rule, binding, deviation, and regression models - `contracts/governance-action-semantics.logical.openapi.yaml`: internal logical contract for governance-action family rules and surface bindings - `quickstart.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) ```text 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) ```text 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 `GovernanceFrictionClass` and `GovernanceReasonPolicy` enums. - Add `GovernanceActionRule` plus `GovernanceActionCatalog` as 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.php` to 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.php` for catalog completeness and invariants. - Add `Spec194GovernanceActionSemanticsGuardTest.php` for 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 `FindingExceptionsQueue` and `ViewFindingException`. - Align review publication and archival semantics on `ViewTenantReview`. - Align evidence refresh versus expiry on `EvidenceSnapshotResource` and `ViewEvidenceSnapshot`, keeping `Refresh evidence` as confirmed F1 with no operator-entered reason. - Align run triage semantics on `System ViewRun`, keeping `Retry` as confirmed F1 with no operator-entered reason while `Mark investigated` and `Cancel` keep 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`, and `FindingWorkflowService`. - Align tenant archive and restore semantics across `ViewTenant`, `EditTenant`, `TenantResource`, and current audit logging, keeping `Restore` as 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 `TenantlessOperationRunViewer` to 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.php` covering 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.php` so friction, reason, and deviation rules remain internally consistent. - Add `Spec194GovernanceActionSemanticsGuardTest.php` to 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-capability `403`, and correct disabled-state behavior where UI enforcement remains visible. - Add `Spec194GovernanceFrictionSmokeTest.php` using the existing spec-based browser smoke pattern already present in the repo. - Run the focused Sail verification commands from `quickstart.md`, then run `cd 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:assets` deployment behavior remains sufficient.