# Data Model: System Operations Surface Alignment ## Overview This feature introduces no new persisted entity, no new table, and no new status family. It reuses existing `OperationRun` truth and existing platform capability checks, while narrowing where triage actions are exposed in the UI. ## Entity: OperationRun - **Type**: Existing persisted model - **Purpose in this feature**: Canonical record shown on the three system list pages and on the system run detail page. ### Relevant Fields | Field | Type | Notes | |-------|------|-------| | `id` | integer | Displayed as `Operation #` and used in canonical detail routing. | | `workspace_id` | integer | Required for platform-wide run context. | | `tenant_id` | integer nullable | Nullable for tenantless/platform runs; still shown on system lists and detail. | | `initiator_name` | string nullable | Default-visible operator truth on the all-runs list. | | `type` | string | Rendered through `OperationCatalog::label(...)`. | | `status` | string | Badge-rendered lifecycle dimension. | | `outcome` | string | Badge-rendered execution-outcome dimension. | | `context` | array/json | Stores triage metadata such as retry, cancel, and investigation context. | | `created_at` | timestamp | Used for default-visible list activity time and recency on all three lists. | | `started_at` | timestamp nullable | Supports stuck classification and detail timing. | | `completed_at` | timestamp nullable | Preserved for completed/failed runs and detail history. | ### Relationships | Relationship | Target | Purpose | |--------------|--------|---------| | `workspace` | `Workspace` | Default-visible context on all system lists and on the detail page. | | `tenant` | `Tenant` | Default-visible context on all system lists and on the detail page. | ### Feature-Specific Invariants - All three system lists eager-load `tenant` and `workspace`. - `Runs` shows the full platform-wide run set. - `Failures` filters to `status=completed` and `outcome=failed`. - `Stuck` filters through `StuckRunClassifier` and exposes a derived `stuck_class` label. - List inspection always resolves to `SystemOperationRunLinks::view($run)`. ### State Transitions Used By This Feature | Transition | Preconditions | Result | |------------|---------------|--------| | Inspect list row | Operator has `platform.operations.view` | No state change; opens canonical detail page. | | Retry run | Run is completed, failed, and retryable | Creates a new queued `OperationRun` with `context.triage.retry_of_run_id` and audit action `platform.system_console.retry`. | | Cancel run | Run is queued or running and cancelable | Updates the current run to completed/failed through `OperationRunService` and logs `platform.system_console.cancel`. | | Mark investigated | Operator has manage capability and supplies a valid reason | Updates `context.triage.investigated` on the current run and logs `platform.system_console.mark_investigated`. | ## Entity: PlatformUser Capability Gate - **Type**: Existing persisted/authenticated actor model - **Purpose in this feature**: Separates inspection access from triage access on system-panel surfaces. ### Relevant Capability Fields | Capability | Purpose | |------------|---------| | `platform.access_system_panel` | Required to enter the system panel. | | `platform.operations.view` | Required to access the system runs/failures/stuck/detail surfaces. | | `platform.operations.manage` | Required to see and execute triage actions on the detail page. | ### Feature-Specific Invariants - View-only users can load list and detail pages but cannot see triage actions. - Manage-capable users retain retry/cancel/mark-investigated on the detail header. - No new capability is introduced. ## Derived UI Contract: System Operations Lists - **Type**: Derived UI surface, not persisted - **Routes**: - `/system/ops/runs` - `/system/ops/failures` - `/system/ops/stuck` - **Surface Type**: `ReadOnlyRegistryReport` - **Primary Question**: Which operation should I open next? ### Contract Rules - Primary inspect affordance is full-row click only. - Row actions are empty. - Bulk actions are empty. - Visible collection naming uses `Operations` and visible singular naming uses `Operation`. - `/system/ops/runs` uses `Go to runbooks` as its single header and empty-state CTA. - `/system/ops/failures` and `/system/ops/stuck` use `Show all operations` as their single header and empty-state CTA. ## Derived UI Contract: System Run Detail - **Type**: Derived UI surface, not persisted - **Route**: `/system/ops/runs/{run}` - **Surface Type**: Detail-first operational surface - **Primary Question**: What happened on this operation, and what follow-up is appropriate? ### Contract Rules - Header actions remain the only triage location for retry, cancel, and mark investigated. - The detail surface exposes `Show all operations` as the canonical return path and keeps `Go to runbooks` available as secondary navigation. - `cancel` remains destructive and confirmation-gated. - `mark investigated` retains the `reason` validation rule: required, minimum 5 characters, maximum 500 characters. - No new page, modal surface, or alternate triage route is introduced. ## Persistence Impact - **Schema changes**: None - **Data migration**: None - **New indexes**: None - **Retention impact**: None