# Data Model — Operations Auto-Refresh Pass ## Overview This feature does not add new tables or columns. It reuses existing persisted state to decide whether two UI surfaces should continue polling. ## Entities ### OperationRun - **Purpose**: Canonical record for queued, running, and completed operational work shown in Monitoring → Operations. - **Relevant fields**: - `id` - `workspace_id` - `tenant_id` (nullable for tenantless/canonical monitoring) - `type` - `status` - `outcome` - `context` - `summary_counts` - `failure_summary` - `created_at` - `started_at` - `completed_at` - **Relationships**: - Belongs to `Workspace` - Belongs to `Tenant` (optional) - Belongs to initiating `User` (optional) - **Polling rule**: - Poll while UX-normalized status is `queued` or `running` - Stop polling for normalized terminal states such as `succeeded`, `partial`, or `failed` - **Derived constraints**: - Polling on run-detail surfaces must continue to respect hidden-tab and mounted-action guards - No direct lifecycle mutation is added; `OperationRunService` remains the only lifecycle transition owner ### ReviewPack - **Purpose**: Persisted output of tenant review pack generation for a tenant-scoped admin surface. - **Relevant fields**: - `id` - `workspace_id` - `tenant_id` - `operation_run_id` - `initiated_by_user_id` - `status` - `options` - `summary` - `generated_at` - `expires_at` - `file_path` - `file_disk` - `file_size` - `created_at` - `updated_at` - **Relationships**: - Belongs to `Workspace` - Belongs to `Tenant` - Belongs to `OperationRun` - Belongs to initiating `User` - **Polling rule**: - Poll while `status` is `queued` or `generating` - Stop polling when `status` is `ready`, `failed`, or `expired` - Do not poll when no review pack exists for the tenant ## Derived View State ### Run detail polling state - **Source**: `OperationRun` + `RunDetailPolling::interval()` - **Output**: `1s`, `5s`, `10s`, or `null` - **Rules**: - `null` when the run is terminal - `null` when the tab is hidden - `null` when Filament action modals are mounted ### Review pack card polling state - **Source**: latest `ReviewPack` for the current tenant - **Output**: `10s` or `null` - **Rules**: - `10s` when the latest pack is `queued` or `generating` - `null` otherwise ## State Transitions ### OperationRun lifecycle relevant to polling 1. `queued` → active polling enabled 2. `running` → active polling enabled 3. `completed` + terminal outcome (`succeeded`, `failed`, `partially_succeeded`) → polling disabled 4. Any unrecognized or missing status normalization → treated as non-active for polling decisions ### ReviewPack lifecycle relevant to polling 1. `queued` → polling enabled 2. `generating` → polling enabled 3. `ready` → polling disabled 4. `failed` → polling disabled 5. `expired` → polling disabled ## Validation Rules - Polling must never start for unauthorized users; existing page and widget access checks remain authoritative. - Polling must stop automatically once terminal state is reached. - Polling decisions must be derived from persisted state only; no external API call is required during render. - Terminal-state rendering must remain stable and must not trigger repeated refresh loops.