---
description: "Task list for Spec 087 implementation"
---

# Tasks: Legacy Runs Removal (Spec 087)

**Input**: Design documents from `/specs/087-legacy-runs-removal/`

**Tests**: REQUIRED (Pest) because this feature changes runtime behavior.

---

## Phase 1: Setup (Docs + Local Validation)

- [X] T001 Validate and (if needed) update specs/087-legacy-runs-removal/quickstart.md with the exact focused test commands for this spec
- [X] T002 Capture the final run_type allow-list in specs/087-legacy-runs-removal/spec.md (FR-012) and ensure tasks below only create those values

---

## Phase 2: Foundational (Blocking Prerequisites)

**⚠️ CRITICAL**: Complete this phase before starting any user story work.

- [X] T003 Update canonical run type identifiers to underscore values for this feature only:
  - Update app/Support/OperationRunType.php (enum App\\Support\\OperationRunType) so new runs store the underscore identifiers from FR-012
  - Change ONLY the affected enum case values (leave unrelated run types unchanged):
    - InventorySync
    - DirectoryGroupsSync
    - DriftGenerate
    - BackupScheduleRunNow
    - BackupScheduleRetry
    - BackupScheduleScheduled
  - Scope note: OperationRun creation accepts a raw string type; enforcement is via standardized usage + tests in this spec (no global renames)
- [X] T004 Create migration database/migrations/2026_02_12_000001_canonicalize_operation_run_types.php to rewrite existing operation_runs.type values (dotted → underscore) for affected workflows (FR-012). Acceptance criteria: perform these rewrites (and only these):
  - inventory.sync → inventory_sync
  - directory_groups.sync → entra_group_sync
  - drift.generate → drift_generate_findings
  - backup_schedule.run_now → backup_schedule_run
  - backup_schedule.retry → backup_schedule_run
  - backup_schedule.scheduled → backup_schedule_run
- [X] T005 [P] Add/adjust OperationRun RBAC semantics tests (404 vs 403) in tests/Feature/Monitoring/MonitoringOperationsTest.php and/or tests/Feature/Operations/ (FR-008)
- [X] T006 [P] Add architecture guard test tests/Feature/Guards/NoLegacyRunsTest.php scanning app/, database/, resources/, routes/ for legacy run tokens (FR-009). Use this initial forbidden token list:
  - InventorySyncRun, inventory_sync_runs, InventorySyncRunResource
  - EntraGroupSyncRun, entra_group_sync_runs, EntraGroupSyncRunResource
  - BackupScheduleRun, backup_schedule_runs, BackupScheduleRunsRelationManager
  Exclusions (minimum): vendor/, storage/, specs/, spechistory/, references/, bootstrap/cache/
- [X] T007 [P] Remove legacy run badge domains/mappers and rely on OperationRun status/outcome badge domains by updating app/Support/Badges/BadgeDomain.php, app/Support/Badges/BadgeCatalog.php, and tests/Unit/Badges/RunStatusBadgesTest.php (BADGE-001)
- [X] T043 [P] Add explicit “no backfill of legacy run history” regression coverage:
  - Confirm no migration/job creates new operation_runs by reading legacy run tables (reference/FK backfills are allowed)
  - Add a focused test under tests/Feature/Guards/ or tests/Feature/Database/ to enforce this (FR-010)

NOTE: routes/web.php currently has a legacy convenience redirect (/admin/t/{tenant}/operations → /admin/operations). It is not a legacy *run page*; keep or change it explicitly as part of US2 decisions.

**Checkpoint**: Canonical run types are stable, guard exists, and operations RBAC semantics are enforced by tests.

---

## Phase 3: User Story 1 — Single canonical run history (Priority: P1) 🎯 MVP

**Goal**: New inventory sync, Entra group sync, and backup schedule executions produce exactly one canonical OperationRun each, visible in Operations UI.

**Independent Test**: Trigger each run type once and verify it appears in the Operations run list and can be opened in the canonical run viewer.

### Tests (write first)

- [X] T008 [P] [US1] Update inventory sync run creation expectations in tests/Feature/Inventory/InventorySyncServiceTest.php to assert an operation_runs row exists with type inventory_sync
- [X] T009 [P] [US1] Update Entra group sync expectations in tests/Feature/DirectoryGroups/StartSyncTest.php and tests/Feature/DirectoryGroups/ScheduledSyncDispatchTest.php to assert an operation_runs row exists with type entra_group_sync
- [X] T010 [P] [US1] Update backup schedule run expectations in tests/Feature/BackupScheduling/RunBackupScheduleJobTest.php to assert an operation_runs row exists with type backup_schedule_run
- [X] T011 [P] [US1] Add tests for retention + purge creating independent canonical runs in tests/Feature/BackupScheduling/ApplyRetentionJobTest.php and tests/Feature/Console/PurgeNonPersistentDataCommandTest.php (backup_schedule_retention / backup_schedule_purge)
- [X] T044 [P] [US1] Add/adjust backup schedule tests to cover skipped/canceled schedule runs still producing a canonical operation_run with a clear terminal outcome (spec Edge Case)

