# Data Model: Operation Run Active-State Visibility & Stale Escalation ## Overview This feature introduces no new persisted entity, table, or stored projection. It formalizes one derived active-state presentation contract over existing `OperationRun` lifecycle truth so tenant and workspace monitoring surfaces present the same meaning. ## Source Entity: OperationRun - **Purpose**: Canonical lifecycle and outcome record for long-running admin-plane work. - **Existing fields used by this feature**: - `id` - `workspace_id` - `tenant_id` - `type` - `status` - `outcome` - `created_at` - `started_at` - `completed_at` - `context` - `failure_summary` - **Existing relationships used by this feature**: - `tenant` - `user` where available for initiator context - **Existing invariants**: - Lifecycle status and outcome remain service-owned. - Reconciliation metadata stays inside `context.reconciliation`. - No new persisted status or outcome values are introduced for visibility purposes. ## Derived Truth: OperationRunFreshnessState - **Type**: Existing enum `App\Support\Operations\OperationRunFreshnessState` - **Values**: - `fresh_active` - `likely_stale` - `reconciled_failed` - `terminal_normal` - `unknown` - **Inputs**: - `status` - `created_at` - `started_at` - `context.reconciliation` - existing `OperationLifecyclePolicy` - **Behavioral rule**: - This remains the only stale/late truth input for surface rendering. - No widget, page, or Livewire component may introduce its own threshold logic. ## Derived Truth: OperationRun Problem Class - **Type**: Existing derived string on `OperationRun` - **Values**: - `none` - `active_stale_attention` - `terminal_follow_up` - **Purpose**: - Separates active stale attention from terminal follow-up while keeping both distinct from calm/no-action runs. - **Relationship to freshness**: - `likely_stale` freshness yields `active_stale_attention`. - `reconciled_failed` freshness yields `terminal_follow_up`. - Completed blocked/partial/failed runs may also yield `terminal_follow_up` without stale lineage. ## Derived View Model: Active-State Presentation Contract - **Type**: Derived, request-scoped presentation payload. Prefer reuse of `OperationUxPresenter::decisionZoneTruth()` and existing badge/presenter outputs before adding any new helper. - **Required fields across covered surfaces**: - `freshness_state` - `problem_class` - `is_currently_active` - `is_reconciled` - `compact_label` - `diagnostic_label` - `guidance` - `stale_lineage_note` - `show_in_active_progress` - `keep_active_polling` - **Presentation categories**: - `healthy_active` - `past_expected_lifecycle` - `likely_stale` - `no_longer_active` - `unknown` fallback - **Category mapping rules**: - `fresh_active` + active run -> `healthy_active` - `likely_stale` on compact summary surfaces -> `past_expected_lifecycle` - `likely_stale` on canonical or stronger diagnostic surfaces -> `likely_stale` - `terminal_normal` or `reconciled_failed` -> `no_longer_active` - `unknown` -> fallback copy without false stale escalation - **Important constraint**: - `past_expected_lifecycle` and `likely_stale` are density variants over the same stale truth, not separate persisted states. ## Derived Surface Policy: Tenant Active Progress Visibility - **Current consumers**: - `App\Livewire\BulkOperationProgress` - `App\Support\OpsUx\ActiveRuns` - **Former issue**: - Both used `healthyActive()` and therefore suppressed stale-active runs from the tenant progress overlay and polling decision. - **Implemented rule**: - Fresh and stale active runs remain visible as active work. - Terminal runs disappear on the next refresh cycle. - Polling continues while any visible active work remains, including stale-active runs. - Overlay rendering uses the existing status badge and `OperationUxPresenter` guidance path so stale-active elevation stays derived from shared freshness truth. ## Covered Surface Consumers | Consumer | Current Truth Inputs | Required Change | |---|---|---| | `BulkOperationProgress` | Active run query, `healthyActive()`, `ActiveRuns` | Include stale-active work in visibility and polling semantics while keeping terminal runs excluded | | `RecentOperationsSummary` | Raw recent runs for tenant | Ensure active-state emphasis and copy stay aligned with canonical freshness meaning | | `Dashboard\RecentOperations` | Badge rendering + `OperationUxPresenter` | Preserve and tighten existing freshness-aware row semantics | | `Dashboard\NeedsAttention` / `DashboardKpis` | Problem-class counts + links | Keep stale-active counts and linked monitoring semantics aligned | | `WorkspaceOverviewBuilder` / `WorkspaceRecentOperations` | Badge rendering + `OperationUxPresenter` | Preserve workspace summary consistency and diagnostic separation | | `OperationRunResource` | Status/outcome badges + lifecycle summaries | Keep canonical list/detail authoritative and consistent with compact surfaces | | `TenantlessOperationRunViewer` | Canonical detail page around resource truth | Preserve diagnostic-first explanation of stale versus terminal meaning | ## State Transitions Relevant To This Feature 1. `queued` or `running` within lifecycle threshold - Freshness: `fresh_active` - Presentation: `healthy_active` - Visible on active-only compact surfaces: yes 2. `queued` or `running` beyond lifecycle threshold - Freshness: `likely_stale` - Presentation: `past_expected_lifecycle` on compact surfaces, `likely_stale` on diagnostic surfaces - Visible on active-only compact surfaces: yes 3. `completed` without reconciliation - Freshness: `terminal_normal` - Presentation: `no_longer_active` - Visible on active-only compact surfaces: no 4. `completed` with reconciliation metadata - Freshness: `reconciled_failed` - Presentation: `no_longer_active` with stale-lineage diagnostics - Visible on active-only compact surfaces: no ## Validation Rules And Invariants - No new `OperationRun.status` or `OperationRun.outcome` values may be added. - No new persisted `operation_runs` summary or mirror table may be added. - All stale/late meaning must derive from existing freshness truth. - Tenant-scoped surfaces must only reflect runs already visible to the current tenant-entitled operator. - Workspace summaries must stay limited to entitled tenant slices. - Healthy queued/running work must not inherit stale emphasis. - Terminal runs must stop appearing in active-only surfaces on the next refresh cycle.