# Tasks: Provider-Missing Policy Visibility & Restore Continuity v1 **Input**: Design documents from `/specs/261-provider-missing-policy-visibility/` **Prerequisites**: `plan.md`, `spec.md`, `research.md`, `data-model.md`, `quickstart.md`, `contracts/provider-missing-policy-visibility.openapi.yaml` **Tests (TEST-GOV-001)**: REQUIRED (Pest). Keep proof in the targeted `fast-feedback` and `confidence` feature/unit lanes already named in `specs/261-provider-missing-policy-visibility/plan.md` and `specs/261-provider-missing-policy-visibility/quickstart.md`. Prefer focused coverage in `apps/platform/tests/Feature/Jobs/PolicySyncProviderMissingSemanticsTest.php`, `apps/platform/tests/Feature/Jobs/PolicySyncIgnoredRevivalTest.php`, `apps/platform/tests/Feature/PolicySyncServiceTest.php`, `apps/platform/tests/Feature/PolicySyncStartSurfaceTest.php`, `apps/platform/tests/Feature/Filament/PolicyProviderMissingUiTest.php`, `apps/platform/tests/Feature/BulkDeletePoliciesTest.php`, `apps/platform/tests/Feature/BulkUnignorePoliciesTest.php`, `apps/platform/tests/Feature/BulkExportToBackupTest.php`, `apps/platform/tests/Feature/Filament/BackupCreationTest.php`, `apps/platform/tests/Feature/Filament/BackupSetPolicyPickerTableTest.php`, `apps/platform/tests/Feature/Filament/RestoreItemSelectionTest.php`, and `apps/platform/tests/Unit/Badges/PolicyBadgesTest.php`. Do not add browser or heavy-governance coverage for this slice. **Operations**: No new `OperationRun` family is introduced. Existing policy sync and current backup/export surfaces keep their shared start UX only when an action is still allowed. Provider-missing current backup/export blocks must stop before run creation and explain why locally. **RBAC**: Preserve current workspace/tenant deny-as-not-found `404` boundaries, retain `403` for in-scope capability failures on existing policy, backup, and restore actions, and do not introduce new capability strings or role checks. **UI / Surface Guardrails**: This is `review-mandatory` work across native Filament policy, backup, and restore surfaces. Keep `standard-native-filament` relief for the policy and backup screens and `shared-detail-family` proof for restore continuity. Explicitly prove one dominant next action per changed surface, diagnostics-secondary ordering, hidden or capability-gated support detail, and no duplicate visible decision summary. Do not add a new page, diagnostics shell, panel, or asset. **Filament UI Action Surfaces**: No new Filament Resource, Page, RelationManager, panel, or provider work is introduced. `apps/platform/app/Filament/Resources/PolicyResource.php`, `apps/platform/app/Filament/Resources/BackupSetResource.php`, and `apps/platform/app/Filament/Resources/RestoreRunResource.php` remain the only affected operator-facing surfaces. **Organization**: Tasks are grouped by user story so each slice stays independently verifiable. Recommended delivery order is Phase 1 -> Phase 2 -> `US1` -> `US2` -> `US3` -> final polish and validation because provider-presence truth must exist before backup/restore and audit behavior can be finished safely. ## Test Governance Checklist - [x] Lane assignment stays `fast-feedback` plus `confidence` and remains the narrowest sufficient proof for the changed behavior. - [x] New or changed tests stay in focused `Feature` and `Unit` files only; no browser or heavy-governance family is added. - [x] Shared helpers, factories, seeds, fixtures, and support defaults remain cheap by default. - [x] Planned validation commands stay limited to the targeted Sail test commands already captured in `specs/261-provider-missing-policy-visibility/plan.md` and `specs/261-provider-missing-policy-visibility/quickstart.md`. - [x] The declared surface test profile stays `standard-native-filament` plus `shared-detail-family` where restore continuity needs explicit proof. - [x] Any follow-up or wording note resolves in this feature as `document-in-feature` or `follow-up-spec`, not as implicit scope creep. ## Phase 1: Setup (Shared Inventory) **Purpose**: Lock the concrete source seams and narrow proof commands before implementation starts. - [x] T001 [P] Verify the source-truth inventory across `apps/platform/app/Models/Policy.php`, `apps/platform/app/Services/Intune/PolicySyncService.php`, `apps/platform/app/Services/Intune/BackupService.php`, `apps/platform/app/Filament/Resources/PolicyResource.php`, `apps/platform/app/Filament/Resources/BackupSetResource.php`, `apps/platform/app/Filament/Resources/RestoreRunResource.php`, and `apps/platform/app/Jobs/Operations/PolicyBulkDeleteWorkerJob.php` - [x] T002 [P] Verify the focused validation commands and proof lanes in `specs/261-provider-missing-policy-visibility/plan.md` and `specs/261-provider-missing-policy-visibility/quickstart.md` - [x] T003 [P] Verify the badge and audit seams across `apps/platform/tests/Unit/Badges/PolicyBadgesTest.php`, `apps/platform/app/Support/Audit/AuditActionId.php`, and the current policy sync test family **Checkpoint**: The narrow seam inventory and proving commands are locked before runtime code changes begin. --- ## Phase 2: Foundational (Blocking Proof Anchors) **Purpose**: Make the failing proof and shared state vocabulary explicit before touching shared runtime truth. **CRITICAL**: No user story work should begin until this phase is complete. - [x] T004 [P] Lock sync-state proof across `apps/platform/tests/Feature/Jobs/PolicySyncProviderMissingSemanticsTest.php`, `apps/platform/tests/Feature/Jobs/PolicySyncIgnoredRevivalTest.php`, `apps/platform/tests/Feature/PolicySyncServiceTest.php`, `apps/platform/tests/Feature/PolicySyncEnrollmentConfigurationTypeCollisionTest.php`, and `apps/platform/tests/Feature/Jobs/AppProtectionPolicySyncFilteringTest.php` - [x] T005 [P] Lock policy-surface and badge proof across `apps/platform/tests/Feature/Filament/PolicyProviderMissingUiTest.php`, `apps/platform/tests/Feature/PolicyGeneralViewTest.php`, and `apps/platform/tests/Unit/Badges/PolicyBadgesTest.php`, including one dominant next action, diagnostics-secondary ordering, and no duplicate visible decision summary - [x] T006 [P] Lock current-backup and restore-continuity proof across `apps/platform/tests/Feature/BulkExportToBackupTest.php`, `apps/platform/tests/Feature/Filament/BackupCreationTest.php`, `apps/platform/tests/Feature/Filament/BackupSetPolicyPickerTableTest.php`, `apps/platform/tests/Feature/Filament/RestoreItemSelectionTest.php`, and `apps/platform/tests/Feature/RestoreUnknownPolicyTypeSafetyTest.php` **Checkpoint**: Failing proof files and state-vocabulary expectations are explicit and ready for bounded implementation work. --- ## Phase 3: User Story 1 - Distinguish provider missing from local ignore (Priority: P1) 🎯 MVP **Goal**: Make policy sync and policy surfaces tell the truth about provider-missing versus locally ignored state. **Independent Test**: Sync a previously observed policy out of the supported provider result set while keeping another policy locally ignored, then verify policy list/detail surfaces show distinct states and sync no longer auto-clears local ignore. ### Tests for User Story 1 - [x] T007 [P] [US1] Add sync-state coverage for provider-missing detection, reappearance, and no-auto-revive behavior in `apps/platform/tests/Feature/Jobs/PolicySyncProviderMissingSemanticsTest.php`, `apps/platform/tests/Feature/Jobs/PolicySyncIgnoredRevivalTest.php`, and `apps/platform/tests/Feature/PolicySyncServiceTest.php` - [x] T008 [P] [US1] Add policy UI and badge coverage for provider-missing versus ignored states in `apps/platform/tests/Feature/Filament/PolicyProviderMissingUiTest.php`, `apps/platform/tests/Feature/PolicyGeneralViewTest.php`, and `apps/platform/tests/Unit/Badges/PolicyBadgesTest.php`, including dominant-action, diagnostics-secondary, and duplicate-summary assertions ### Implementation for User Story 1 - [x] T009 [US1] Add `missing_from_provider_at` persistence and provider-presence helpers in `apps/platform/database/migrations/*_add_missing_from_provider_at_to_policies_table.php` and `apps/platform/app/Models/Policy.php` - [x] T010 [US1] Update sync and type-filter semantics in `apps/platform/app/Services/Intune/PolicySyncService.php` so provider absence sets/clears `missing_from_provider_at`, supported-type reclassification stops using `ignored_at`, and local ignore survives reappearance - [x] T011 [US1] Update policy filters, badges, helper copy, and action availability in `apps/platform/app/Filament/Resources/PolicyResource.php` and any related policy page helpers so provider-missing state is distinct from local ignore - [x] T012 [US1] Reconcile local ignore regression expectations in `apps/platform/tests/Feature/BulkDeletePoliciesTest.php`, `apps/platform/tests/Feature/BulkUnignorePoliciesTest.php`, `apps/platform/tests/Feature/PolicySyncStartSurfaceTest.php`, `apps/platform/tests/Feature/Jobs/AppProtectionPolicySyncFilteringTest.php`, and `apps/platform/tests/Feature/PolicySyncEnrollmentConfigurationTypeCollisionTest.php` **Checkpoint**: User Story 1 is independently functional and policy surfaces no longer collapse provider absence into local ignore. --- ## Phase 4: User Story 2 - Keep current backup/export honest while preserving restore continuity (Priority: P1) **Goal**: Stop treating provider-missing policies as current snapshot candidates while keeping historical restore paths available. **Independent Test**: Mark a policy provider-missing, verify current backup/export selection blocks or excludes it, then verify historical restore selection still offers the related backup item with continuity messaging. ### Tests for User Story 2 - [x] T013 [P] [US2] Add current backup/export eligibility coverage in `apps/platform/tests/Feature/BulkExportToBackupTest.php`, `apps/platform/tests/Feature/Filament/BackupCreationTest.php`, and `apps/platform/tests/Feature/Filament/BackupSetPolicyPickerTableTest.php`, including the combined ignored-plus-missing case where `provider_missing` is primary and local ignore is secondary context - [x] T014 [P] [US2] Add restore continuity coverage for provider-missing policies in `apps/platform/tests/Feature/Filament/RestoreItemSelectionTest.php` and any required restore safety regression assertions in `apps/platform/tests/Feature/RestoreUnknownPolicyTypeSafetyTest.php`, including calm continuity messaging without duplicating current-state blocker summaries ### Implementation for User Story 2 - [x] T015 [US2] Update current backup/export policy selection in `apps/platform/app/Services/Intune/BackupService.php` so provider-missing policies remain visible but blocked from fresh capture - [x] T016 [US2] Update backup selection/picker messaging in `apps/platform/app/Filament/Resources/BackupSetResource.php` and related backup creation helpers so provider-missing policies explain why fresh capture is unavailable without masquerading as ignored, while the combined state keeps local ignore as secondary context only - [x] T017 [US2] Update historical restore option builders and descriptions in `apps/platform/app/Filament/Resources/RestoreRunResource.php` so provider-missing policies remain selectable from backup history with continuity messaging **Checkpoint**: User Story 2 is independently functional and backup versus restore truth is no longer conflated. --- ## Phase 5: User Story 3 - Audit transitions and preserve safe recovery paths (Priority: P2) **Goal**: Make provider-missing and reappeared transitions auditable while keeping existing safe sync-retry behavior on the shared action surface. **Independent Test**: Run sync through missing and reappeared transitions, verify audit evidence is emitted, and confirm existing sync-retry surfaces remain truthful without creating new run behavior. ### Tests for User Story 3 - [x] T018 [P] [US3] Add audit-transition coverage in `apps/platform/tests/Feature/Jobs/PolicySyncProviderMissingSemanticsTest.php` and any existing audit assertions that cover policy sync transitions - [x] T019 [P] [US3] Add sync-action and authorization continuity assertions in `apps/platform/tests/Feature/PolicySyncStartSurfaceTest.php`, `apps/platform/tests/Feature/Filament/PolicyProviderMissingUiTest.php`, `apps/platform/tests/Feature/Filament/BackupSetPolicyPickerTableTest.php`, and `apps/platform/tests/Feature/Filament/RestoreItemSelectionTest.php` ### Implementation for User Story 3 - [x] T020 [US3] Add or reuse audit action identifiers and emit provider-missing/reappeared events in `apps/platform/app/Support/Audit/AuditActionId.php` plus the existing audit logger call sites reached from policy sync - [x] T021 [US3] Reconcile sync-retry/export action truth in `apps/platform/app/Filament/Resources/PolicyResource.php`, `apps/platform/tests/Feature/PolicySyncStartSurfaceTest.php`, and related policy action tests so blocked current backup/export does not create a run and allowed sync retry still uses the shared path **Checkpoint**: User Story 3 is independently functional and provider-presence transitions are auditable without new lifecycle or run infrastructure. --- ## Phase 6: Polish & Cross-Cutting Validation **Purpose**: Clean shared wording and run the narrow validation workflow. - [x] T022 [P] Reconcile any remaining provider-missing wording, badge labels, helper copy, dominant-action hierarchy, diagnostics-secondary ordering, raw/support gating, and duplicate-summary removal across `apps/platform/app/Filament/Resources/PolicyResource.php`, `apps/platform/app/Filament/Resources/BackupSetResource.php`, `apps/platform/app/Filament/Resources/RestoreRunResource.php`, and any touched localization or UI helper files - [x] T023 Run formatting for touched PHP files with `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - [x] T024 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Jobs/PolicySyncProviderMissingSemanticsTest.php tests/Feature/Jobs/PolicySyncIgnoredRevivalTest.php tests/Feature/Jobs/AppProtectionPolicySyncFilteringTest.php tests/Feature/PolicySyncServiceTest.php tests/Feature/PolicySyncEnrollmentConfigurationTypeCollisionTest.php tests/Feature/PolicySyncStartSurfaceTest.php` - [x] T025 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/PolicyProviderMissingUiTest.php tests/Feature/PolicyGeneralViewTest.php tests/Feature/BulkDeletePoliciesTest.php tests/Feature/BulkUnignorePoliciesTest.php tests/Unit/Badges/PolicyBadgesTest.php` - [x] T026 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/BulkExportToBackupTest.php tests/Feature/Filament/BackupCreationTest.php tests/Feature/Filament/BackupSetPolicyPickerTableTest.php tests/Feature/Filament/RestoreItemSelectionTest.php tests/Feature/RestoreUnknownPolicyTypeSafetyTest.php` - [x] T027 Run final residue searches for sync-driven `ignored_at` writes, expected `missing_from_provider_at` query usage, and the absence of `SoftDeletes`, purge-flow additions, new deletion actions, or lifecycle-framework drift across `apps/platform/app/` and `apps/platform/tests/` --- ## Dependencies & Execution Order ### Phase Dependencies - **Setup (Phase 1)**: Starts immediately and locks the seam inventory plus validation commands. - **Foundational (Phase 2)**: Depends on Setup and blocks story work until failing proof and state vocabulary are explicit. - **User Story 1 (Phase 3)**: Depends on Foundational and is the MVP entry point because provider-presence truth is the base behavior. - **User Story 2 (Phase 4)**: Depends on User Story 1 because backup and restore behavior consume the new provider-presence truth. - **User Story 3 (Phase 5)**: Depends on User Story 1 and should land after User Story 2 so audit and action continuity match the finished current-state and historical-state behavior. - **Polish (Phase 6)**: Depends on all desired user stories being complete so wording and residue checks run against the final shape. ### User Story Dependencies - **US1**: No dependencies beyond Foundational. - **US2**: Depends on US1. - **US3**: Depends on US1 and should follow US2. ### Within Each User Story - Add or update story tests first and confirm they fail before implementation is considered complete. - Keep `ignored_at` and `missing_from_provider_at` orthogonal rather than introducing a combined stored enum. - Reuse existing policy, backup, and restore surfaces instead of adding a new provider-missing registry or diagnostics page. - Keep provider-deleted taxonomy, multi-object rollout, and broader lifecycle work out of scope. ### Parallel Opportunities - `T001`, `T002`, and `T003` can run in parallel during Setup. - `T004`, `T005`, and `T006` can run in parallel during Foundational work. - `T007` and `T008` can run in parallel for User Story 1 before `T009` through `T012`. - `T013` and `T014` can run in parallel for User Story 2 before `T015` through `T017`. - `T018` and `T019` can run in parallel for User Story 3 before `T020` and `T021`. - `T024`, `T025`, and `T026` can run in parallel during final validation. --- ## Parallel Example: User Story 1 ```bash # User Story 1 tests in parallel T007 apps/platform/tests/Feature/Jobs/PolicySyncProviderMissingSemanticsTest.php + apps/platform/tests/Feature/Jobs/PolicySyncIgnoredRevivalTest.php + apps/platform/tests/Feature/PolicySyncServiceTest.php T008 apps/platform/tests/Feature/Filament/PolicyProviderMissingUiTest.php + apps/platform/tests/Feature/PolicyGeneralViewTest.php + apps/platform/tests/Unit/Badges/PolicyBadgesTest.php # User Story 1 implementation after the tests are in place T009 apps/platform/database/migrations/*_add_missing_from_provider_at_to_policies_table.php + apps/platform/app/Models/Policy.php T010 apps/platform/app/Services/Intune/PolicySyncService.php T011 apps/platform/app/Filament/Resources/PolicyResource.php ``` ## Parallel Example: User Story 2 ```bash # User Story 2 tests in parallel T013 apps/platform/tests/Feature/BulkExportToBackupTest.php + apps/platform/tests/Feature/Filament/BackupCreationTest.php + apps/platform/tests/Feature/Filament/BackupSetPolicyPickerTableTest.php T014 apps/platform/tests/Feature/Filament/RestoreItemSelectionTest.php + apps/platform/tests/Feature/RestoreUnknownPolicyTypeSafetyTest.php # User Story 2 implementation after the tests are in place T015 apps/platform/app/Services/Intune/BackupService.php T016 apps/platform/app/Filament/Resources/BackupSetResource.php T017 apps/platform/app/Filament/Resources/RestoreRunResource.php ``` --- ## Implementation Strategy ### MVP First (User Stories 1 and 2) 1. Complete Phase 1: Setup. 2. Complete Phase 2: Foundational. 3. Complete Phase 3: User Story 1. 4. Complete Phase 4: User Story 2. 5. Run `T023`, `T024`, `T025`, and `T026` before widening into audit and action-continuity cleanup. ### Incremental Delivery 1. Introduce provider-presence truth on `Policy` and stop sync from mutating `ignored_at` for provider absence. 2. Update policy UI to reflect the corrected state vocabulary. 3. Update backup selection so fresh capture uses provider-present truth only. 4. Update restore selection so historical backup continuity remains available. 5. Add audit continuity and finish with narrow validation commands. ### Parallel Team Strategy 1. One contributor can own the sync/model/policy surface slice (`US1`) while another prepares backup/restore tests (`US2`) after Phase 2. 2. After `US1` lands, backup and restore implementation can proceed without reopening state vocabulary. 3. A final pass can add audit continuity plus residue cleanup and run the targeted Sail commands. --- ## Notes - Suggested MVP scope: Phase 1 through Phase 4 only. Current backup/export truth is not honest until both US1 and US2 land together. - Explicit non-goals remain: `SoftDeletes`, provider-deleted taxonomy, ghost-policy registry, multi-object lifecycle rollout, workspace/tenant lifecycle semantics, and new browser or heavy-governance proof. - Follow-up candidates remain the same as the prepared spec: the broader lifecycle taxonomy and an explicit provider-deleted distinction. - All tasks above follow the required checklist format with task ID, optional parallel marker, story label where applicable, and concrete file paths.