### Implementation

- [X] T012 [US1] Refactor app/Services/Inventory/InventorySyncService.php to stop creating InventorySyncRun rows and instead create/update a canonical OperationRun (FR-001/FR-002)
- [X] T013 [US1] Refactor app/Jobs/EntraGroupSyncJob.php to stop updating EntraGroupSyncRun and instead create/update a canonical OperationRun (FR-001/FR-002)
- [X] T014 [US1] Refactor app/Jobs/RunBackupScheduleJob.php to stop reading/updating BackupScheduleRun status as the canonical record and instead use a canonical OperationRun with schedule metadata stored in operation_runs.context (FR-001/FR-002)
- [X] T015 [US1] Refactor app/Jobs/ApplyBackupScheduleRetentionJob.php to remove BackupScheduleRun dependency and track retention via a canonical OperationRun (FR-006/FR-011)
- [X] T016 [US1] Refactor app/Console/Commands/TenantpilotPurgeNonPersistentData.php to track purge via a canonical OperationRun and remove BackupScheduleRun queries (FR-006/FR-011)
- [X] T017 [US1] Refactor app/Console/Commands/TenantpilotReconcileBackupScheduleOperationRuns.php to reconcile based on operation_runs only (remove BackupScheduleRun reads) (FR-001/FR-006)
- [X] T018 [US1] Update run status notifications/links to point to canonical run viewer by editing app/Notifications/RunStatusChangedNotification.php and app/Notifications/OperationRunQueued.php (FR-001)
- [X] T019 [US1] Update inventory run “last run” widget links to canonical runs by editing app/Filament/Widgets/Inventory/InventoryKpiHeader.php (FR-001)

**Checkpoint**: US1 tests pass and every new execution yields a canonical OperationRun of the correct underscore run_type.

---

## Phase 4: User Story 2 — Legacy run UI is intentionally gone (Priority: P1)

**Goal**: Legacy run pages/resources are removed; old links return 404; no legacy run resources appear in navigation.

**Independent Test**: Request known legacy run URLs and verify 404; verify navigation has no legacy run resources.

### Tests (write first)

- [X] T020 [P] [US2] Replace redirect-based legacy tests with 404 assertions in tests/Feature/Operations/LegacyRunRedirectTest.php (FR-004)
- [X] T021 [P] [US2] Add explicit “legacy run routes not found” coverage in tests/Feature/Operations/LegacyRunRoutesNotFoundTest.php for inventory/entra/backup schedule legacy run URLs (FR-004)

### Implementation

- [X] T022 [US2] Remove legacy Inventory Sync run Filament resource by deleting app/Filament/Resources/InventorySyncRunResource.php and app/Filament/Resources/InventorySyncRunResource/Pages/ (FR-003)
- [X] T023 [US2] Remove legacy Entra Group Sync run Filament resource by deleting app/Filament/Resources/EntraGroupSyncRunResource.php and app/Filament/Resources/EntraGroupSyncRunResource/Pages/ (FR-003)
- [X] T024 [US2] Remove legacy backup schedule run history relation manager by deleting app/Filament/Resources/BackupScheduleResource/RelationManagers/BackupScheduleRunsRelationManager.php (FR-003)
- [X] T025 [US2] Remove navigation links to legacy run resources by updating app/Filament/Resources/EntraGroupResource/Pages/ListEntraGroups.php and any other references found under app/Filament/ (FR-003)
- [X] T026 [US2] Remove legacy run UI tests and replace with canonical Operations coverage by updating/deleting tests/Feature/Filament/InventorySyncRunResourceTest.php, tests/Feature/Filament/EntraGroupSyncRunResourceTest.php, and tests/Feature/BackupScheduling/BackupScheduleRunViewModalTest.php (FR-003)
- [X] T027 [US2] Remove legacy run badge mappers now unused by UI by deleting app/Support/Inventory/InventorySyncStatusBadge.php and app/Support/Badges/Domains/EntraGroupSyncRunStatusBadge.php (FR-003/BADGE-001)

NOTE: Badge cleanup is handled by T007. If any legacy badge mapper is still referenced, remove it as part of T007 and treat this note as satisfied.

**Checkpoint**: Legacy run URLs are 404 (no redirects) and legacy run resources no longer exist.

---

