# Implementation Plan: Operation Run Active-State Visibility & Stale Escalation **Branch**: `233-stale-run-visibility` | **Date**: 2026-04-23 | **Spec**: [spec.md](./spec.md) **Input**: Feature specification from `/specs/233-stale-run-visibility/spec.md` ## Summary Complete one shared active-state presentation contract on top of the already-existing `OperationRun` lifecycle freshness truth by converging tenant dashboard activity signals, tenant-local active-run progress cards, workspace recent-operations summaries, the canonical operations list, and canonical run detail on the same fresh-versus-past-expected-versus-likely-stale semantics without introducing new persisted run state, new status values, or page-local heuristics. ## Technical Context **Language/Version**: PHP 8.4.15, Laravel 12, Filament v5, Livewire v4 **Primary Dependencies**: Filament widgets/resources/pages, Pest v4, `App\Models\OperationRun`, `App\Support\Operations\OperationRunFreshnessState`, `App\Services\Operations\OperationLifecycleReconciler`, `App\Support\OpsUx\OperationUxPresenter`, `App\Support\OpsUx\ActiveRuns`, `App\Support\Badges\BadgeCatalog` / `BadgeRenderer`, `App\Support\Workspaces\WorkspaceOverviewBuilder`, `App\Support\OperationRunLinks` **Storage**: Existing PostgreSQL `operation_runs` records and current session/query-backed monitoring navigation state; no new persistence **Testing**: Focused Pest feature tests over tenant dashboard widgets, tenant active-run progress surfaces, workspace overview operations summaries, canonical operations list/detail pages, and stale-reconciliation semantics **Validation Lanes**: `fast-feedback`, `confidence` **Target Platform**: Laravel admin web application in Sail containers with workspace routes under `/admin` and tenant routes under `/admin/t/{tenant}` **Project Type**: Monorepo with one Laravel runtime in `apps/platform` and spec artifacts at repository root **Performance Goals**: Preserve existing query shape and request-local presenter work; no additional remote calls, no background-process changes, and no new persisted summary projections **Constraints**: No new `OperationRun.status` or `OperationRun.outcome` values, no retry/cancel/reconcile-now UX, no new notification channel, no page-local stale heuristics, no cross-tenant leakage, and no second presentation framework beyond the existing badge/presenter path **Scale/Scope**: Existing tenant dashboard and tenant resource widgets, one Livewire active-progress slice, workspace overview builders/widgets, canonical operations list/detail pages, and their focused feature-test families ## Filament v5 Implementation Contract - **Livewire v4.0+ compliance**: Preserved. The feature extends existing Filament v5 pages/widgets/resources and Livewire components without introducing legacy Livewire v3 patterns. - **Provider registration location**: Unchanged. Panel providers remain registered in `bootstrap/providers.php`, not `bootstrap/app.php`. - **Global search coverage**: `OperationRunResource` already keeps global search disabled via `$isGloballySearchable = false`, so this feature adds no new global-search exposure and does not depend on Edit/View global-search rules. - **Destructive actions**: No destructive actions are introduced. Existing monitoring/detail actions remain read-only, and this feature must not add retry, cancel, or force-fail controls. - **Asset strategy**: No new Filament assets are planned. Deployment expectations remain unchanged, including `cd apps/platform && php artisan filament:assets` only if a future implementation adds registered assets. - **Testing plan**: Prove semantics with focused feature tests for tenant dashboard activity, tenant progress summaries, workspace recent operations, canonical operations list/detail consistency, and stale-versus-fresh boundary cases. No browser or heavy-governance lane is required for this slice. ## UI / Surface Guardrail Plan - **Guardrail scope**: Changed surfaces across tenant dashboard activity, tenant-local active-run progress, workspace recent operations summaries, canonical monitoring list rows, and canonical run detail summary - **Native vs custom classification summary**: Mixed shared-family change using native Filament widgets/resources/pages plus one existing Livewire progress component - **Shared-family relevance**: Status messaging, dashboard signals/cards, monitoring list presentation, canonical drill-through, and run-detail summary semantics - **State layers in scope**: `page`, `detail`, and one request-scoped/Livewire compact-progress slice; no new URL-state layer beyond existing monitoring continuity - **Handling modes by drift class or surface**: Review-mandatory because meaning must stay aligned across multiple existing surfaces and one existing hidden gap (`healthyActive()`-only progress) must be closed without widening scope - **Repository-signal treatment**: Review-mandatory; the feature changes operator-visible semantics but does not need a hard-stop repo guard - **Special surface test profiles**: `standard-native-filament`, `monitoring-state-page`, `shared-detail-family` - **Required tests or manual smoke**: `functional-core`, `state-contract` - **Exception path and spread control**: None planned. All covered surfaces should consume existing freshness truth and shared presenter/badge paths rather than diverging locally. - **Active feature PR close-out entry**: `Guardrail` ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes - **Systems touched**: `OperationRunFreshnessState`, `OperationLifecycleReconciler`, `OperationRun` problem-class helpers, `OperationUxPresenter`, centralized badge rendering, `BulkOperationProgress`, `RecentOperationsSummary`, `RecentOperations`, `DashboardKpis`, `NeedsAttention`, `WorkspaceOverviewBuilder`, `WorkspaceRecentOperations`, `OperationRunResource`, and `TenantlessOperationRunViewer` - **Shared abstractions reused**: `OperationRun::freshnessState()`, `OperationRun::problemClass()`, `OperationRunFreshnessState`, `OperationUxPresenter::decisionZoneTruth()`, `OperationUxPresenter::lifecycleAttentionSummary()`, `OperationUxPresenter::surfaceGuidance()`, `ActiveRuns`, `BadgeCatalog` / `BadgeRenderer`, `OperationRunLinks`, and existing workspace/tenant authorization helpers - **New abstraction introduced? why?**: One bounded derived active-state presentation contract is intentionally made explicit through the existing presenter and active-run helpers so compact and canonical surfaces can stay aligned without introducing a standalone semantic framework. - **Why the existing abstraction was sufficient or insufficient**: Existing lifecycle truth is sufficient and authoritative. Existing compact-surface adoption is insufficient because some slices already honor freshness (`OperationRunResource`, `RecentOperations`, `WorkspaceOverviewBuilder`) while others still filter to `healthyActive()` or under-communicate stale active work. - **Bounded deviation / spread control**: Same meaning, different density only. Surface-specific copy may vary by density, but all covered surfaces must consume the same freshness/problem-class truth and must not invent local stale logic. ## Constitution Check *GATE: Passed before Phase 0 research. Re-checked after Phase 1 design: still passed with one bounded derived presentation contract and no new persisted truth.* | Gate | Status | Plan Notes | |------|--------|------------| | Inventory-first / read-write separation | PASS | The feature is read-only presentation hardening over existing `operation_runs`; no restore, preview, or write-path change is introduced. | | RBAC, workspace isolation, tenant isolation | PASS | Existing tenant-scoped widgets and canonical workspace monitoring routes remain on current entitlement checks; no new visibility surface is added. | | Run observability / Ops-UX lifecycle | PASS | `OperationRunService`, lifecycle reconciliation, queued/running/terminal notifications, and run ownership remain unchanged; the plan only changes interpretation and visibility of existing run truth. | | Shared pattern first | PASS | The plan explicitly reuses existing freshness, problem-class, presenter, and badge paths rather than adding a second semantic layer or local mapping family. | | Proportionality / no premature abstraction | PASS | The narrowest credible change is one derived presentation contract over current truth plus convergence of existing surfaces. No new persistence, registry, or workflow framework is planned. | | Badge semantics / Filament-native discipline | PASS | Status-like emphasis stays on centralized badge rendering and existing Filament widgets/resources/pages; no ad-hoc surface-local color system is introduced. | | Decision-first / operator surfaces | PASS | The operations list remains the primary triage surface, tenant widgets stay secondary context, and canonical run detail stays diagnostic-first. | | Test governance | PASS | Proof stays in focused feature lanes and existing surface families, with no browser-lane promotion and no heavy shared test infrastructure growth. | ## Test Governance Check - **Test purpose / classification by changed surface**: `Feature` for tenant dashboard activity, tenant progress surfaces, workspace recent operations summaries, canonical operations list/detail consistency, and stale boundary semantics - **Affected validation lanes**: `fast-feedback`, `confidence` - **Why this lane mix is the narrowest sufficient proof**: The business truth is cross-surface semantic consistency over existing `OperationRun` freshness state. That is fully provable with focused feature tests against the touched widgets/pages and existing reconciliation truth; browser coverage would add cost without validating additional domain behavior. - **Narrowest proving command(s)**: - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php tests/Feature/OpsUx/ProgressWidgetFiltersTest.php tests/Feature/OpsUx/ProgressWidgetOverflowTest.php` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/RecentOperationsSummaryWidgetTest.php tests/Feature/Filament/DashboardKpisWidgetTest.php tests/Feature/Filament/NeedsAttentionWidgetTest.php tests/Feature/Filament/WorkspaceOverviewOperationsTest.php tests/Feature/Monitoring/OperationLifecycleFreshnessPresentationTest.php tests/Feature/Monitoring/MonitoringOperationsTest.php tests/Feature/Monitoring/OperationsDashboardDrillthroughTest.php tests/Feature/Filament/OperationRunEnterpriseDetailPageTest.php tests/Feature/Operations/TenantlessOperationRunViewerTest.php` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/RunAuthorizationTenantIsolationTest.php tests/Feature/OpsUx/NonLeakageWorkspaceOperationsTest.php` - **Fixture / helper / factory / seed / context cost risks**: Moderate. Tests need representative fresh queued/running runs, likely stale runs, reconciled terminal runs, tenant membership context, workspace overview payloads, and hidden-tenant/non-member isolation boundaries, but existing factories and operation-run helpers already cover most of that setup. - **Expensive defaults or shared helper growth introduced?**: No. Existing `OperationRun` factories and workspace/tenant test helpers should stay opt-in and sufficient. - **Heavy-family additions, promotions, or visibility changes**: none - **Surface-class relief / special coverage rule**: Standard native-Filament relief plus the existing `monitoring-state-page` proving profile for canonical monitoring pages and summaries - **Closing validation and reviewer handoff**: Re-run `pint`, then the focused feature command above. Reviewers should verify that stale active work is visible on every covered compact surface, healthy active work is not falsely escalated, and drill-through into canonical detail preserves the same active-state meaning. - **Budget / baseline / trend follow-up**: none - **Review-stop questions**: Did any surface invent its own stale threshold? Did `healthyActive()` filtering remain in a surface that should show stale-active attention? Did any test rely on status strings alone instead of freshness truth? Did any change accidentally widen visibility beyond entitled tenant/workspace scope? - **Escalation path**: `document-in-feature` - **Active feature PR close-out entry**: `Guardrail` - **Why no dedicated follow-up spec is needed**: This is bounded current-release convergence of an existing truth family. A separate follow-up spec is only needed if later work tries to add intervention actions or a broader operations workbench. ## Project Structure ### Documentation (this feature) ```text specs/233-stale-run-visibility/ ├── plan.md ├── research.md ├── data-model.md ├── quickstart.md ├── contracts/ │ └── operation-run-active-state-visibility.logical.openapi.yaml └── tasks.md ``` ### Source Code (repository root) ```text apps/platform/ ├── app/ │ ├── Filament/ │ │ ├── Pages/ │ │ │ └── Operations/TenantlessOperationRunViewer.php │ │ ├── Resources/ │ │ │ └── OperationRunResource.php │ │ └── Widgets/ │ │ ├── Dashboard/ │ │ │ ├── DashboardKpis.php │ │ │ ├── NeedsAttention.php │ │ │ └── RecentOperations.php │ │ ├── Tenant/ │ │ │ └── RecentOperationsSummary.php │ │ └── Workspace/ │ │ └── WorkspaceRecentOperations.php │ ├── Livewire/ │ │ └── BulkOperationProgress.php │ ├── Models/ │ │ └── OperationRun.php │ ├── Services/Operations/ │ │ └── OperationLifecycleReconciler.php │ └── Support/ │ ├── Badges/Domains/OperationRunStatusBadge.php │ ├── OperationRunLinks.php │ ├── OpsUx/ │ │ ├── ActiveRuns.php │ │ └── OperationUxPresenter.php │ ├── Operations/OperationRunFreshnessState.php │ └── Workspaces/WorkspaceOverviewBuilder.php ├── resources/views/ │ ├── filament/widgets/ │ │ ├── tenant/recent-operations-summary.blade.php │ │ └── workspace/workspace-recent-operations.blade.php │ └── livewire/ │ ├── bulk-operation-progress.blade.php │ └── bulk-operation-progress-wrapper.blade.php └── tests/ └── Feature/ ├── Filament/ │ ├── DashboardKpisWidgetTest.php │ ├── NeedsAttentionWidgetTest.php │ ├── OperationRunEnterpriseDetailPageTest.php │ ├── RecentOperationsSummaryWidgetTest.php │ └── WorkspaceOverviewOperationsTest.php ├── Monitoring/ │ ├── MonitoringOperationsTest.php │ ├── OperationLifecycleFreshnessPresentationTest.php │ └── OperationsDashboardDrillthroughTest.php └── Operations/ └── TenantlessOperationRunViewerTest.php ├── OpsUx/ │ ├── BulkOperationProgressDbOnlyTest.php │ ├── NonLeakageWorkspaceOperationsTest.php │ ├── ProgressWidgetFiltersTest.php │ └── ProgressWidgetOverflowTest.php └── RunAuthorizationTenantIsolationTest.php ``` **Structure Decision**: Single Laravel application inside `apps/platform`. Runtime work stays in existing monitoring widgets/resources/pages and one existing Livewire progress slice; planning artifacts stay under `specs/233-stale-run-visibility`. ## Complexity Tracking No constitutional violation is planned. One bounded derived presentation contract is intentionally tracked because the spec introduces a small new semantic family over existing truth. | Violation | Why Needed | Simpler Alternative Rejected Because | |-----------|------------|-------------------------------------| | BLOAT-001 derived category family | Compact surfaces currently disagree in practice about whether stale active work is still ordinary progress. One small derived contract keeps surface meaning aligned without changing persisted run state. | Leaving each widget to infer meaning from raw `status` or local heuristics would preserve drift and make future regressions likely. | ## Proportionality Review - **Current operator problem**: Compact operator surfaces can still hide or understate that active work is already past its expected lifecycle, so operators get false reassurance until they drill into monitoring detail. - **Existing structure is insufficient because**: Existing freshness truth and presenter helpers already exist, but they are not applied consistently across tenant progress and summary surfaces, and one slice (`BulkOperationProgress`) still intentionally filters stale active work out. - **Narrowest correct implementation**: Reuse current freshness/problem-class truth, introduce at most one small derived active-state presentation contract, and retrofit only the existing tenant/workspace/canonical monitoring surfaces that already summarize active work. - **Ownership cost created**: Small ongoing maintenance of one derived category family, shared copy alignment, and focused regression tests across covered surfaces. - **Alternative intentionally rejected**: Adding new persisted `OperationRun` statuses or separate page-local stale heuristics. Both would widen lifecycle scope or create contradictory truth. - **Release truth**: Current-release truth and operator-trust hardening. ## Phase 0 Research Summary - Existing lifecycle and freshness truth already live in `OperationRunFreshnessState`, `OperationRun::problemClass()`, and `OperationLifecycleReconciler`; the feature should consume them rather than create new thresholds. - Canonical monitoring surfaces already partially honor stale-active semantics: `OperationRunResource`, `Dashboard\RecentOperations`, and `WorkspaceOverviewBuilder` all feed badge/presenter state with `freshness_state` or lifecycle summaries. - The clearest gap was tenant-local active-progress visibility: `BulkOperationProgress` scoped to `healthyActive()`, which hid stale active work from a high-frequency tenant surface and created exactly the cross-surface contradiction the spec describes. - `OperationUxPresenter::surfaceGuidance()` already differentiates likely stale, reconciled failed, and ordinary queued/running work, so Phase 1 should extend adoption before inventing new presentation machinery. - Existing focused tests already cover parts of the semantics (`OperationLifecycleFreshnessPresentationTest`, `MonitoringOperationsTest`, `RecentOperationsSummaryWidgetTest`, `WorkspaceOverviewOperationsTest`, `OperationRunEnterpriseDetailPageTest`, `TenantlessOperationRunViewerTest`), so implementation should prefer extending those families over introducing new broad suites. ## Phase 1 Design Summary - `data-model.md` defines the derived active-state presentation model over existing `OperationRun`, freshness state, problem class, and covered surface consumers. - `contracts/operation-run-active-state-visibility.logical.openapi.yaml` documents the internal logical contract for how covered surfaces derive and display active-state meaning from existing run truth. - `quickstart.md` gives the narrow validation path for fresh-versus-stale fixtures, compact-surface rendering, canonical drill-through, and regression checks. ## Implementation Strategy 1. **Converge on one freshness-to-surface contract** - Reuse `OperationUxPresenter::decisionZoneTruth()`, `lifecycleAttentionSummary()`, current badge helpers, and `ActiveRuns` as the default convergence path. - Keep all thresholds and lifecycle windows owned by existing freshness truth. 2. **Fix the tenant-local active-progress blind spot** - Update `BulkOperationProgress` so stale active runs are not silently excluded from tenant-local progress visibility. - Preserve calm presentation for healthy active work while allowing stale/late work to escalate visibly. 3. **Align tenant dashboard and tenant-summary surfaces** - Reconcile `DashboardKpis`, `NeedsAttention`, `RecentOperationsSummary`, and any shared tenant activity slices so they expose the same active-state meaning and drill-through expectations. - Ensure mixed tenant activity does not over-generalize one stale run into “all activity is stale.” 4. **Keep workspace and canonical monitoring surfaces authoritative** - Reuse existing freshness-aware row/detail rendering in `OperationRunResource`, `TenantlessOperationRunViewer`, and `WorkspaceOverviewBuilder`, tightening copy and top-level summary semantics only where necessary. - Preserve canonical list/detail roles and existing filter continuity from tenant context. 5. **Regression-protect fresh versus stale boundaries** - Extend the existing monitoring and Filament feature tests to prove fresh active, likely stale, reconciled terminal, and terminal-transition cases across covered surfaces. - Explicitly assert that healthy queued/running runs do not inherit stale emphasis and that terminal runs disappear from active-only compact surfaces after refresh. ## Risks and Mitigations - **Surface drift survives in one slice**: A compact surface may continue to rely on `status` only. Mitigation: inventory and update every covered surface in this plan, with tests tied to each family. - **Over-escalation of healthy active work**: Copy or badge reuse could make all queued/running work feel unhealthy. Mitigation: keep the proving fixtures split between fresh and stale runs and assert negative cases explicitly. - **Tenant progress regression**: Broadening `BulkOperationProgress` could accidentally turn a calm progress bar into a noisy problem board. Mitigation: keep one bounded active-state distinction and preserve existing density expectations. - **New semantic layer grows too far**: It would be easy to invent a broader taxonomy. Mitigation: constrain the plan to one derived presentation contract backed entirely by existing freshness/problem-class truth. ## Implementation Close-Out - **Finalized affected surfaces**: Tenant active progress overlay and polling now include all active `OperationRun` records, including stale-active runs. Tenant summary, dashboard KPI/attention, workspace overview, canonical operations list, and canonical detail surfaces already consume shared freshness, badge, and presenter paths and were validated without widening the runtime change. - **Density-specific copy retained**: Compact surfaces use shared badge copy such as `Likely stale` plus `OperationUxPresenter::surfaceGuidance()` text about being past the lifecycle window. Canonical detail keeps the stronger `Likely stale operation` diagnostic banner. - **Test-governance disposition**: `document-in-feature`. Coverage stayed inside existing feature-test families and the focused `fast-feedback` / `confidence` lanes; no browser lane, heavy-governance family, shared fixture widening, or new test infrastructure was introduced. ## Post-Design Re-check Phase 0 and Phase 1 outputs keep the feature within existing `OperationRun` lifecycle truth, existing Filament/Livewire surfaces, and focused feature-test families. The plan remains constitution-compliant, Livewire v4 / Filament v5 compliant, and ready for `/speckit.tasks`.