## 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
20 KiB
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
- Lane assignment stays
fast-feedbackplusconfidenceand remains the narrowest sufficient proof for the changed behavior. - New or changed tests stay in focused
FeatureandUnitfiles only; no browser or heavy-governance family is added. - Shared helpers, factories, seeds, fixtures, and support defaults remain cheap by default.
- Planned validation commands stay limited to the targeted Sail test commands already captured in
specs/261-provider-missing-policy-visibility/plan.mdandspecs/261-provider-missing-policy-visibility/quickstart.md. - The declared surface test profile stays
standard-native-filamentplusshared-detail-familywhere restore continuity needs explicit proof. - Any follow-up or wording note resolves in this feature as
document-in-featureorfollow-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.
- 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, andapps/platform/app/Jobs/Operations/PolicyBulkDeleteWorkerJob.php - T002 [P] Verify the focused validation commands and proof lanes in
specs/261-provider-missing-policy-visibility/plan.mdandspecs/261-provider-missing-policy-visibility/quickstart.md - 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.
- 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, andapps/platform/tests/Feature/Jobs/AppProtectionPolicySyncFilteringTest.php - T005 [P] Lock policy-surface and badge proof across
apps/platform/tests/Feature/Filament/PolicyProviderMissingUiTest.php,apps/platform/tests/Feature/PolicyGeneralViewTest.php, andapps/platform/tests/Unit/Badges/PolicyBadgesTest.php, including one dominant next action, diagnostics-secondary ordering, and no duplicate visible decision summary - 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, andapps/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
- 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, andapps/platform/tests/Feature/PolicySyncServiceTest.php - 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, andapps/platform/tests/Unit/Badges/PolicyBadgesTest.php, including dominant-action, diagnostics-secondary, and duplicate-summary assertions
Implementation for User Story 1
- T009 [US1] Add
missing_from_provider_atpersistence and provider-presence helpers inapps/platform/database/migrations/*_add_missing_from_provider_at_to_policies_table.phpandapps/platform/app/Models/Policy.php - T010 [US1] Update sync and type-filter semantics in
apps/platform/app/Services/Intune/PolicySyncService.phpso provider absence sets/clearsmissing_from_provider_at, supported-type reclassification stops usingignored_at, and local ignore survives reappearance - T011 [US1] Update policy filters, badges, helper copy, and action availability in
apps/platform/app/Filament/Resources/PolicyResource.phpand any related policy page helpers so provider-missing state is distinct from local ignore - 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, andapps/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
- T013 [P] [US2] Add current backup/export eligibility coverage in
apps/platform/tests/Feature/BulkExportToBackupTest.php,apps/platform/tests/Feature/Filament/BackupCreationTest.php, andapps/platform/tests/Feature/Filament/BackupSetPolicyPickerTableTest.php, including the combined ignored-plus-missing case whereprovider_missingis primary and local ignore is secondary context - T014 [P] [US2] Add restore continuity coverage for provider-missing policies in
apps/platform/tests/Feature/Filament/RestoreItemSelectionTest.phpand any required restore safety regression assertions inapps/platform/tests/Feature/RestoreUnknownPolicyTypeSafetyTest.php, including calm continuity messaging without duplicating current-state blocker summaries
Implementation for User Story 2
- T015 [US2] Update current backup/export policy selection in
apps/platform/app/Services/Intune/BackupService.phpso provider-missing policies remain visible but blocked from fresh capture - T016 [US2] Update backup selection/picker messaging in
apps/platform/app/Filament/Resources/BackupSetResource.phpand 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 - T017 [US2] Update historical restore option builders and descriptions in
apps/platform/app/Filament/Resources/RestoreRunResource.phpso 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
- T018 [P] [US3] Add audit-transition coverage in
apps/platform/tests/Feature/Jobs/PolicySyncProviderMissingSemanticsTest.phpand any existing audit assertions that cover policy sync transitions - 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, andapps/platform/tests/Feature/Filament/RestoreItemSelectionTest.php
Implementation for User Story 3
- T020 [US3] Add or reuse audit action identifiers and emit provider-missing/reappeared events in
apps/platform/app/Support/Audit/AuditActionId.phpplus the existing audit logger call sites reached from policy sync - 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.
- 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 - 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 - 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 - 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 - 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 - T027 Run final residue searches for sync-driven
ignored_atwrites, expectedmissing_from_provider_atquery usage, and the absence ofSoftDeletes, purge-flow additions, new deletion actions, or lifecycle-framework drift acrossapps/platform/app/andapps/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_atandmissing_from_provider_atorthogonal 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, andT003can run in parallel during Setup.T004,T005, andT006can run in parallel during Foundational work.T007andT008can run in parallel for User Story 1 beforeT009throughT012.T013andT014can run in parallel for User Story 2 beforeT015throughT017.T018andT019can run in parallel for User Story 3 beforeT020andT021.T024,T025, andT026can run in parallel during final validation.
Parallel Example: User Story 1
# 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
# 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)
- Complete Phase 1: Setup.
- Complete Phase 2: Foundational.
- Complete Phase 3: User Story 1.
- Complete Phase 4: User Story 2.
- Run
T023,T024,T025, andT026before widening into audit and action-continuity cleanup.
Incremental Delivery
- Introduce provider-presence truth on
Policyand stop sync from mutatingignored_atfor provider absence. - Update policy UI to reflect the corrected state vocabulary.
- Update backup selection so fresh capture uses provider-present truth only.
- Update restore selection so historical backup continuity remains available.
- Add audit continuity and finish with narrow validation commands.
Parallel Team Strategy
- One contributor can own the sync/model/policy surface slice (
US1) while another prepares backup/restore tests (US2) after Phase 2. - After
US1lands, backup and restore implementation can proceed without reopening state vocabulary. - 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.