## Phase 5: User Story 3 — Drift references canonical runs (Priority: P1)

**Goal**: Drift baseline/current/last-seen references use canonical OperationRuns; historical records without a safe mapping render without errors.

**Independent Test**: Generate drift findings and confirm baseline/current reference canonical run IDs; verify null-safe behavior when mapping is absent.

### Tests (write first)

- [X] T028 [P] [US3] Update drift baseline/current selection tests under tests/Feature/Drift/ (directory) to create OperationRun records instead of InventorySyncRun
- [X] T029 [P] [US3] Update RBAC drift landing UI enforcement in tests/Feature/Rbac/DriftLandingUiEnforcementTest.php to avoid InventorySyncRunResource and assert canonical run links

### Data model + migrations

- [X] T030 [US3] Create migration database/migrations/2026_02_12_000002_add_operation_run_ids_to_findings_table.php adding findings.baseline_operation_run_id and findings.current_operation_run_id (nullable FKs to operation_runs)
- [X] T031 [US3] Create migration database/migrations/2026_02_12_000003_backfill_findings_operation_run_ids.php that backfills the new findings columns by joining through inventory_sync_runs.operation_run_id (null-safe)
- [X] T032 [US3] Create migration database/migrations/2026_02_12_000004_backfill_inventory_items_last_seen_operation_run_id.php backfilling inventory_items.last_seen_operation_run_id from inventory_items.last_seen_run_id via inventory_sync_runs.operation_run_id

### Application changes

- [X] T033 [US3] Refactor drift run selection to use OperationRuns by updating app/Services/Drift/DriftRunSelector.php and app/Services/Drift/DriftScopeKey.php (FR-005)
- [X] T034 [US3] Refactor drift finding generation to accept/use OperationRuns by updating app/Services/Drift/DriftFindingGenerator.php (FR-005)
- [X] T035 [US3] Update drift landing UI to link to canonical OperationRuns (not legacy resources) by updating app/Filament/Pages/DriftLanding.php (FR-003/FR-005)

### Cutover + cleanup

- [X] T036 [US3] Create migration database/migrations/2026_02_12_000005_drop_legacy_run_id_columns_from_findings_and_inventory_items.php dropping findings.baseline_run_id/current_run_id and inventory_items.last_seen_run_id after code cutover (FR-005)

**Checkpoint**: Drift reads/writes canonical operation run references and remains functional with null mappings.

---

## Phase 6: Drop legacy tables (Data + Code)

**Purpose**: Remove legacy run storage permanently after all cutovers.

- [X] T037 Create migration database/migrations/2026_02_12_000006_drop_legacy_run_tables.php dropping inventory_sync_runs, entra_group_sync_runs, and backup_schedule_runs (FR-001)
- [X] T038 [P] Delete legacy run Eloquent models app/Models/InventorySyncRun.php, app/Models/EntraGroupSyncRun.php, and app/Models/BackupScheduleRun.php (FR-001)
- [X] T039 [P] Delete legacy factories database/factories/InventorySyncRunFactory.php and database/factories/EntraGroupSyncRunFactory.php and update any references in tests/Feature/ (FR-001)
- [X] T040 Update any remaining references to legacy run tables (tokens caught by the guard) under app/, database/, resources/, routes/ until tests/Feature/Guards/NoLegacyRunsTest.php passes (FR-009)

---

## Phase 7: Polish & Cross-Cutting Concerns

- [X] T041 Run formatting for touched files with vendor/bin/sail bin pint --dirty and fix any style issues in app/ and tests/
- [X] T042 Run focused test pack for this spec (at minimum): tests/Feature/Guards/NoLegacyRunsTest.php, tests/Feature/Operations/LegacyRunRoutesNotFoundTest.php, tests/Feature/Monitoring/MonitoringOperationsTest.php, tests/Feature/Drift/ (directory)

---

## Dependencies & Execution Order

### Story dependency graph

- Phase 2 blocks everything.
- US1 (canonical run creation) should land before US2 (removing UI) to avoid removing the only user-visible run history.
- US3 (drift cutover) can proceed after Phase 2, but MUST complete before Phase 6 (dropping legacy tables).

### Parallel opportunities (examples)

- After Phase 2:
  - US1 implementation tasks in app/Services/Inventory/InventorySyncService.php and app/Jobs/EntraGroupSyncJob.php can be done in parallel.
  - US2 removal tasks (Filament resource deletion) can proceed in parallel with US3 migrations/code, as long as any shared files are coordinated.

## Implementation Strategy (MVP)

- MVP = Phase 2 + US1 + the minimum of US2 needed to remove navigation entry points.
- Then complete US3 cutover and only then drop legacy tables.
