--- description: "Task list for OperationRun Progress Contract v1" --- # Tasks: OperationRun Progress Contract v1 **Input**: Design documents from `specs/270-operationrun-progress-contract/` **Prerequisites**: `specs/270-operationrun-progress-contract/spec.md`, `specs/270-operationrun-progress-contract/plan.md`, `specs/270-operationrun-progress-contract/checklists/requirements.md` **Review Artifact**: `specs/270-operationrun-progress-contract/checklists/requirements.md` is the outcome-of-record for the review outcome class, workflow outcome, and test-governance outcome. If implementation widens into counted-writer rollout, dashboard drift work, or a new persisted progress model, update that artifact before continuing. **Tests**: REQUIRED (Pest). Keep proof bounded to one new unit suite plus focused Ops-UX feature coverage. Browser coverage remains owned by `specs/268-operationrun-activity-feedback/` and must not be pulled into this slice implicitly. **Operations**: No new `OperationRun` type, no queue-family changes, no notification-policy changes, no new `summary_counts` keys, and no new lifecycle ownership. Existing queued toasts, terminal notifications, `run-enqueued` browser events, and canonical `OperationRun` links remain authoritative. **RBAC**: Reuse current `OperationRun` policies and tenant context guards. No tenantless leakage from tenant surfaces; covered surfaces stay inert when no selected tenant or `viewAny` capability exists. **Shared Pattern Reuse**: Reuse `SummaryCountsNormalizer`, `OperationSummaryKeys`, `ActiveRuns`, `OperationStatusNormalizer`, `OperationUxPresenter`, `OperationRunService`, `BulkOperationProgress`, and `docs/ui/tenantpilot-enterprise-ui-standards.md`. Do not create a second local progress helper in Blade or Livewire. **Filament / Panel Guardrails**: Filament remains v5 on Livewire v4. Provider registration remains unchanged in `apps/platform/bootstrap/providers.php`. No new panel, resource, or asset strategy is allowed. This slice changes shared progress semantics only. **Organization**: Tasks are grouped by user story so the shared contract, the shell adoption, and the future-boundary documentation remain independently reviewable. ## Test Governance Notes - Lane mix stays Unit plus Feature. - Prefer extending `ActivityFeedbackSurfaceTest`, `BulkOperationProgressDbOnlyTest`, and `SummaryCountsWhitelistTest` before creating broader families. - Browser proof stays with Spec 268 and must not become a hidden requirement here. - Validation commands must stay file-scoped and run through Sail. ## Phase 1: Setup (Shared Context) **Purpose**: confirm the bounded slice, the inherited Ops-UX rules, and the specific ad hoc progress seam before runtime edits begin. - [x] T001 Review `specs/270-operationrun-progress-contract/spec.md`, `specs/270-operationrun-progress-contract/plan.md`, `specs/270-operationrun-progress-contract/checklists/requirements.md`, `docs/product/spec-candidates.md`, `docs/product/roadmap.md`, `specs/268-operationrun-activity-feedback/spec.md`, `specs/055-ops-ux-rollout/spec.md`, `docs/ui/tenantpilot-enterprise-ui-standards.md`, and `.specify/memory/constitution.md` together so the slice stays on repo-real progress truth and keeps `269`, `271`, `272`, and `273` explicitly out of scope. - [x] T002 [P] Confirm the current writer and sanitizer seams in `apps/platform/app/Services/OperationRunService.php`, `apps/platform/app/Support/OpsUx/SummaryCountsNormalizer.php`, and `apps/platform/app/Support/OpsUx/OperationSummaryKeys.php`. - [x] T003 [P] Confirm the current visible progress host and reader seams in `apps/platform/app/Support/OpsUx/ActiveRuns.php`, `apps/platform/app/Livewire/BulkOperationProgress.php`, and `apps/platform/resources/views/livewire/bulk-operation-progress.blade.php`. - [x] T004 [P] Confirm current proof owners in `apps/platform/tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php`, `apps/platform/tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php`, and `apps/platform/tests/Feature/OpsUx/SummaryCountsWhitelistTest.php`, then record the exact shell-progress drift seam that the new unit suite must own. --- ## Phase 2: Foundational (Blocking Prerequisites) **Purpose**: settle the progress contract and proof owners before the visible shell host is refactored. **Critical**: no user-story runtime work should begin until this phase is complete. - [x] T005 [P] Create failing unit coverage in `apps/platform/tests/Unit/Support/OpsUx/OperationRunProgressContractTest.php` for `none`, `activity`, `counted`, safe `phased`, and safe `composite` capability mapping, queued indeterminate handling, terminal no-progress handling, and outcome-counter rejection. - [x] T006 [P] Extend `apps/platform/tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php` for shell adoption of the shared contract: determinate progress only from running plus trustworthy `processed`/`total`, no counted progress for queued runs, and no progress line or percentage for terminal runs. - [x] T007 [P] Extend `apps/platform/tests/Feature/OpsUx/SummaryCountsWhitelistTest.php` only as needed so the new contract still reuses numeric-only whitelist semantics and does not create hidden progress inputs from non-whitelisted keys. - Note: no file edit was required because the existing whitelist suite already proved the contract continued to consume the canonical numeric-only keys without introducing new progress inputs. **Checkpoint**: the shared contract and focused proof owners are settled before implementation begins. --- ## Phase 3: User Story 1 - Derive truthful progress modes from existing run truth (Priority: P1) **Goal**: one shared Ops-UX helper classifies progress capability and render model from current `OperationRun` truth. **Independent Test**: create queued, running, and terminal runs with varying `summary_counts`, then verify the new unit suite classifies them correctly without involving a UI host. ### Tests for User Story 1 - [x] T008 [P] [US1] Add any additional dataset or fixture coverage needed in `apps/platform/tests/Unit/Support/OpsUx/OperationRunProgressContractTest.php` for current real run shapes such as inventory sync, review-pack generation, and bulk jobs that already emit `processed` and `total`. ### Implementation for User Story 1 - [x] T009 [US1] Introduce one shared progress contract/helper under `apps/platform/app/Support/OpsUx/` that derives progress capability and render-safe output from `OperationRun` status, outcome, sanitized `summary_counts`, and current trusted context only. - [x] T010 [US1] Reuse or extend `apps/platform/app/Support/OpsUx/SummaryCountsNormalizer.php`, `apps/platform/app/Support/OpsUx/OperationSummaryKeys.php`, and `apps/platform/app/Support/OpsUx/OperationStatusNormalizer.php` only as needed so lifecycle semantics and progress semantics stay separate but consistent. - Note: the implementation reused the existing normalizer and status helper without modifying their source, which kept progress semantics bounded to the new contract helper. **Checkpoint**: User Story 1 is independently functional when one shared helper owns the progress semantics. --- ## Phase 4: User Story 2 - Keep the current shell host on the shared contract (Priority: P1) **Goal**: the current shell activity hint consumes the shared contract instead of local progress math. **Independent Test**: render the shell surface with queued, running, and terminal runs, then verify the shell shows counted progress only when the shared contract allows it and otherwise falls back to activity-only or terminal semantics. ### Tests for User Story 2 - [x] T010A [P] [US2] Extend `apps/platform/tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php` so the shell stays inert for missing-tenant or unauthorized actors and does not expose progress-derived copy for runs the actor cannot view. - Note: repo truth kept the missing-tenant inert-state proof in `BulkOperationProgressDbOnlyTest.php`, while tenant-scoped visibility remained covered by the existing DB-only tenant-scoping assertion. - [x] T011 [P] [US2] Extend `apps/platform/tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php` for queued indeterminate state, clamped counted progress, and terminal no-progress behavior at the shell host hydration boundary. ### Implementation for User Story 2 - [x] T012 [US2] Refactor `apps/platform/resources/views/livewire/bulk-operation-progress.blade.php` and `apps/platform/app/Livewire/BulkOperationProgress.php` so the shell host consumes the shared progress contract and no longer computes percentages or progress eligibility inline. - Note: repository truth only required the Blade host seam to change; `BulkOperationProgress.php` remained unchanged because it already handed the correct run collection to the view. - [x] T013 [US2] Update `apps/platform/app/Support/OpsUx/ActiveRuns.php` only if needed so shell-visible progress availability stays aligned with the shared contract; if implementation reveals another consumer with local progress math, stop and update the spec, plan, and checklist before touching it. - Note: no `ActiveRuns.php` change was required; no second shell-visible local progress calculator was found. **Checkpoint**: User Story 2 is independently functional when the shell surface no longer owns progress semantics ad hoc. --- ## Phase 5: User Story 3 - Document future-safe progress boundaries (Priority: P2) **Goal**: the UI standards and feature package define how future counted, phased, and composite work must extend the contract. **Independent Test**: review the standards update and the focused proving suite together, then confirm that counted rollout, phase/composite rollout, and dashboard follow-up remain named follow-up specs rather than hidden scope here. ### Implementation for User Story 3 - [x] T014 [US3] Update `docs/ui/tenantpilot-enterprise-ui-standards.md` with canonical progress modes, the rule that `processed` and `total` are the only v1 determinate source, the rule that outcome counters remain outcome-only, the queued indeterminate rule, the terminal no-progress rule, and the safe future boundaries for `phased` and `composite` categories. - [x] T015 [US3] Review the resulting implementation to confirm it introduces no new `summary_counts` keys, no writer rollout, no dashboard-specific progress surface, and no persisted progress mode. **Checkpoint**: User Story 3 is independently functional when the standards doc and feature package leave clear extension rules for later specs. --- ## Phase 6: Polish & Cross-Cutting Validation **Purpose**: validate the bounded slice, stop drift, and hand off a clean implementation path. - [x] T016 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/OpsUx/OperationRunProgressContractTest.php`. - [x] T017 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php tests/Feature/OpsUx/SummaryCountsWhitelistTest.php`. - [x] T018 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` for touched platform files. - [x] T019 [P] Review touched code against `docs/ui/tenantpilot-enterprise-ui-standards.md` and confirm the shell remains decision-first, diagnostics-light, Filament-native, and backed by one shared progress contract. - [x] T020 [P] Review touched code to confirm Filament stays on Livewire v4, provider registration remains unchanged in `apps/platform/bootstrap/providers.php`, no new assets were registered, and no new `OperationRun` lifecycle or notification path was introduced. - [x] T021 [P] Review touched code to confirm the implementation reuses existing poller families and introduces no new parallel polling loops while adopting the shared progress contract. --- ## Dependencies & Execution Order ### Phase Dependencies - **Phase 1 (Setup)**: no dependencies; start immediately. - **Phase 2 (Foundational)**: depends on Phase 1 and blocks user-story work. - **Phase 3 (US1)**: depends on Phase 2 and establishes the shared progress contract. - **Phase 4 (US2)**: depends on Phase 3 because the shell must consume the shared contract rather than invent its own logic. - **Phase 5 (US3)**: depends on Phase 3 and should land with US2 so the contract and extension boundaries stay aligned. - **Phase 6 (Polish)**: depends on all desired user stories being complete. ### User Story Dependencies - **US1 (P1)**: independently testable after Phase 2 and delivers the core enterprise-truth contract. - **US2 (P1)**: independently testable after Phase 3 and delivers the real visible shell adoption. - **US3 (P2)**: independently testable after Phase 3 and is still required for package completion because future rollout ownership is part of the approved scope. ### Within Each User Story - Write the listed Pest coverage first and make it fail for the intended gap. - Land the shared progress helper before removing local shell math. - Re-run the narrowest affected validation command after each story checkpoint before moving on. --- ## Implementation Strategy ### Suggested MVP Scope - MVP = **US1 + US2**, because the package only delivers value once the shared contract exists and the current visible shell host consumes it. ### Incremental Delivery 1. Complete Phase 1 and Phase 2. 2. Deliver US1. 3. Deliver US2 on top of the shared helper. 4. Add US3 documentation and boundary hardening. 5. Finish with focused validation and formatting. ### Team Strategy 1. Settle the shared contract and unit proof owner first. 2. Keep shell-adoption edits serialized around `BulkOperationProgress` and its Blade view. 3. Do not widen into writer rollout or dashboard follow-up while implementing this package. --- ## Deferred Follow-Ups / Non-Goals - `271 — Counted Progress Rollout v1` - `272 — OperationRun Phase & Composite Progress v1` - `273 — Tenant Dashboard Active Operations Summary Card` - any browser-smoke expansion beyond the currently-owned Spec 268 overlap proof - any new writer-side rollout that adds or changes `summary_counts.total` or `summary_counts.processed` - any persisted progress mode, registry, or dashboard redesign