--- description: "Task list for feature 044 drift MVP" --- # Tasks: Drift MVP (044) **Input**: Design documents from `specs/044-drift-mvp/` **Prerequisites**: `plan.md` (required), `spec.md` (required), plus `research.md`, `data-model.md`, `contracts/`, `quickstart.md` **Tests**: REQUIRED (Pest) - feature introduces runtime behavior + new persistence. **Organization**: Tasks are grouped by user story (Scenario 1/2/3 in spec). ## Format: `[ID] [P?] [Story] Description` - **[P]**: Can run in parallel (different files, no dependencies) - **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3) - Include exact file paths in descriptions --- ## Phase 1: Setup (Shared Infrastructure) **Purpose**: Project wiring for Drift MVP. - [ ] T001 Create/update constitution gate checklist in `specs/044-drift-mvp/checklists/requirements.md` - [ ] T002 Confirm spec/plan artifacts are current in `specs/044-drift-mvp/{plan.md,spec.md,research.md,data-model.md,quickstart.md,contracts/admin-findings.openapi.yaml}` - [ ] T003 Add Drift landing page shell in `app/Filament/Pages/DriftLanding.php` - [ ] T004 [P] Add Finding resource shells in `app/Filament/Resources/FindingResource.php` and `app/Filament/Resources/FindingResource/Pages/` --- ## Phase 2: Foundational (Blocking Prerequisites) **Purpose**: Persistence + authorization + deterministic IDs that all stories depend on. **Checkpoint**: DB schema exists, tenant scoping enforced, and tests can create Finding rows. - [ ] T005 Create `findings` migration in `database/migrations/*_create_findings_table.php` with Finding fields aligned to `specs/044-drift-mvp/spec.md`: (tenant_id, finding_type, scope_key, baseline_run_id, current_run_id, subject_type, subject_external_id, severity, status, fingerprint unique, evidence_jsonb, acknowledged_at, acknowledged_by_user_id) - [ ] T006 Create `Finding` model in `app/Models/Finding.php` (casts for `evidence_jsonb`, enums/constants for `finding_type`/`severity`/`status`, `acknowledged_at` handling) - [ ] T007 [P] Add `FindingFactory` in `database/factories/FindingFactory.php` - [ ] T008 Ensure `InventorySyncRunFactory` exists (or add it) in `database/factories/InventorySyncRunFactory.php` - [ ] T009 Add authorization policy in `app/Policies/FindingPolicy.php` and wire it in `app/Providers/AuthServiceProvider.php` (or project equivalent) - [ ] T010 Add Drift permissions in `config/intune_permissions.php` (view + acknowledge) and wire them into Filament navigation/actions - [ ] T011 Enforce tenant scoping for Finding queries in `app/Models/Finding.php` and/or `app/Filament/Resources/FindingResource.php` - [ ] T012 Implement fingerprint helper in `app/Services/Drift/DriftHasher.php` (sha256 per spec) - [ ] T013 Pin `scope_key = InventorySyncRun.selection_hash` in `app/Services/Drift/DriftScopeKey.php` (single canonical definition) - [ ] T014 Implement evidence allowlist builder in `app/Services/Drift/DriftEvidence.php` (new file) --- ## Phase 3: User Story 1 - View drift summary (Priority: P1) MVP **Goal**: Opening Drift generates (async) and displays a summary of new drift findings for the latest scope. **Independent Test**: With 2 successful inventory runs for the same selection hash, opening Drift dispatches generation if missing and then shows summary counts. ### Tests (write first) - [ ] T015 [P] [US1] Baseline selection tests in `tests/Feature/Drift/DriftBaselineSelectionTest.php` - [ ] T016 [P] [US1] Generation dispatch tests in `tests/Feature/Drift/DriftGenerationDispatchTest.php` - [ ] T017 [P] [US1] Tenant isolation tests in `tests/Feature/Drift/DriftTenantIsolationTest.php` - [ ] T018 [P] [US1] Assignment drift detection test (targets + intent changes per FR2b) in `tests/Feature/Drift/DriftAssignmentDriftDetectionTest.php` ### Implementation - [ ] T019 [US1] Implement run selection service in `app/Services/Drift/DriftRunSelector.php` - [ ] T020 [US1] Implement generator job in `app/Jobs/GenerateDriftFindingsJob.php` (dedupe/lock by tenant+scope+baseline+current) - [ ] T021 [US1] Implement generator service in `app/Services/Drift/DriftFindingGenerator.php` (idempotent) - [ ] T022 [US1] Implement landing behavior (dispatch + status UI) in `app/Filament/Pages/DriftLanding.php` - [ ] T023 [US1] Implement summary queries/widgets in `app/Filament/Pages/DriftLanding.php` --- ## Phase 4: User Story 2 - Drill into a drift finding (Priority: P2) **Goal**: Admin can view a finding and see sanitized evidence + run references (DB-only label resolution). **Independent Test**: A persisted finding renders details without Graph calls. ### Tests (write first) - [ ] T024 [P] [US2] Finding detail test in `tests/Feature/Drift/DriftFindingDetailTest.php` - [ ] T025 [P] [US2] Evidence minimization test in `tests/Feature/Drift/DriftEvidenceMinimizationTest.php` ### Implementation - [ ] T026 [US2] Implement list UI in `app/Filament/Resources/FindingResource.php` (filters: status, scope_key, run) - [ ] T027 [US2] Implement detail UI in `app/Filament/Resources/FindingResource/Pages/ViewFinding.php` - [ ] T028 [US2] Implement DB-only name resolution in `app/Filament/Resources/FindingResource.php` (inventory/foundations caches) --- ## Phase 5: User Story 3 - Acknowledge/triage (Priority: P3) **Goal**: Admin can acknowledge findings; new lists hide acknowledged but records remain auditable. **Independent Test**: Acknowledging sets `acknowledged_at` + `acknowledged_by_user_id` and flips status. ### Tests (write first) - [ ] T029 [P] [US3] Acknowledge action test in `tests/Feature/Drift/DriftAcknowledgeTest.php` - [ ] T030 [P] [US3] Acknowledge authorization test in `tests/Feature/Drift/DriftAcknowledgeAuthorizationTest.php` ### Implementation - [ ] T031 [US3] Add acknowledge actions in `app/Filament/Resources/FindingResource.php` - [ ] T032 [US3] Implement `acknowledge()` domain method in `app/Models/Finding.php` - [ ] T033 [US3] Ensure Drift summary excludes acknowledged by default in `app/Filament/Pages/DriftLanding.php` --- ## Phase 6: Polish & Cross-Cutting Concerns - [ ] T034 Add DB indexes in `database/migrations/*_create_findings_table.php` (tenant_id+status, tenant_id+scope_key, tenant_id+baseline_run_id, tenant_id+current_run_id) - [ ] T035 [P] Add determinism test in `tests/Feature/Drift/DriftGenerationDeterminismTest.php` (same baseline/current => same fingerprints) - [ ] T036 Add job observability logs in `app/Jobs/GenerateDriftFindingsJob.php` (no secrets) - [ ] T037 Add idempotency/upsert strategy in `app/Services/Drift/DriftFindingGenerator.php` - [ ] T038 Ensure volatile fields excluded from hashing in `app/Services/Drift/DriftHasher.php` and cover in `tests/Feature/Drift/DriftHasherTest.php` - [ ] T039 Validate and update `specs/044-drift-mvp/quickstart.md` after implementation --- ## Dependencies & Execution Order - Setup (Phase 1) -> Foundational (Phase 2) -> US1 -> US2 -> US3 -> Polish ### Parallel execution examples - Foundational: T007, T008, T012, T013, T014 - US1 tests: T015, T016, T017, T018 - US2 tests: T024, T025 - US3 tests: T029, T030 --- ## Implementation Strategy ### MVP scope - MVP = Phase 1 + Phase 2 + US1. ### Format validation - All tasks use `- [ ] T###` format - Story tasks include `[US1]`/`[US2]`/`[US3]` - All tasks include file paths