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

# Tasks: Drift Golden Master Cutover (Baseline Compare) (Spec 119)

**Input**: Design documents from `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/119-baseline-drift-engine/`
**Prerequisites**:
- `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/119-baseline-drift-engine/plan.md` (required)
- `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/119-baseline-drift-engine/spec.md` (required)
- `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/119-baseline-drift-engine/research.md`
- `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/119-baseline-drift-engine/data-model.md`
- `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/119-baseline-drift-engine/contracts/drift.openapi.yaml`
- `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/119-baseline-drift-engine/quickstart.md`

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

**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.

---

## Phase 1: Setup (Shared Infrastructure)

**Purpose**: Local readiness + baseline validation before changing runtime behavior

- [X] T001 Start local stack and run migrations using `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/vendor/bin/sail` (up -d, artisan migrate)
- [X] T002 Run a baseline test subset using `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/vendor/bin/sail` to confirm a green starting point (artisan test --compact --filter=BaselineCompare)

---

## Phase 2: Foundational (Blocking Prerequisites)

**Purpose**: Shared building blocks used across user stories (evidence contract + resolvers)

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

- [X] T003 Create baseline policy-version resolver in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Services/Baselines/Evidence/BaselinePolicyVersionResolver.php` (resolve baseline `policy_version_id` deterministically from baseline snapshot item identity `policy_type` + `subject_key` and baseline evidence provenance `observed_at`; return null when no match)
- [X] T004 [P] Add resolver unit tests in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Unit/Baselines/BaselinePolicyVersionResolverTest.php` (covers: found, not found, invalid observed_at, deterministic tie-breaker when multiple candidates exist)
- [X] T005 [P] Add drift evidence contract assertion helper in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Support/AssertsDriftEvidenceContract.php` (required keys, allowed `summary.kind`, provenance keys, fidelity algorithm, and diff-renderability rule)

**Checkpoint**: Contract helper + resolver exist; US1 tests can be written against them.

---

## Phase 3: User Story 1 — Understand drift with consistent diffs (Priority: P1) 🎯 MVP

**Goal**: Baseline Compare drift findings carry diff-compatible evidence so operators get consistent diffs when content evidence exists, and a clear “diff unavailable” explanation when it does not.

**Independent Test**: Run Baseline Compare to produce (a) a `different_version` drift finding with both refs, (b) a `missing_policy` or `unexpected_policy` finding with a single required ref, and (c) a meta-only finding, then verify the finding detail view renders the correct diff or an explicit “diff unavailable” explanation.

### Tests for User Story 1 (write first) ⚠️

- [X] T006 [P] [US1] Add Baseline Compare evidence-contract tests in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Baselines/BaselineCompareDriftEvidenceContractTest.php` (different_version + missing_policy; asserts `source`, `change_type` semantics unchanged, `summary.kind`, baseline/current `policy_version_id`, fidelity algorithm, and `evidence_jsonb.provenance.*` keys including `compare_operation_run_id`)
- [X] T007 [P] [US1] Add FindingResource “diff unavailable” regression test in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Drift/DriftFindingDiffUnavailableTest.php` (missing baseline/current refs → explicit message)
- [X] T008 [P] [US1] Update Baseline Compare findings tests for new evidence shape in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Baselines/BaselineCompareFindingsTest.php` (replace `current_hash`/`baseline_hash` assertions with nested baseline/current evidence + `summary.kind`)

### Implementation for User Story 1

