TenantAtlas/specs/261-provider-missing-policy-visibility/tasks.md
ahmido feeaadd5ad feat: add provider-missing policy visibility and restore continuity (#316)
## Summary
- separate provider-missing policy presence from local ignore semantics by introducing `missing_from_provider_at`
- update policy, backup, and restore surfaces so current-state capture stays honest while historical restore continuity remains available
- add focused sync, Filament, backup, restore, localization, and badge coverage for the new provider-missing behavior

## Scope
- policy sync and model truth
- policy resource visibility, badges, labels, and action gating
- backup/export eligibility and restore continuity messaging
- spec 261 artifacts and focused tests

## Validation
- feature-specific Pest coverage is included in the branch
- validation was not re-run as part of this commit/push/PR handoff

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #316
2026-05-01 20:18:27 +00:00

218 lines
20 KiB
Markdown

# 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.