Implements Spec 096 ops polish bundle: - Persist durable OperationRun.summary_counts for assignment fetch/restore (final attempt wins) - Server-side dedupe for assignment jobs (15-minute cooldown + non-canonical skip) - Track ReconcileAdapterRunsJob via workspace-scoped OperationRun + stable failure codes + overlap prevention - Seed DX: ensure seeded tenants use UUID v4 external_id and seed satisfies workspace_id NOT NULL constraints Verification (local / evidence-based): - `vendor/bin/sail artisan test --compact tests/Feature/Operations/AssignmentRunSummaryCountsTest.php tests/Feature/Operations/AssignmentJobDedupeTest.php tests/Feature/Operations/ReconcileAdapterRunsJobTrackingTest.php tests/Feature/Seed/PoliciesSeederExternalIdTest.php` - `vendor/bin/sail bin pint --dirty` Spec artifacts included under `specs/096-ops-polish-assignment-dedupe-system-tracking/` (spec/plan/tasks/checklists). Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #115
178 lines
8.8 KiB
Markdown
178 lines
8.8 KiB
Markdown
# Tasks: 096 — Ops Polish Bundle (Assignment job summaries + job dedupe + system job tracking + seeder DX)
|
||
|
||
**Input**: Design documents from `specs/096-ops-polish-assignment-dedupe-system-tracking/`
|
||
**Prerequisites**: `plan.md` (required), `spec.md` (required), `research.md`, `data-model.md`, `contracts/`, `quickstart.md`
|
||
|
||
**Tests**: REQUIRED (Pest) for runtime behavior changes.
|
||
**Operations**: This feature modifies queued/scheduled work, so tasks must ensure canonical `OperationRun` creation/reuse + DB-level active-run dedupe + safe failure summaries.
|
||
**RBAC / Filament**: No authorization or Filament UI changes in scope.
|
||
|
||
---
|
||
|
||
## Phase 1: Setup (Docs + hygiene)
|
||
|
||
**Purpose**: Ensure spec artifacts and plan alignment are clean before code work.
|
||
|
||
- [X] T001 Fix duplicated FR numbering in specs/096-ops-polish-assignment-dedupe-system-tracking/spec.md
|
||
- [X] T002 Sync plan references after edits in specs/096-ops-polish-assignment-dedupe-system-tracking/plan.md (ensure dedupe window semantics are described as a cooldown)
|
||
|
||
---
|
||
|
||
## Phase 2: Foundational (Blocking prerequisites)
|
||
|
||
**Purpose**: Shared primitives used by all user stories.
|
||
|
||
- [X] T003 Add operation label for `ops.reconcile_adapter_runs` in app/Support/OperationCatalog.php
|
||
- [X] T004 Add expected duration for `ops.reconcile_adapter_runs` in app/Support/OperationCatalog.php
|
||
- [X] T005 Do not add an enum case for `ops.reconcile_adapter_runs` in app/Support/OperationRunType.php (use the string type; enum is not a complete registry)
|
||
- [X] T006 Implement a stable, non-secret fingerprint helper for assignment job identity in app/Support/OpsUx/AssignmentJobFingerprint.php
|
||
- [X] T007 [P] Wire FetchAssignmentsJob identity inputs to use AssignmentJobFingerprint in app/Jobs/FetchAssignmentsJob.php
|
||
- [X] T008 [P] Wire RestoreAssignmentsJob identity inputs to use AssignmentJobFingerprint in app/Jobs/RestoreAssignmentsJob.php
|
||
|
||
**Checkpoint**: Foundation ready — story implementation can begin.
|
||
|
||
---
|
||
|
||
## Phase 3: User Story 1 — Assignment runs show durable summaries (Priority: P2) 🎯 MVP
|
||
|
||
**Goal**: Persist consistent `OperationRun.summary_counts` for assignment fetch/restore runs (final attempt wins).
|
||
|
||
**Independent Test**: Dispatch each job; assert `operation_runs.summary_counts` contains non-null `total`, `processed`, `failed`, and does not double-count across retries.
|
||
|
||
### Tests (write first)
|
||
|
||
- [X] T009 [P] [US1] Add fetch summary persistence test in tests/Feature/Operations/AssignmentRunSummaryCountsTest.php
|
||
- [X] T010 [P] [US1] Add restore summary persistence test in tests/Feature/Operations/AssignmentRunSummaryCountsTest.php
|
||
|
||
### Implementation
|
||
|
||
- [X] T011 [US1] Persist terminal summary counts for fetch runs in app/Jobs/FetchAssignmentsJob.php via app/Services/OperationRunService.php::updateRun(...)
|
||
- [X] T012 [US1] Persist terminal summary counts for restore runs in app/Jobs/RestoreAssignmentsJob.php via app/Services/OperationRunService.php::updateRun(...)
|
||
- [X] T013 [US1] Ensure summary counts reflect final attempt (overwrite on completion) in app/Services/OperationRunService.php usage from app/Jobs/FetchAssignmentsJob.php
|
||
- [X] T014 [US1] Ensure summary counts reflect final attempt (overwrite on completion) in app/Services/OperationRunService.php usage from app/Jobs/RestoreAssignmentsJob.php
|
||
|
||
**Checkpoint**: Assignment runs always write durable counters.
|
||
|
||
---
|
||
|
||
## Phase 4: User Story 2 — Duplicate dispatches do not overlap (Priority: P2)
|
||
|
||
**Goal**: Prevent concurrent overlap for the same logical assignment job identity.
|
||
|
||
**Independent Test**: Dispatch the same job identity twice and verify only one execution performs work; the other is skipped/reuses the canonical active run.
|
||
|
||
### Tests (write first)
|
||
|
||
- [X] T015 [P] [US2] Add dedupe test for fetch job in tests/Feature/Operations/AssignmentJobDedupeTest.php
|
||
- [X] T016 [P] [US2] Add dedupe test for restore job in tests/Feature/Operations/AssignmentJobDedupeTest.php
|
||
|
||
### Implementation
|
||
|
||
- [X] T017 [US2] Implement dispatch-time dedupe (reuse active `OperationRun`) for fetch in app/Jobs/FetchAssignmentsJob.php using app/Services/OperationRunService.php::ensureRunWithIdentity(...)
|
||
- [X] T018 [US2] Implement dispatch-time dedupe (reuse active `OperationRun`) for restore in app/Jobs/RestoreAssignmentsJob.php using app/Services/OperationRunService.php::ensureRunWithIdentity(...)
|
||
- [X] T019 [US2] Implement execute-time guard (skip when not canonical run) for fetch in app/Jobs/FetchAssignmentsJob.php
|
||
- [X] T020 [US2] Implement execute-time guard (skip when not canonical run) for restore in app/Jobs/RestoreAssignmentsJob.php
|
||
- [X] T021 [US2] Enforce dedupe window semantics (15 minutes) by reusing a recently completed identity (cooldown) in app/Services/OperationRunService.php (new helper) and call it from app/Jobs/FetchAssignmentsJob.php
|
||
- [X] T022 [US2] Enforce dedupe window semantics (15 minutes) by reusing a recently completed identity (cooldown) in app/Services/OperationRunService.php (new helper) and call it from app/Jobs/RestoreAssignmentsJob.php
|
||
|
||
**Checkpoint**: Duplicate dispatch/redelivery cannot cause overlapping work.
|
||
|
||
---
|
||
|
||
## Phase 5: User Story 3 — Housekeeping runs are tracked like everything else (Priority: P3)
|
||
|
||
**Goal**: `ReconcileAdapterRunsJob` writes a workspace-scoped `OperationRun` with stable failure codes + sanitized messages.
|
||
|
||
**Independent Test**: Execute the job successfully and with a forced failure; verify an `OperationRun` exists for `type = ops.reconcile_adapter_runs` with correct outcome and failure summary.
|
||
|
||
### Tests (write first)
|
||
|
||
- [X] T023 [P] [US3] Add reconcile job success tracking test in tests/Feature/Operations/ReconcileAdapterRunsJobTrackingTest.php
|
||
- [X] T024 [P] [US3] Add reconcile job failure tracking test in tests/Feature/Operations/ReconcileAdapterRunsJobTrackingTest.php
|
||
|
||
### Implementation
|
||
|
||
- [X] T025 [US3] Create/reuse workspace-scoped run for housekeeping in app/Jobs/ReconcileAdapterRunsJob.php via app/Services/OperationRunService.php::ensureWorkspaceRunWithIdentity(...)
|
||
- [X] T026 [US3] Persist terminal outcome + sanitized failure summary for housekeeping in app/Jobs/ReconcileAdapterRunsJob.php using app/Services/OperationRunService.php::updateRun(...)
|
||
- [X] T027 [US3] Include stable failure code (e.g., `ops.reconcile_adapter_runs.failed`) for housekeeping failures in app/Jobs/ReconcileAdapterRunsJob.php
|
||
|
||
**Checkpoint**: Housekeeping shows up in the operations ledger consistently.
|
||
|
||
---
|
||
|
||
## Phase 6: User Story 4 — Fresh seed flows work without manual intervention (Priority: P3)
|
||
|
||
**Goal**: Seeding creates tenants with UUID v4 `external_id` and does not violate constraints.
|
||
|
||
**Independent Test**: Run `migrate:fresh --seed` and assert the seeded tenant(s) have UUID v4 `external_id`.
|
||
|
||
### Tests (write first)
|
||
|
||
- [X] T028 [P] [US4] Add seed external_id UUID test in tests/Feature/Seed/PoliciesSeederExternalIdTest.php
|
||
|
||
### Implementation
|
||
|
||
- [X] T029 [US4] Generate UUID v4 `external_id` for seed tenant in database/seeders/PoliciesSeeder.php (do not reuse `INTUNE_TENANT_ID`)
|
||
- [X] T034 [US4] Ensure seed workflow sets `workspace_id` for seeded tenant + policies to satisfy NOT NULL constraints in database/seeders/PoliciesSeeder.php
|
||
- [X] T035 [US4] Ensure platform tenant seed sets `workspace_id` (default workspace) in database/seeders/PlatformUserSeeder.php
|
||
|
||
**Checkpoint**: Seed workflow is reliable locally and in CI.
|
||
|
||
---
|
||
|
||
## Phase 7: Polish & Cross-Cutting Concerns
|
||
|
||
**Purpose**: Consistency, formatting, and verification.
|
||
|
||
- [X] T030 Run formatter on changed files (app/**, database/**, tests/**) via `vendor/bin/sail bin pint --dirty`
|
||
- [X] T031 Run spec-focused tests in tests/Feature/Operations/AssignmentRunSummaryCountsTest.php and tests/Feature/Operations/AssignmentJobDedupeTest.php
|
||
- [X] T032 Run spec-focused tests in tests/Feature/Operations/ReconcileAdapterRunsJobTrackingTest.php and tests/Feature/Seed/PoliciesSeederExternalIdTest.php
|
||
|
||
---
|
||
|
||
## Addendum: Constitution-required idempotency (queued/scheduled jobs)
|
||
|
||
- [X] T033 [US3] Add overlap-prevention for ReconcileAdapterRunsJob so concurrent dispatch/schedule overlap cannot execute twice (lock/guard must be server-side)
|
||
|
||
---
|
||
|
||
## Dependencies & Execution Order
|
||
|
||
### User Story completion order
|
||
|
||
- US1 (P2) → US2 (P2) → US3 (P3) → US4 (P3)
|
||
|
||
### Why
|
||
|
||
- US1 establishes durable counters used by ops.
|
||
- US2 dedupe builds on the same identity/counter plumbing.
|
||
- US3 and US4 are independent after foundational primitives.
|
||
|
||
---
|
||
|
||
## Parallel execution examples
|
||
|
||
### US1
|
||
|
||
- T009 and T010 can run in parallel (same file, but split by responsibility).
|
||
|
||
### US2
|
||
|
||
- T015 and T016 can run in parallel.
|
||
- T019 and T020 can run in parallel.
|
||
|
||
### US3
|
||
|
||
- T023 and T024 can run in parallel.
|
||
|
||
### US4
|
||
|
||
- T028 can run in parallel with US3 implementation tasks.
|
||
|
||
---
|
||
|
||
## Implementation strategy (MVP)
|
||
|
||
- MVP scope: US1 only (Phase 3) after completing Phases 1–2.
|
||
- After MVP validation: implement US2 next to reduce operational risk.
|