- Enrich drift findings evidence_jsonb for diff UX (summary.kind, refs, fidelity, provenance) - Add baseline policy version resolver and contract asserts - Remove legacy drift generator + DriftLanding surfaces - Add one-time cleanup migration for legacy drift findings - Scope baseline capture/landing warnings to latest inventory sync - Canonicalize compliance scheduledActionsForRule drift signal
21 KiB
| 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
- T001 Start local stack and run migrations using
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/vendor/bin/sail(up -d, artisan migrate) - T002 Run a baseline test subset using
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/vendor/bin/sailto 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.
- T003 Create baseline policy-version resolver in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Services/Baselines/Evidence/BaselinePolicyVersionResolver.php(resolve baselinepolicy_version_iddeterministically from baseline snapshot item identitypolicy_type+subject_keyand baseline evidence provenanceobserved_at; return null when no match) - 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) - T005 [P] Add drift evidence contract assertion helper in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Support/AssertsDriftEvidenceContract.php(required keys, allowedsummary.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) ⚠️
- T006 [P] [US1] Add Baseline Compare evidence-contract tests in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Baselines/BaselineCompareDriftEvidenceContractTest.php(different_version + missing_policy; assertssource,change_typesemantics unchanged,summary.kind, baseline/currentpolicy_version_id, fidelity algorithm, andevidence_jsonb.provenance.*keys includingcompare_operation_run_id) - 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) - T008 [P] [US1] Update Baseline Compare findings tests for new evidence shape in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Baselines/BaselineCompareFindingsTest.php(replacecurrent_hash/baseline_hashassertions with nested baseline/current evidence +summary.kind)
Implementation for User Story 1
- T009 [US1] Upgrade Baseline Compare drift evidence schema in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CompareBaselineToTenantJob.php(writeevidence_jsonb.summary.kind,evidence_jsonb.baseline.policy_version_id,evidence_jsonb.current.policy_version_id, computeevidence_jsonb.fidelity, and writeevidence_jsonb.provenance.{baseline_profile_id,baseline_snapshot_id,compare_operation_run_id,inventory_sync_run_id}) - T010 [US1] Populate
evidence_jsonb.current.policy_version_idfrom content evidence meta in/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CompareBaselineToTenantJob.php(useResolvedEvidence.meta.policy_version_idwhen available; else null) - T011 [US1] Populate
evidence_jsonb.baseline.policy_version_idvia/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Services/Baselines/Evidence/BaselinePolicyVersionResolver.phpand integrate into/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CompareBaselineToTenantJob.php(when baseline snapshot provenance indicates content evidence + hasobserved_at, attempt resolve; otherwise null) - T012 [US1] Implement
summary.kindselection in/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CompareBaselineToTenantJob.phpby “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) - T013 [US1] Ensure
findings.evidence_fidelityandevidence_jsonb.fidelitystay 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) - T014 [US1] Enforce diff-renderability rule in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Filament/Resources/FindingResource.php(different_versionrequires both refs;missing_policy/unexpected_policyrender against an empty side when their single required ref exists; otherwise show explicit “diff unavailable” explanation in the Diff section) - 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) ⚠️
- 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
- T017 [US2] Remove legacy Drift landing surface by deleting
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Filament/Pages/DriftLanding.phpand/Users/ahmeddarrazi/Documents/projects/TenantAtlas/resources/views/filament/pages/drift-landing.blade.php - 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) - 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) - T020 [US2] Remove DriftLanding action-surface exemption in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Support/Ui/ActionSurface/ActionSurfaceExemptions.php - T021 [US2] Update Filament auth allowlist to remove DriftLanding in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Guards/NoAdHocFilamentAuthPatternsTest.php - 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) ⚠️
- T023 [P] [US3] Add cleanup migration test in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Drift/LegacyDriftFindingsCleanupMigrationTest.php(deletesfinding_type=driftwheresourceis null or != baseline.compare; keeps baseline.compare) - T024 [P] [US3] Update alert + monitoring tests to remove drift_generate_findings references in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/Alerts/BaselineCompareFailedAlertTest.phpand/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/RunAuthorizationTenantIsolationTest.php - 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
- 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 - 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) - 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) - T029 [US3] Add one-time cleanup migration in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/database/migrations/2026_03_05_000001_delete_legacy_drift_findings.php(deletefinding_type=driftwheresourceis null or <> baseline.compare) - 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) - 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
- T032 [P] Format changed files using
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/vendor/bin/sail(php vendor/bin/pint) - T033 Run full test suite using
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/vendor/bin/sail(artisan test) - 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) - 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) - T036 [US1] Extend
FindingResourceone-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) - 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) - T038 [US1] Scope baseline snapshot capture to the latest completed Inventory Sync in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CaptureBaselineSnapshotJob.php(ignore staleinventory_itemsrows from older sync runs when deriving subject-key matches; recordbaseline_capture.inventory_sync_run_idfor operability) - 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) - 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) - T041 [US1] Reuse same-run full-content capture evidence in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CompareBaselineToTenantJob.php(overlay compare-time captured/reusedpolicy_versionsbefore thesince-based resolver so unchanged policies do not becomemissing_current) - 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 yieldsno_drift_detected, notevidence_capture_incomplete) - 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) - 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) - 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) - 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) - T047 [US1] Canonicalize compliance
scheduledActionsForRulein/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) - 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) - T049 [US1] Recompute effective baseline content hashes from resolved baseline
policy_versionsin/Users/ahmeddarrazi/Documents/projects/TenantAtlas/app/Jobs/CompareBaselineToTenantJob.php(keep existing content-backed baseline snapshots comparable when drift-signal semantics expand) - T050 [P] Add compare regressions + docs for compliance noncompliance action drift in
/Users/ahmeddarrazi/Documents/projects/TenantAtlas/tests/Feature/BaselineDriftEngine/ComplianceNoncomplianceActionsDriftTest.phpand/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
# 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
# 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
# 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)
- Complete Phase 1: Setup
- Complete Phase 2: Foundational (CRITICAL - blocks all stories)
- Complete Phase 3: User Story 1
- STOP and VALIDATE: Test User Story 1 independently
- Deploy/demo if ready
Incremental Delivery
- Complete Setup + Foundational → Foundation ready
- Add User Story 1 → Test independently → Deploy/Demo (MVP!)
- Add User Story 2 → Test independently → Deploy/Demo
- Add User Story 3 → Test independently → Deploy/Demo
- 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