- [X] T009 [US1] Upgrade Baseline Compare drift evidence schema in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CompareBaselineToTenantJob.php` (write `evidence_jsonb.summary.kind`, `evidence_jsonb.baseline.policy_version_id`, `evidence_jsonb.current.policy_version_id`, compute `evidence_jsonb.fidelity`, and write `evidence_jsonb.provenance.{baseline_profile_id,baseline_snapshot_id,compare_operation_run_id,inventory_sync_run_id}`)
- [X] T010 [US1] Populate `evidence_jsonb.current.policy_version_id` from content evidence meta in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CompareBaselineToTenantJob.php` (use `ResolvedEvidence.meta.policy_version_id` when available; else null)
- [X] T011 [US1] Populate `evidence_jsonb.baseline.policy_version_id` via `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Services/Baselines/Evidence/BaselinePolicyVersionResolver.php` and integrate into `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CompareBaselineToTenantJob.php` (when baseline snapshot provenance indicates content evidence + has `observed_at`, attempt resolve; otherwise null)
- [X] T012 [US1] Implement `summary.kind` selection in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CompareBaselineToTenantJob.php` by “stealing” dimension detection logic from `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Services/Drift/DriftFindingGenerator.php` (prefer settings snapshot changes; else assignments; else scope tags; fallback policy_snapshot)
- [X] T013 [US1] Ensure `findings.evidence_fidelity` and `evidence_jsonb.fidelity` stay aligned in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CompareBaselineToTenantJob.php` (compute deterministically from policy-version refs: both present = `content`, exactly one = `mixed`, none = `meta`)
- [X] T014 [US1] Enforce diff-renderability rule in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Filament/Resources/FindingResource.php` (`different_version` requires both refs; `missing_policy`/`unexpected_policy` render against an empty side when their single required ref exists; otherwise show explicit “diff unavailable” explanation in the Diff section)
- [X] T015 [US1] Run US1-focused tests via `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/vendor/bin/sail` (artisan test --compact --filter=BaselineCompareDriftEvidenceContract; artisan test --compact --filter=DriftFindingDiffUnavailable)

**Checkpoint**: Baseline Compare findings show consistent diffs for content evidence; meta-only shows “diff unavailable” without errors.

---

## Phase 4: User Story 2 — Eliminate “two truths” for drift (Priority: P2)

**Goal**: Operators only see Baseline Compare as the drift engine; no legacy “Generate drift” UI or source switching remains.

**Independent Test**: After the cutover, verify all drift findings shown in the UI are Baseline Compare-origin and no UI surface offers a legacy “Generate drift” action or “source” switching.

### Tests for User Story 2 (write first) ⚠️

- [X] T016 [P] [US2] Remove/replace DriftLanding enforcement tests in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Rbac/DriftLandingUiEnforcementTest.php` (assert drift entry point is Baseline Compare landing instead)

### Implementation for User Story 2

- [X] T017 [US2] Remove legacy Drift landing surface by deleting `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Filament/Pages/DriftLanding.php` and `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/resources/views/filament/pages/drift-landing.blade.php`
- [X] T018 [US2] Update related-run links to point drift to Baseline Compare landing in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Support/OperationRunLinks.php` (remove DriftLanding import; add BaselineCompareLanding link for baseline_compare runs)
- [X] T019 [US2] Update dashboard attention widget to use Baseline Compare runs (not drift_generate) in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Filament/Widgets/Dashboard/NeedsAttention.php` (stale/failed checks + URLs → Baseline Compare landing / Operations)
- [X] T020 [US2] Remove DriftLanding action-surface exemption in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Support/Ui/ActionSurface/ActionSurfaceExemptions.php`
- [X] T021 [US2] Update Filament auth allowlist to remove DriftLanding in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Guards/NoAdHocFilamentAuthPatternsTest.php`
- [X] T022 [US2] Run US2-focused tests via `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/vendor/bin/sail` (artisan test --compact --filter=BaselineCompareLanding; artisan test --compact --filter=NeedsAttention)

**Checkpoint**: No DriftLanding surface exists; “Drift” entry point routes to Baseline Compare landing.

---

## Phase 5: User Story 3 — Clean cutover & legacy removal (Priority: P3)

**Goal**: Hard cut: legacy run-to-run drift generator is removed end-to-end and legacy drift findings are deleted so operators never encounter mixed states.

**Independent Test**: After deployment and the one-time cleanup step, verify legacy drift findings no longer exist, legacy drift generation cannot be started, and Baseline Compare drift continues to work.

### Tests for User Story 3 (write first) ⚠️

