# Implementation Plan: OperationRun Actionability System v1 **Branch**: `367-operationrun-actionability-system` | **Date**: 2026-06-08 | **Spec**: `specs/367-operationrun-actionability-system/spec.md` **Input**: Feature specification from `specs/367-operationrun-actionability-system/spec.md` ## Summary Introduce a derived OperationRun actionability layer that separates historical terminal execution truth from current UI follow-up truth. The implementation will keep `operation_runs` immutable history intact, classify every known operation type deliberately, migrate dashboard/Operations/current-follow-up consumers away from raw `terminalFollowUp()` semantics, and prove the known Provider Connection CTA loop is closed. ## Technical Context **Language/Version**: PHP 8.4.15, Laravel 12.52.0 **Primary Dependencies**: Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1, PostgreSQL **Storage**: Existing PostgreSQL tables only; no migration planned **Testing**: Pest 4 Unit, Feature, Architecture/guard, optional Browser smoke **Validation Lanes**: fast-feedback, confidence, browser only if rendered UI changes **Target Platform**: Laravel Sail locally, Dokploy container deployment for staging/production **Project Type**: Laravel monolith under `apps/platform` **Performance Goals**: DB-only render-time evaluation; batch-friendly dashboard and Operations table evaluation; no Graph calls during UI render **Constraints**: preserve workspace/managed-environment isolation, RBAC, OperationRunService lifecycle ownership, global-search-disabled OperationRun posture, and existing Operations routes **Scale/Scope**: Known operation types in `OperationCatalog`, provider registry, reconciliation registry, jobs, factories, seeders, and current tests ## UI / Surface Guardrail Plan - **Guardrail scope**: changed existing dashboard and Operations status/follow-up surfaces. - **Affected routes/pages/actions/states/navigation/panel/provider surfaces**: - `/admin/workspaces/{workspace}/operations` - `/admin/workspaces/{workspace}/operations/{run}` - tenant dashboard widgets `NeedsAttention` and `BaselineCompareNow` - shell active-work hint via `BulkOperationProgress` / `ActiveRuns` - **No-impact class, if applicable**: N/A. - **Native vs custom classification summary**: mixed existing native Filament table/detail plus existing dashboard widget Blade/Livewire surfaces. - **Shared-family relevance**: status messaging, dashboard signals, operation links, current follow-up filters, primary action guidance. - **State layers in scope**: widget, page, detail, shell hint, URL query for Operations filters. - **Audience modes in scope**: operator-MSP and support-platform; no customer-facing surface. - **Decision/diagnostic/raw hierarchy plan**: current actionability is default-visible; historical status remains visible; raw/support diagnostics stay secondary/collapsed/capability-gated. - **Raw/support gating plan**: unchanged existing Operations detail gating. - **One-primary-action / duplicate-truth control**: use one actionability result for dashboard count, Operations current-follow-up filters, and OperationRun action eligibility. - **Handling modes by drift class or surface**: review-mandatory for high-risk operation families and insufficient correlation proof. - **Repository-signal treatment**: hard-stop-candidate for any UI consumer that still directly treats raw terminal historical status as current follow-up after migration. - **Special surface test profiles**: monitoring-state-page, dashboard-signal, shared-detail-family. - **Required tests or manual smoke**: Unit actionability policies, Feature dashboard/Operations regressions, guard tests, optional browser smoke for the provider loop. - **Exception path and spread control**: none expected. - **Active feature PR close-out entry**: Guardrail + Smoke Coverage. - **UI/Productization coverage decision**: implementation must update existing coverage artifacts or document checked no-update rationale. - **Coverage artifacts to update**: existing Operations/dashboard entries only if visible surface contract materially changes; otherwise record no-update rationale in close-out. - **No-impact rationale**: N/A. - **Navigation / Filament provider-panel handling**: no panel/provider changes; providers remain in `apps/platform/bootstrap/providers.php`. - **Screenshot or page-report need**: screenshot only if rendered dashboard/Operations layout or copy changes materially. ## Shared Pattern & System Fit - **Shared pattern touched**: OperationRun monitoring, dashboard attention, links, current follow-up, and action eligibility. - **Existing shared paths to reuse**: - `App\Support\OperationCatalog` - `App\Support\OperationRunLinks` - `App\Support\Operations\OperationRunActionEligibility` - `App\Support\Operations\Reconciliation\OperationRunReconciliationRegistry` - `App\Support\Operations\OperationRunCorrelationResolver` - `App\Support\OpsUx\OperationUxPresenter` - `App\Support\OpsUx\ActiveRuns` - **New shared path allowed**: bounded actionability resolver/registry/policies under `App\Support\Operations\Actionability` or equivalent local namespace. - **Forbidden drift**: no parallel UI action framework, no persisted actionability table, no ad-hoc dashboard-only special case, no Graph calls, no broad Operations UX rebuild. - **OperationRun UX contract**: no run-start or terminal-notification changes. Existing OperationRun lifecycle remains service-owned. ## Constitution Check - **Inventory-first / snapshots-second**: N/A; uses existing OperationRun and domain state only. - **Read/write separation**: PASS; actionability is read-only and DB-only. - **Single Contract Path to Graph**: PASS; no Graph calls allowed in evaluation or render. - **Proportionality First / BLOAT-001**: REQUIRED and satisfied in `spec.md`; new derived status/resolver/registry is justified by a confirmed false CTA loop and multiple current consumers. - **No new persisted truth**: PASS; no migration/table. - **No new state without behavioral consequence**: PASS; actionability states change dashboard counts, CTA routing, filters, and manual-review behavior. - **Workspace/Tenant isolation**: REQUIRED; same-workspace/same-environment proof only unless operation is explicitly workspace-owned. - **RBAC-UX**: REQUIRED; existing policies stay authoritative; UI state is not security. - **OperationRun standards**: REQUIRED; historical execution truth remains `OperationRun`; current actionability is separate derived truth. - **UI-COV-001**: REQUIRED; existing reachable UI surfaces change in status/follow-up semantics. - **TEST-GOV-001**: REQUIRED; test lanes and fixture costs are explicit. - **LEAN-001**: PASS; no legacy compatibility shims or data migration. ## Project Structure Likely application surfaces for later implementation: ```text apps/platform/app/Models/OperationRun.php apps/platform/app/Support/OperationCatalog.php apps/platform/app/Support/OperationRunLinks.php apps/platform/app/Support/Operations/Actionability/ apps/platform/app/Support/Operations/OperationRunActionEligibility.php apps/platform/app/Support/Operations/Reconciliation/ apps/platform/app/Support/OpsUx/ActiveRuns.php apps/platform/app/Support/OpsUx/OperationUxPresenter.php apps/platform/app/Support/GovernanceInbox/GovernanceInboxSectionBuilder.php apps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummaryBuilder.php apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php apps/platform/app/Filament/Widgets/Dashboard/NeedsAttention.php apps/platform/app/Filament/Widgets/Dashboard/BaselineCompareNow.php apps/platform/app/Filament/Widgets/Operations/OperationsWorkbenchStats.php apps/platform/app/Filament/Pages/Monitoring/Operations.php apps/platform/app/Filament/Resources/OperationRunResource.php apps/platform/app/Filament/Pages/Operations/TenantlessOperationRunViewer.php apps/platform/app/Livewire/BulkOperationProgress.php specs/367-operationrun-actionability-system/repo-truth-map.md apps/platform/lang/en/localization.php apps/platform/lang/de/localization.php apps/platform/tests/Unit/Support/Operations/ apps/platform/tests/Feature/Operations/ apps/platform/tests/Feature/Monitoring/ apps/platform/tests/Feature/Guards/ apps/platform/tests/Browser/ ``` ## Data Model / Persistence Impact - No new tables. - No migration. - No new persisted actionability column. - Tenant-bound `OperationRun` records remain tenant-owned operational artifacts for authorization purposes even though canonical Operations routes are workspace-scoped; workspace-only runs are valid only for explicitly workspace-owned operation types. - Existing `operation_runs.context` may be read for correlation proof; implementation must not mutate historical context as part of evaluation. - Related current-state proof may read existing models such as `ProviderConnection`, `BaselineSnapshot`, `EvidenceSnapshot`, `EnvironmentReview`, `ReviewPack`, `BackupSet`, and `RestoreRun` only where the policy can prove same-scope ownership. ## Domain Model / Service Approach 1. Add a derived actionability result object. 2. Add a derived actionability status enum/value object. 3. Add a resolver with single-run and batch evaluation APIs. 4. Add a registry that maps canonical operation families to policies and fails coverage tests when known types are uncovered. 5. Implement initial policies: - provider connection checks - repeatable sync operations - baseline operations - evidence/review/review-pack artifact operations - backup operations - restore/promotion/destructive-like operations - alert/notification/informational fallback decisions discovered during implementation 6. Explicitly classify every remaining `OperationCatalog::canonicalInventory()` entry as actionable, manual-review, superseded-capable, resolved-by-current-state-capable, or informational-only. 7. Reuse `OperationCatalog` for canonical/alias type resolution. 8. Reuse existing reconciliation proof where it is already same-scope and safe. 9. Feed result into existing `OperationRunActionEligibility` instead of replacing it. ## Policy Semantics - **Actionable**: current operator action exists and should count in dashboard/current filters. - **Requires manual review**: current action remains necessary because safe automatic resolution is not provable. - **Superseded by later success**: later same-scope successful run proves old terminal problem no longer current. - **Resolved by current state**: current domain model proves old terminal problem no longer current. - **Informational only**: historical record only; never dashboard CTA. - **Not terminal**: active/non-problem run; active stale remains owned by existing freshness/reconciliation path. ## UI / Filament / Livewire Implications - Filament v5 / Livewire v4.0+ compliance remains required; current app has Livewire 4.1.4. - Panel providers remain registered in `apps/platform/bootstrap/providers.php`; no panel provider changes planned. - `OperationRunResource` remains `protected static bool $isGloballySearchable = false`; no global search changes. - No destructive actions are added. Existing high-impact Operations actions continue using existing confirmation/authorization patterns. - Dashboard widgets must show current actionability counts, not raw historical terminal follow-up. - Operations list/current-follow-up filters must distinguish current actionable/manual-review rows from historical resolved/superseded rows. - Operations workbench stats, Governance Inbox, environment dashboard summaries, workspace overview signals, and `OperationUxPresenter` decision copy must use actionability for current-follow-up truth or explicitly remain historical-only. - Operation detail should show historical status and current actionability separately if implementation touches rendered detail. - Shell active-run hint must not mix terminal actionability with active progress semantics; existing terminal follow-up visibility in `ActiveRuns::shellVisibleQueryForTenantId()` must be removed or converted into a distinct actionability-backed non-active signal. ## RBAC / Policy Implications - Existing `OperationRunPolicy` and workspace/environment entitlement checks remain authoritative. - Any actionability result that references a superseding run or resolving model must be same workspace and same managed environment or explicitly workspace-owned. - Non-members must not learn that hidden runs or hidden resolving models exist. - Dashboard counts and Operations filters must run inside actor-visible scope. ## Audit / Observability / Evidence Implications - No new AuditLog writes for read-only evaluation. - No changes to OperationRun lifecycle transitions. - Historical terminal status remains audit truth. - Current actionability explanation is derived UI truth; it should be testable and explainable but not persisted. ## Performance Plan - Use batch evaluation for dashboard/Operations collections. - Group lookups by operation family and scope. - Avoid per-row `ProviderConnection`, artifact, or later-run queries in table render and in multi-tenant aggregate builders such as workspace overview and governance inbox. - Keep evaluation DB-only and deterministic. - Add tests or code-review tasks to catch obvious N+1 regressions in actionability consumer paths. ## Test Strategy - **Unit**: - resolver/result/status behavior - provider connection policy - repeatable sync policy - baseline/artifact/backup policies - high-risk manual-review policy - registry coverage against operation catalog - **Feature**: - dashboard provider loop regression - dashboard/BaselineCompareNow current follow-up counts - Operations filters and action links - cross-workspace/cross-environment non-resolution - action eligibility alignment - **Guard / Architecture**: - no direct current-follow-up UI consumption of `terminalFollowUp()` / `dashboardNeedsFollowUp()` - new operation types require actionability coverage - no Graph calls in actionability/render tests through fail-hard binding where practical - **Browser**: - bounded provider-loop smoke if UI rendering changes: old provider blocker, current healthy state, dashboard no false CTA, Operations history still visible. ## Rollout / Deployment Considerations - **Env vars**: none. - **Migrations**: none. - **Queues/workers**: none. - **Scheduler**: none. - **Storage/volumes**: none. - **Filament assets**: no new assets; `filament:assets` not newly required by this spec. - **Staging/production**: validate on Staging before Production because dashboard current-follow-up semantics change operator attention routing. - **Rollback**: code rollback restores old raw terminal-follow-up behavior; no data rollback needed. ## Implementation Phases ### Phase 1 - Repo Truth Inventory - Confirm all known operation types from `OperationCatalog`, provider registry, reconciliation registry, jobs, factories, seeders, and tests. - Confirm every current consumer of terminal follow-up / dashboard follow-up / problem class. - Confirm ProviderConnection current-state proof fields. ### Phase 2 - Failing Proof - Add Unit/Feature/Guard tests before runtime changes where practical. - Prove the provider CTA loop, repeatable superseded success, high-risk manual review, cross-scope non-resolution, and guard coverage. ### Phase 3 - Core Actionability Contract - Add status/result/resolver/registry/policies. - Add batch evaluation APIs. - Register known operation families. ### Phase 4 - Consumer Migration - Migrate Dashboard, BaselineCompareNow, Operations filters/list/detail, OperationRunActionEligibility, OperationRunLinks where relevant, and ActiveRuns boundaries. - Keep history visible. ### Phase 5 - Validation and Close-Out - Run focused tests and optional browser smoke. - Update or document UI coverage artifacts. - Record Filament/Livewire/global-search/destructive-action/asset/deployment posture in close-out. ## Risk Controls - Default to actionable/manual-review when correlation proof is incomplete. - Keep high-risk mutation families manual-review. - Require same-scope proof for superseded/resolved outcomes. - Do not evaluate with Graph calls. - Do not add persistence. - Do not remove `terminalFollowUp()` until all current consumers are migrated and guard tests exist. ## Implementation Verification Notes - No product question blocks implementation. The implementation loop must verify which exact ProviderConnection timestamp or verification proof is safe for `resolved_by_current_state` when no later successful run exists. If no reliable field exists, the provider policy can still resolve via later same-scope successful runs and must otherwise leave the old blocker actionable/manual-review. ## Readiness Assessment Ready for implementation once `tasks.md` is followed. The only verification note is ProviderConnection proof-field selection, not a product blocker, because the provider policy can rely on later same-scope successful runs if timestamp proof is insufficient.