--- description: "Task list for Ops-UX Constitution Rollout (v1.3.0 Alignment) (055)" --- # Tasks: Ops-UX Constitution Rollout (v1.3.0 Alignment) (055) **Input**: Design documents from `specs/055-ops-ux-rollout/` **Tests**: REQUIRED (Pest) — runtime behavior + UX contract enforcement. ## Phase 1: Setup (Shared Infrastructure) **Purpose**: Create a clean workspace for implementing and testing this migration. - [x] T001 Create Ops UX test folder structure in `tests/Feature/OpsUx/` - [x] T002 [P] Add a dedicated test file stub in `tests/Feature/OpsUx/OpsUxSmokeTest.php` - [x] T003 [P] Add a shared test helper (factory/state helpers) in `tests/Support/OpsUxTestSupport.php` --- ## Phase 2: Foundational (Blocking Prerequisites) **Purpose**: Shared primitives (catalog/links/presenter/normalization) that every user story depends on. - [x] T004 Update runtime unknown-type label behavior in `app/Support/OperationCatalog.php` (render `Unknown operation`, never raw type) - [x] T005 [P] Add shared presenter for toast/widget/notification copy in `app/Support/OpsUx/OperationUxPresenter.php` - [x] T059 Implement a single status normalization function for Ops-UX rendering - Map legacy completed/outcome values to canonical terminal statuses (`succeeded|partial|failed`) - Ensure widget and notifications consume normalized status - [x] T006 [P] Add summary_counts normalizer + whitelist enforcement in `app/Support/OpsUx/SummaryCountsNormalizer.php` - [x] T060 Consolidate allowed summary keys into one code constant/source (no duplicated lists) - Example shape: `OperationSummaryKeys::all()` (or similar) - Normalizer MUST reference that source - Catalog (if it references keys) MUST reference the same source - Add one guard test asserting the list matches spec.md canonical list - [x] T007 [P] Add canonical “View run” URL helper wrapper in `app/Support/OpsUx/OperationRunUrl.php` (delegates to `app/Support/OperationRunLinks.php`) - [x] T008 Update summary key whitelist consumption in `app/Support/OperationCatalog.php` to reference the consolidated source (see T060) - [x] T009 Update summary sanitization to use shared normalizer in `app/Services/OperationRunService.php` - [x] T010 Update OperationRun completed notification to use shared presenter + normalizer in `app/Notifications/OperationRunCompleted.php` - [x] T011 Disable queued DB notification emission by default in `app/Services/OperationRunService.php` (align with FR-010c) - [x] T012 Deprecate/stop using queued DB notification class in `app/Notifications/OperationRunQueued.php` (keep class but ensure no producers call it) - [x] T013 Ensure all “View run” actions inside operation notifications use canonical URL helper in `app/Notifications/OperationRunCompleted.php` **Checkpoint**: Shared contracts available; user story work can proceed. --- ## Phase 3: User Story 1 — Consistent “I started it” feedback (Priority: P1) 🎯 MVP **Goal**: Starting any operation shows queued-only intent feedback with canonical “View run”. **Independent Test**: Trigger an operation start from a Filament action; observe a queued-only toast (`{OperationLabel} queued` / `Running in the background.`) and verify no queued DB notification is created. ### Tests for User Story 1 - [x] T014 [P] [US1] Add test ensuring no queued DB notifications are emitted in `tests/Feature/OpsUx/NoQueuedDbNotificationsTest.php` - [x] T015 [P] [US1] Add test for canonical queued toast copy builder in `tests/Feature/OpsUx/QueuedToastCopyTest.php` - [x] T057 [US1] Enforce toast auto-dismiss duration (3–5 seconds) for queued intent feedback (set duration explicitly, e.g. 4000ms) - [x] T058 [P] [US1] (Optional guard) Centralize toast duration in `OperationUxPresenter` and add a small unit test to keep it within 3000–5000ms ### Implementation for User Story 1 - [x] T016 [P] [US1] Migrate queued toast copy for policy operations in `app/Filament/Resources/PolicyResource.php` (use `OperationUxPresenter`) - [x] T017 [P] [US1] Migrate queued toast copy for policy version operations in `app/Filament/Resources/PolicyVersionResource.php` (use `OperationUxPresenter`) - [x] T018 [P] [US1] Migrate queued toast copy for restore run operations in `app/Filament/Resources/RestoreRunResource.php` (use `OperationUxPresenter`) - [x] T019 [P] [US1] Migrate queued toast copy for backup schedule operations in `app/Filament/Resources/BackupScheduleResource.php` (use `OperationUxPresenter`) - [x] T020 [P] [US1] Migrate queued toast copy for backup set operations in `app/Filament/Resources/BackupSetResource.php` (use `OperationUxPresenter`) - [x] T021 [P] [US1] Migrate queued toast copy for tenant sync operations in `app/Filament/Resources/TenantResource.php` (use `OperationUxPresenter`) - [x] T022 [P] [US1] Migrate queued toast copy for policy view page operations in `app/Filament/Resources/PolicyResource/Pages/ViewPolicy.php` (use `OperationUxPresenter`) - [x] T023 [P] [US1] Migrate queued toast copy for inventory landing operations in `app/Filament/Pages/InventoryLanding.php` (use `OperationUxPresenter`) - [x] T024 [P] [US1] Migrate queued toast copy for drift landing operations in `app/Filament/Pages/DriftLanding.php` (use `OperationUxPresenter`) - [x] T025 [P] [US1] Migrate queued toast copy for backup-set policy picker operations in `app/Livewire/BackupSetPolicyPickerTable.php` (use `OperationUxPresenter`) **Checkpoint**: A user can start operations and get consistent queued intent feedback. --- ## Phase 4: User Story 2 — Live awareness of active operations (Priority: P2) **Goal**: A single global widget shows only tenant-scoped queued/running runs with strict copy and canonical links. **Independent Test**: Create active runs in the DB; the widget shows max 5 rows, each row has `Queued`/`Running` only, and terminal runs never render. ### Tests for User Story 2 - [x] T026 [P] [US2] Add widget filtering test (never show terminal) in `tests/Feature/OpsUx/ProgressWidgetFiltersTest.php` - [x] T027 [P] [US2] Add widget max-5 + overflow link test in `tests/Feature/OpsUx/ProgressWidgetOverflowTest.php` - [x] T062 [US2] Add restore execution → OperationRun sync regression test in `tests/Feature/OpsUx/RestoreExecutionOperationRunSyncTest.php` ### Implementation for User Story 2 - [x] T028 [US2] Migrate widget query from BulkOperationRun to OperationRun in `app/Livewire/BulkOperationProgress.php` - [x] T029 [US2] Enforce tenant-wide scope + Monitoring access guard in `app/Livewire/BulkOperationProgress.php` - [x] T030 [US2] Update widget UI strings + strict status text in `resources/views/livewire/bulk-operation-progress.blade.php` - [x] T031 [US2] Implement max-5 + overflow link behavior in `resources/views/livewire/bulk-operation-progress.blade.php` - [x] T032 [US2] Use canonical “View run” URLs in widget rows in `resources/views/livewire/bulk-operation-progress.blade.php` (via `OperationRunUrl` / `OperationRunLinks`) - [x] T033 [US2] No % in widget; widget may show elapsed time only - [x] T034 [US2] Implement calm polling schedule + pause rules in `resources/views/livewire/bulk-operation-progress.blade.php` - [x] T063 [US2] Dispatch `ops-ux:run-enqueued` browser event after successful enqueue so the widget refreshes immediately - Producers: `app/Filament/Pages/InventoryLanding.php`, `app/Filament/Pages/DriftLanding.php`, `app/Filament/Resources/BackupScheduleResource.php`, `app/Filament/Resources/PolicyResource.php`, `app/Filament/Resources/PolicyResource/Pages/ListPolicies.php`, `app/Filament/Resources/RestoreRunResource.php`, `app/Filament/Resources/TenantResource.php`, `app/Livewire/BackupSetPolicyPickerTable.php`, `app/Filament/Resources/BackupSetResource/RelationManagers/BackupItemsRelationManager.php` - [x] T035 [US2] Confirm widget injection remains global and consistent in `app/Providers/Filament/AdminPanelProvider.php` ### Run detail polling (missing coverage for FR-013) - [x] T053 [US2] Add run-detail polling controller/hook that applies calm polling while status is active (`queued|running`) (only poll when run detail is visible; stop immediately on terminal; backoff 1s (first 10s) → 5s → 10s (after 60s)) - [x] T054 [US2] Pause run-detail polling when a modal is open (global modal flag) and resume when closed (no network update spam while confirm dialogs/modals are open) - [x] T055 [US2] Pause run-detail polling when browser tab is hidden (Page Visibility API) and resume when visible (no polling when `document.hidden = true`) - [x] T056 [P] [US2] Add a small guard test/component test that run-detail polling is disabled once the run becomes terminal - [x] T061 [US2] Surface elapsed time + expected duration + stuck guidance in run detail **Checkpoint**: Widget is constitution-compliant and becomes the single active-ops surface. --- ## Phase 5: User Story 3 — Audit + outcome without spam (Priority: P3) **Goal**: Exactly one terminal DB notification per run (initiator-only) with canonical copy, canonical link, safe summary. **Independent Test**: Transition a run to terminal multiple times (or call completion twice); verify only one DB notification exists and it contains only whitelisted numeric summary keys. ### Tests for User Story 3 - [x] T036 [P] [US3] Add terminal notification idempotency test in `tests/Feature/OpsUx/TerminalNotificationIdempotencyTest.php` - [x] T037 [P] [US3] Add summary whitelist + numeric-only test in `tests/Feature/OpsUx/SummaryCountsWhitelistTest.php` - [x] T038 [P] [US3] Add canonical “View run” action test for notifications in `tests/Feature/OpsUx/NotificationViewRunLinkTest.php` ### Implementation for User Story 3 - [x] T039 [US3] Refactor terminal notification copy/title/body to use presenter in `app/Notifications/OperationRunCompleted.php` - [x] T040 [US3] Ensure initiator-only delivery is enforced in `app/Services/OperationRunService.php` - [x] T041 [US3] Ensure terminal notification is emitted exactly once per run in `app/Services/OperationRunService.php` - [x] T042 [US3] Ensure notification summary renders only normalized `summary_counts` in `app/Notifications/OperationRunCompleted.php` - [x] T043 [US3] Ensure failure message suffix is sanitized + short in `app/Notifications/OperationRunCompleted.php` **Checkpoint**: Terminal outcomes are auditable without spam. --- ## Phase 6: User Story 4 — Regression-safe by default (Priority: P4) **Goal**: Guards prevent drift (catalog coverage, canonical links, surface rules, summary rules). **Independent Test**: Introduce a fake operation type in code and confirm tests fail; confirm “View run” always resolves to the canonical Monitoring run-detail destination. ### Tests for User Story 4 - [x] T044 [P] [US4] Add catalog coverage guard test in `tests/Feature/OpsUx/OperationCatalogCoverageTest.php` - [x] T045 [P] [US4] Add canonical “View run” helper usage guard test in `tests/Feature/OpsUx/CanonicalViewRunLinksTest.php` - [x] T046 [P] [US4] Add unknown-type runtime label test in `tests/Feature/OpsUx/UnknownOperationTypeLabelTest.php` ### Implementation for User Story 4 - [x] T047 [US4] Ensure OperationRunResource type label rendering never shows raw type in `app/Filament/Resources/OperationRunResource.php` - [x] T048 [US4] Ensure Monitoring Operations page type labels never show raw type in `app/Filament/Pages/Monitoring/Operations.php` - [x] T049 [US4] Ensure any remaining “View run” links use canonical helper in `app/Support/OperationRunLinks.php` **Checkpoint**: Drift prevention is enforced in CI. --- ## Phase 7: Polish & Cross-Cutting Concerns - [x] T050 [P] Run Pint autofix for touched files via `app/` and `tests/` (validate against `composer.json` scripts) - [x] T051 Run targeted test suite for Ops UX via `tests/Feature/OpsUx/` (document exact filter in `specs/055-ops-ux-rollout/quickstart.md`) - [x] T052 [P] Remove or update any stale queued-notification references in `app/Services/OperationRunService.php` --- ## Dependencies & Execution Order ### User Story Dependencies - **US1 (P1)** depends on Phase 2 (Foundational) tasks T004–T013. - **US2 (P2)** depends on Phase 2 (Foundational) tasks T004–T013. - **US3 (P3)** depends on Phase 2 (Foundational) tasks T004–T013. - **US4 (P4)** depends on completion of US1–US3 (guards should reflect final behavior). ### Recommended completion order 1. Phase 2 (Foundational) 2. US1 (queued toast + no queued DB notifications) 3. US3 (terminal notification contract) 4. US2 (widget) 5. US4 (guards) ## Parallel Opportunities - Within Phase 2: T005–T007 can be done in parallel. - US1 migration tasks T016–T025 are parallelizable (different files). - US4 tests T044–T046 can be written in parallel. ## Parallel Example: User Story 1 - Task: T016 (PolicyResource) + T017 (PolicyVersionResource) + T018 (RestoreRunResource) can run in parallel. - Task: T019 (BackupScheduleResource) + T020 (BackupSetResource) can run in parallel. ## Implementation Strategy ### MVP scope Ship US1 + the minimum foundational primitives (Phase 2) to guarantee: - queued-only toast copy is consistent - queued DB notifications are banned - canonical “View run” destination is available Then layer US3 (terminal notification) before US2 (widget) to ensure audit outcomes are reliable early.