- [X] T023 [P] [US3] Add cleanup migration test in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Drift/LegacyDriftFindingsCleanupMigrationTest.php` (deletes `finding_type=drift` where `source` is null or != baseline.compare; keeps baseline.compare)
- [X] T024 [P] [US3] Update alert + monitoring tests to remove drift_generate_findings references in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Alerts/BaselineCompareFailedAlertTest.php` and `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/RunAuthorizationTenantIsolationTest.php`
- [X] T025 [P] [US3] Remove legacy drift generator tests tied to DriftLanding/GenerateDriftFindingsJob/DriftFindingGenerator in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Drift/` (delete or rewrite: DriftGenerationDispatchTest.php, DriftLandingCopyTest.php, DriftLandingShowsComparisonInfoTest.php, GenerateDriftFindingsJobNotificationTest.php, Drift*DriftDetectionTest.php, DriftGenerationDeterminismTest.php, DriftTenantIsolationTest.php)

### Implementation for User Story 3

- [X] T026 [US3] Delete legacy drift generation runtime code: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/GenerateDriftFindingsJob.php`, `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Services/Drift/DriftFindingGenerator.php`, `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Services/Drift/DriftRunSelector.php`, `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Services/Drift/DriftScopeKey.php`
- [X] T027 [US3] Remove legacy drift operation type from catalogs + triage: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Support/OperationRunType.php`, `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Support/OperationCatalog.php`, `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Services/SystemConsole/OperationRunTriageService.php` (no drift_generate_findings label/duration/retry/cancel)
- [X] T028 [US3] Remove legacy drift-generate alert event producer in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/Alerts/EvaluateAlertsJob.php` (drop compareFailedEvents() and its call site)
- [X] T029 [US3] Add one-time cleanup migration in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/database/migrations/2026_03_05_000001_delete_legacy_drift_findings.php` (delete `finding_type=drift` where `source` is null or <> baseline.compare)
- [X] T030 [US3] Remove remaining legacy drift references discovered by search in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/` and `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/resources/` (target: no DriftLanding / drift_generate_findings strings outside historical migrations/specs; explicitly audit Findings UI for legacy-source badges/filters/labels or “source switching” states)
- [X] T031 [US3] Run US3-focused tests via `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/vendor/bin/sail` (artisan test --compact --filter=Alerts; artisan test --compact --filter=OperationRun; artisan test --compact --filter=Drift)

**Checkpoint**: Legacy generator is gone; DB cleanup migration removes legacy drift findings; all tests green.

---

## Phase N: Polish & Cross-Cutting Concerns

**Purpose**: Final quality pass across all user stories

- [X] T032 [P] Format changed files using `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/vendor/bin/sail` (php vendor/bin/pint)
- [X] T033 Run full test suite using `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/vendor/bin/sail` (artisan test)
- [X] T034 [P] Validate manual smoke steps remain accurate in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/119-baseline-drift-engine/quickstart.md` (update only if behavior/screens changed)
- [X] T035 [P] Update Spec 119 docs for one-sided drift diff rendering in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/119-baseline-drift-engine/` (spec, plan, research, data-model, quickstart)
- [X] T036 [US1] Extend `FindingResource` one-sided diff rendering in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Filament/Resources/FindingResource.php` (`unexpected_policy` => added against empty baseline, `missing_policy` => removed against empty current)
- [X] T037 [P] Extend drift view regressions in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Drift/DriftFindingDiffUnavailableTest.php` (cover one-sided empty-side rendering and explicit unavailable messaging)
- [X] T038 [US1] Scope baseline snapshot capture to the latest completed Inventory Sync in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CaptureBaselineSnapshotJob.php` (ignore stale `inventory_items` rows from older sync runs when deriving subject-key matches; record `baseline_capture.inventory_sync_run_id` for operability)
- [X] T039 [P] Add baseline-capture stale-inventory regression coverage in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Baselines/BaselineCaptureAmbiguousMatchGapTest.php` (duplicates in the same latest sync still gap; stale duplicates from older syncs no longer do)
- [X] T040 [P] Update Spec 119 docs for baseline-capture latest-sync scoping in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/119-baseline-drift-engine/` (spec, plan, research, data-model, quickstart)
- [X] T041 [US1] Reuse same-run full-content capture evidence in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CompareBaselineToTenantJob.php` (overlay compare-time captured/reused `policy_versions` before the `since`-based resolver so unchanged policies do not become `missing_current`)
- [X] T042 [P] Add full-content compare reuse regression in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Baselines/BaselineCompareWhyNoFindingsReasonCodeTest.php` (reused identical compare-purpose version still yields `no_drift_detected`, not `evidence_capture_incomplete`)
- [X] T043 [P] Update Spec 119 docs for reused compare-evidence handling in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/119-baseline-drift-engine/` (spec, plan, research, quickstart)
- [X] T044 [US1] Scope Baseline Compare landing duplicate-name warnings to the latest completed Inventory Sync in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Support/Baselines/BaselineCompareStats.php` (historical stale duplicates must not keep the warning banner visible)
- [X] T045 [P] Add landing-page stale-duplicate regression in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Filament/BaselineCompareLandingDuplicateNamesBannerTest.php` (latest sync clean ⇒ no warning, latest sync duplicate ⇒ warning remains)
- [X] T046 [P] Update Spec 119 docs for landing-page duplicate warning scoping in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/119-baseline-drift-engine/` (spec, research)
- [X] T047 [US1] Canonicalize compliance `scheduledActionsForRule` in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Services/Intune/CompliancePolicyNormalizer.php` (include semantic noncompliance action fields in the drift signal; ignore opaque IDs/order-only noise)
- [X] T048 [P] Add unit coverage for canonical compliance action drift normalization in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Unit/CompliancePolicyNormalizerTest.php` (grace-period/template signal, stable ordering, ignored internal IDs)
- [X] T049 [US1] Recompute effective baseline content hashes from resolved baseline `policy_versions` in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CompareBaselineToTenantJob.php` (keep existing content-backed baseline snapshots comparable when drift-signal semantics expand)
- [X] T050 [P] Add compare regressions + docs for compliance noncompliance action drift in `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/BaselineDriftEngine/ComplianceNoncomplianceActionsDriftTest.php` and `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/119-baseline-drift-engine/` (unchanged legacy-hash snapshot stays quiet; changed grace/action semantics create drift)

