# 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).
