# Phase 1 — Data Model: Legacy Runs Removal (Spec 087) **Branch**: `087-legacy-runs-removal` **Date**: 2026-02-12 ## Canonical Entity: OperationRun **Table**: `operation_runs` **Model**: `App\\Models\\OperationRun` Key fields (existing): - `id` - `workspace_id` (required) - `tenant_id` (nullable; tenant-scoped runs use this) - `user_id` (nullable) - `initiator_name` - `type` (canonical run_type) - `status` / `outcome` - `run_identity_hash` (idempotency) - `summary_counts` (JSON) - `failure_summary` (JSON) - `context` (JSON) - `started_at` / `completed_at` - `created_at` / `updated_at` Spec impact: - `type` must be standardized to the underscore identifiers listed in FR-012. ## Legacy Entities (To Remove) ### InventorySyncRun **Table**: `inventory_sync_runs` **Model**: `App\\Models\\InventorySyncRun` Notes: - Acts as a legacy duplicate run store. - Has `operation_run_id` bridge column (added later). **Plan**: remove model + table, and rely on `operation_runs`. ### EntraGroupSyncRun **Table**: `entra_group_sync_runs` **Model**: `App\\Models\\EntraGroupSyncRun` Notes: - Legacy duplicate run store. - Has `operation_run_id` bridge column. **Plan**: remove model + table, and rely on `operation_runs`. ### BackupScheduleRun **Table**: `backup_schedule_runs` **Model**: `App\\Models\\BackupScheduleRun` Notes: - Currently used for schedule run history + retention/purge selection. - Has `operation_run_id` bridge column. **Plan**: remove model + table and replace schedule “run history” with querying `operation_runs` by type + context. ## Drift Findings: References Must Become Canonical **Table**: `findings` **Model**: `App\\Models\\Finding` Current fields (relevant): - `baseline_run_id` → FK to `inventory_sync_runs` (nullable) - `current_run_id` → FK to `inventory_sync_runs` (nullable) **Planned fields**: - `baseline_operation_run_id` → FK to `operation_runs` (nullable) - `current_operation_run_id` → FK to `operation_runs` (nullable) **Backfill rule**: - If `baseline_run_id` points to an `inventory_sync_runs` row with a non-null `operation_run_id`, and that `operation_runs` row exists, copy it. - Same for `current_run_id`. - Otherwise leave null (matches spec edge-case expectations). ## Inventory Items: Last Seen Run Reference Must Become Canonical **Table**: `inventory_items` **Model**: `App\\Models\\InventoryItem` Current fields (relevant): - `last_seen_run_id` → FK to `inventory_sync_runs` (nullable) - `last_seen_operation_run_id` → FK to `operation_runs` (nullable; already exists) **Plan**: - Backfill `last_seen_operation_run_id` via `inventory_sync_runs.operation_run_id` where possible. - Drop `last_seen_run_id` after code is migrated. ## Backup Schedules: Run History **Table**: `backup_schedules` **Model**: `App\\Models\\BackupSchedule` Planned behavior: - Remove `runs()` relationship that points to `backup_schedule_runs`. - For UI/history, query `operation_runs` using: - `type = backup_schedule_run|backup_schedule_retention|backup_schedule_purge` - `context->backup_schedule_id = {id}` (and optionally scheduled time metadata) ## Validation Rules (from spec) - All new run records created by this feature must have `type` in the FR-012 allow-list. - Run visibility is workspace-scoped; non-members must be deny-as-not-found (404).