---

## Dependencies & Execution Order

### Phase Dependencies

- **Setup (Phase 1)**: No dependencies - can start immediately
- **Foundational (Phase 2)**: Depends on Setup completion - BLOCKS all user stories
- **User Stories (Phase 3+)**: All depend on Foundational phase completion
  - Stories can proceed in priority order (P1 → P2 → P3)
  - Or in parallel after Phase 2 if staffed (be mindful of overlapping files)
- **Polish (Final Phase)**: Depends on all desired user stories being complete

### User Story Dependencies

- **US1 (P1)**: No dependencies after Phase 2; delivers the MVP (diff-compatible evidence + diff guardrails)
- **US2 (P2)**: Depends on US1 being stable in UI terms (so removing DriftLanding doesn’t remove drift visibility)
- **US3 (P3)**: Can start after Phase 2, but recommended after US1/US2 so the cutover is clean and operators still have a drift workflow

### Parallel Opportunities (examples)

- Tests marked `[P]` can be written in parallel with implementation (and should fail before the fix lands).
- Deletions of legacy drift files in US3 can be parallelized with catalog/triage cleanup (different files).

---

## Parallel Example: US1

```bash
# In parallel (different files):
Task: "Add Baseline Compare evidence-contract tests in /Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Baselines/BaselineCompareDriftEvidenceContractTest.php"
Task: "Implement evidence schema upgrade in /Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CompareBaselineToTenantJob.php"
Task: "Add diff-unavailable regression test in /Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Drift/DriftFindingDiffUnavailableTest.php"
```

---

## Parallel Example: US2

```bash
# In parallel (different files):
Task: "Delete Drift landing surface in /Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Filament/Pages/DriftLanding.php"
Task: "Update dashboard widget links in /Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Filament/Widgets/Dashboard/NeedsAttention.php"
Task: "Update run links in /Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Support/OperationRunLinks.php"
```

---

## Parallel Example: US3

```bash
# In parallel (different files):
Task: "Add cleanup migration in /Users/ahmeddarrazi/Documents/projects/TenantAtlas/database/migrations/2026_03_05_000001_delete_legacy_drift_findings.php"
Task: "Remove legacy drift code in /Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/GenerateDriftFindingsJob.php"
Task: "Update triage/catalog in /Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Support/OperationCatalog.php"
```

---

## Implementation Strategy

### MVP First (User Story 1 Only)

1. Complete Phase 1: Setup
2. Complete Phase 2: Foundational (CRITICAL - blocks all stories)
3. Complete Phase 3: User Story 1
4. **STOP and VALIDATE**: Test User Story 1 independently
5. Deploy/demo if ready

### Incremental Delivery

1. Complete Setup + Foundational → Foundation ready
2. Add User Story 1 → Test independently → Deploy/Demo (MVP!)
3. Add User Story 2 → Test independently → Deploy/Demo
4. Add User Story 3 → Test independently → Deploy/Demo
5. Each story adds value without breaking previous stories

---

## Notes

- `[P]` tasks = different files, no dependencies
- `[US#]` label maps task to specific user story for traceability
- Each user story should be independently completable and testable
- Prefer Sail for all local commands: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/vendor/bin/sail`
