# Implementation Plan: OperationRun Terminal Outcome Feedback v1 **Branch**: `269-operationrun-terminal-outcome-feedback` | **Date**: 2026-05-05 | **Spec**: [spec.md](./spec.md) **Input**: Feature specification from `/specs/269-operationrun-terminal-outcome-feedback/spec.md` ## Summary This plan prepares one bounded refinement over the repo's existing shell activity feedback. The current `BulkOperationProgress` surface already shows active work and recent terminal rows, but terminal success and unresolved follow-up still share too much generic terminal-update behavior. The implementation path is to keep the existing shell host, links, and progress contract intact while splitting terminal success from terminal follow-up copy and browser-session tertiary semantics, then record the final rule in `docs/ui/tenantpilot-enterprise-ui-standards.md`. Filament remains on Livewire v4, no panel-provider registration changes are required (`apps/platform/bootstrap/providers.php` remains authoritative), no globally searchable resource is added, no asset registration change is expected, and no destructive action is introduced. ## Inherited Baseline / Explicit Delta ### Inherited baseline - `OperationRun` already provides the execution-truth model and current tenant/workspace scoping. - `BulkOperationProgress` already hosts the shell activity surface on tenant-scoped pages. - `OperationUxPresenter`, `OperationStatusNormalizer`, `OperationRunProgressContract`, `OperationRunLinks`, `OperationRunUrl`, and `ActiveRuns` already own the current status, progress, and link semantics. - `ActivityFeedbackSurfaceTest`, `BulkOperationProgressDbOnlyTest`, and `OperationActivityFeedbackSmokeTest` already prove core shell behavior. ### Explicit delta in this plan - split terminal-success shell behavior from unresolved terminal-follow-up shell behavior - preserve active-state helper, progress, and canonical-link behavior unchanged unless terminal-outcome refinement requires a local adjustment - keep unresolved terminal follow-up explicitly reviewable instead of generically dismissible - keep terminal success briefly dismissible and clearly no-action-needed during the current 30-second shell-visible success window from `ActiveRuns` - keep acknowledge and dismiss behavior browser-session-only - update `docs/ui/tenantpilot-enterprise-ui-standards.md` with the terminal outcome contract ## Technical Context **Language/Version**: PHP 8.4, Laravel 12, Filament v5, Livewire v4 **Primary Dependencies**: current Ops-UX support classes, native Filament widgets or Blade, current badge infrastructure, Pest v4 **Storage**: PostgreSQL via existing `operation_runs`; browser-session state only for current shell collapse or acknowledgement behavior; no new DB storage **Testing**: Pest Feature coverage plus one required browser smoke **Validation Lanes**: fast-feedback, confidence, browser **Target Platform**: existing Laravel monolith in `apps/platform`, admin or operator plane only **Project Type**: Web application (Laravel monolith with Filament) **Performance Goals**: no new query families, no duplicate polling loops, and no additional shell host surfaces **Constraints**: no new persistence, no new lifecycle family, no new notification policy, no dashboard card, and no panel/provider/asset changes **Scale/Scope**: one current shell host, one standards update, and one browser-session tertiary-action rule ## Likely Affected Repo Surfaces - `apps/platform/app/Livewire/BulkOperationProgress.php` - `apps/platform/resources/views/livewire/bulk-operation-progress.blade.php` - `apps/platform/app/Support/OpsUx/OperationUxPresenter.php` - `apps/platform/app/Support/OpsUx/ActiveRuns.php` - `apps/platform/public/js/tenantpilot/ops-ux-progress-widget-poller.js` - `apps/platform/tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php` - `apps/platform/tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php` - `apps/platform/tests/Browser/OpsUx/OperationActivityFeedbackSmokeTest.php` - `docs/ui/tenantpilot-enterprise-ui-standards.md` ## UI / Filament & Livewire Fit - Keep the changed shell host Filament-native and local to the existing Livewire component. - The shell remains decision-first: one dominant primary action, one concise helper line, and one lifecycle-sensitive tertiary action. - Monitoring collection and detail pages remain diagnostics-first drill-through targets. The shell must not restate their evidence-heavy content. - Successful terminal rows stay briefly visible with no-action-needed semantics; unresolved terminal follow-up stays explicitly reviewable. - Browser-session `Acknowledge` stays local to the current browser session and must not become a server-side workflow state. - No new asset registration, panel configuration, or provider registration change is planned. ## RBAC / Policy Fit - Existing `OperationRun` policies remain the first and only visibility gate. - The shell continues to derive rows only after tenant context and policy filtering. - No plane expansion, no new action surface, and no new authorization rule are introduced. - Canonical Operations collection and detail pages remain the only drill-through owners for deeper diagnostics. ## Audit / Logging Fit - Existing queued toasts, browser events, and terminal DB notifications remain authoritative and unchanged. - Existing Monitoring and audit behavior remain the only audit trail. No page-view audit stream is introduced. - Because the slice changes presentation only, `OperationRun.status` and `OperationRun.outcome` ownership remain service-owned and unchanged. ## Data & Query Fit - The shell host continues to derive rows from current-tenant `OperationRun` truth. - The current 30-second terminal-success grace window in `ActiveRuns::shellVisibleQueryForTenantId()` remains the source of truth for recent successful terminal visibility in this slice. - Terminal success and terminal follow-up remain derived display states only; they do not create new persisted fields. - Acknowledge and dismiss remain browser-session scoped and must not be written to the database or to the run record. ## UI / Surface Guardrail Plan - **Guardrail scope**: changed surfaces - **Native vs custom classification summary**: native Filament plus a bounded local shell refinement - **Shared-family relevance**: Ops UX lifecycle feedback, canonical run links - **State layers in scope**: shell, page, browser-session - **Audience modes in scope**: operator-MSP - **Decision/diagnostic/raw hierarchy plan**: decision-first on the shell host, diagnostics-first on Operations collection/detail - **Raw/support gating plan**: raw and support detail stay on existing diagnostics surfaces only - **One-primary-action / duplicate-truth control**: each visible shell state keeps one dominant primary action; grouped `Review operations` remains only the label variant of the canonical collection link also exposed as `Show all operations`, and the shell differentiates `success` from `follow-up` through helper and tertiary wording instead of duplicate diagnostics - **Handling modes by drift class or surface**: review-mandatory - **Repository-signal treatment**: review-mandatory - **Special surface test profiles**: global-context-shell - **Required tests**: functional-core, named-browser-smoke - **Exception path and spread control**: none planned; any attempt to add persisted acknowledgement, dashboard work, or a second lifecycle surface resolves as `reject-or-split` - **Active feature PR close-out entry**: Guardrail / Smoke Coverage ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes - **Systems touched**: current shell hint, canonical run links, current run guidance, current progress contract, current shell poller, UI standards - **Shared abstractions reused**: `OperationUxPresenter`, `OperationStatusNormalizer`, `OperationRunProgressContract`, `OperationRunLinks`, `OperationRunUrl`, `ActiveRuns`, `OpsUxBrowserEvents` - **New abstraction introduced? why?**: none planned; keep the change local to the existing shell component and helper seams unless a tiny readability helper becomes necessary during implementation - **Why the existing abstraction was sufficient or insufficient**: the repo already owns truthful state and links; the missing piece is the terminal-outcome decision contract on the shell - **Bounded deviation / spread control**: do not create a second terminal-outcome presenter family, a registry, or a persisted acknowledgement model ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: yes, for post-completion shell follow-through and drill-through links only - **Central contract reused**: current Ops-UX shell contract via `OperationUxPresenter`, `OperationRunLinks`, `OperationRunUrl`, `OperationRunProgressContract`, and `OpsUxBrowserEvents` - **Delegated UX behaviors**: current queued toast wording, canonical `View operation`, grouped `Review operations`, and `Show all operations` links, current browser-event dispatch, and existing terminal DB-notification lifecycle remain delegated to the shared contract - **Surface-owned behavior kept local**: success vs follow-up helper copy and lifecycle-sensitive tertiary action wording only - **Queued DB-notification policy**: `N/A` - unchanged - **Terminal notification path**: unchanged central lifecycle mechanism - **Exception path**: none ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: no - **Provider-owned seams**: `N/A` - **Platform-core seams**: existing `OperationRun` truth, links, and operator vocabulary only - **Neutral platform terms / contracts preserved**: `Operation`, `View operation`, `Review operations`, `Show all operations`, `completed successfully`, `review needed` - **Retained provider-specific semantics and why**: none - **Bounded extraction or follow-up path**: none ## Constitution Check *GATE: Must pass before implementation begins and again before merge.* - Inventory-first: PASS. The slice is fully derived from existing `OperationRun` truth. - Read/write separation: PASS. No new write path or retry surface is introduced. - Graph contract path: PASS. No Graph/provider interaction is added. - Deterministic capabilities: PASS. Existing `OperationRun` policies remain authoritative. - RBAC-UX: PASS. No plane expansion; tenant/admin visibility stays on current guards and deny-as-not-found semantics. - Run observability: PASS. Existing start contract, terminal notifications, and Monitoring ownership remain unchanged while the shell only refines terminal-outcome meaning. - Ops-UX lifecycle: PASS. No change to service-owned status/outcome transitions or `summary_counts` semantics. - Data minimization: PASS. The shell remains compact and does not surface raw evidence by default. - Test governance: PASS. Proof stays bounded to focused Feature coverage plus one browser smoke. - Proportionality / no premature abstraction: PASS. The default implementation stays local to the existing shell host and standards document. - Persisted truth / behavioral state: PASS. No new table, no new lifecycle, no new persisted acknowledgement or dismiss state. - Shared pattern first / UI semantics / Filament-native UI: PASS. Existing helpers and badge semantics stay central, and the shell moves closer to a precise decision-first contract. - Provider boundary: PASS. No provider/platform seam changes. - Filament/Laravel panel safety: PASS. Filament v5 stays on Livewire v4, provider registration remains in `apps/platform/bootstrap/providers.php`, no globally searchable resource is introduced, and no new assets are planned. **Gate evaluation**: PASS. ## Test Governance Check - **Test purpose / classification by changed surface**: Feature for terminal-outcome shell behavior; one required browser smoke for live shell interaction - **Affected validation lanes**: fast-feedback, confidence, browser - **Why this lane mix is the narrowest sufficient proof**: Feature coverage proves success vs follow-up copy, tertiary actions, browser-session-only acknowledgement, and the absence of progress UI after completion. The browser smoke remains reserved for real shell interaction and re-open behavior. - **Narrowest proving command(s)**: - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/OpsUx/OperationActivityFeedbackSmokeTest.php` - **Fixture / helper / factory / seed / context cost risks**: low to moderate; reuse current `OperationRun` factories, tenant helpers, and shell smoke helpers instead of introducing new provider-heavy defaults - **Expensive defaults or shared helper growth introduced?**: no - **Heavy-family additions, promotions, or visibility changes**: none - **Surface-class relief / special coverage rule**: `global-context-shell` - **Closing validation and reviewer handoff**: reviewers should rerun the focused commands above, then confirm that unresolved terminal follow-up uses `Acknowledge` or review wording, successful completion stays dismissible, and new run-enqueue events still reopen the shell. - **Budget / baseline / trend follow-up**: none expected beyond a small feature-local increase - **Review-stop questions**: did the shell stay bounded, did unresolved follow-up stop using generic dismiss semantics, did terminal rows stay progress-free, and did acknowledgement remain browser-session-only? - **Escalation path**: `reject-or-split` for any dashboard expansion, persisted acknowledgement state, or notification-policy change - **Active feature PR close-out entry**: Guardrail / Smoke Coverage - **Why no dedicated follow-up spec is needed**: this package already narrows the live shell contract to the remaining terminal-outcome seam; larger dashboard or progress topics remain explicit follow-up candidates instead of hidden work here. ## Authorization Verification Fit - Reuse the existing shell Feature proof to verify no-tenant and no-capability suppression, tenant-safe filtering, and the absence of inaccessible run exposure on the shell host. - Keep that verification local to the current shell test family; do not create a separate authorization test family for this slice. ## Preparation Review Outcome - **Review outcome class**: `acceptable-special-case` - **Workflow outcome**: `keep` - **Test-governance outcome**: `keep` - **Reason**: the automatic candidate queue is intentionally empty, but this manual promotion is still justified because current repo truth leaves a bounded terminal-outcome gap on a live shell surface that is smaller and safer than the deferred dashboard or broader progress follow-ups. ## Project Structure ### Documentation (this feature) ```text specs/269-operationrun-terminal-outcome-feedback/ ├── spec.md ├── plan.md ├── tasks.md └── checklists/ └── requirements.md ``` This preparation package intentionally stays on the core artifacts plus the readiness checklist. The repo already contains the relevant Ops-UX truth, shell host, and proof surfaces, so no extra research, data-model, quickstart, or contracts package is required for a bounded implementation handoff. ### Source Code (expected implementation surfaces) ```text apps/platform/app/Livewire/BulkOperationProgress.php apps/platform/resources/views/livewire/bulk-operation-progress.blade.php apps/platform/app/Support/OpsUx/OperationUxPresenter.php apps/platform/app/Support/OpsUx/ActiveRuns.php apps/platform/public/js/tenantpilot/ops-ux-progress-widget-poller.js apps/platform/tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php apps/platform/tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php apps/platform/tests/Browser/OpsUx/OperationActivityFeedbackSmokeTest.php docs/ui/tenantpilot-enterprise-ui-standards.md ``` **Structure Decision**: keep the implementation local to the existing Ops-UX shell seams and standards document. Do not introduce a second activity framework or a dashboard-owned run-state model in this slice. ## Data / Migration Implications - No migration or new table is planned. - No new persisted user preference is allowed. - No new cache layer, backfill, or deploy step should be required. ## Rollout Considerations - Filament remains v5 on Livewire v4. No panel-provider change is required, and provider registration remains in `apps/platform/bootstrap/providers.php`. - No global search change is required because the slice changes a shell widget, not a resource. - No destructive action is added. - No new asset registration is expected; if future work ever registers assets, deployment still runs `cd apps/platform && php artisan filament:assets` outside this slice. ## Risk Controls - Reject any implementation that leaves unresolved terminal follow-up on generic `Dismiss` semantics. - Reject any implementation that introduces a new `OperationRun` lifecycle, a persisted acknowledgement model, or a dashboard active-operations card in this slice. - Reject any implementation that reintroduces progress UI after terminal transition. - Reject any implementation that changes notification policy, route ownership, or shell polling scope. ## Implementation Phases ### Phase 0 - Confirm Current Terminal Outcome Truth - Verify the current shell host, current helper seams, and current proof owners for successful terminal items, unresolved terminal follow-up, and browser-session collapse or acknowledge behavior. ### Phase 1 - Split Success From Follow-Up Semantics - Keep terminal success calm and dismissible. - Make unresolved terminal follow-up explicitly reviewable and acknowledge-only at the shell level. ### Phase 2 - Keep Browser-Session Outcome Actions Local - Preserve current browser-session-only shell calmness. - Ensure new run-enqueue events reopen the shell. ### Phase 3 - Record The Guardrail And Validate - Update the standards document. - Run the focused Feature proof and the named browser smoke. ## Proportionality Review - **Current operator problem**: terminal follow-up still looks too much like harmless completion in the live shell surface. - **Existing structure is insufficient because**: the broader shell feedback exists already, but its current terminal-outcome semantics are still too generic for honest decision-first behavior. - **Narrowest correct implementation**: refine the existing shell component, helper text, and browser-session tertiary actions only. - **Ownership cost created**: minimal shell branching plus focused tests and one standards update. - **Alternative intentionally rejected**: a tiny copy-only patch was rejected because it would not define the durable `success vs follow-up` action contract or prevent regression. - **Release truth**: current-release truth. The repo already ships the shell activity surface; this slice only hardens the remaining terminal-outcome seam.