TenantAtlas/specs/096-ops-polish-assignment-dedupe-system-tracking/tasks.md

8.8 KiB
Raw Blame History

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.

  • T001 Fix duplicated FR numbering in specs/096-ops-polish-assignment-dedupe-system-tracking/spec.md
  • 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.

  • T003 Add operation label for ops.reconcile_adapter_runs in app/Support/OperationCatalog.php
  • T004 Add expected duration for ops.reconcile_adapter_runs in app/Support/OperationCatalog.php
  • 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)
  • T006 Implement a stable, non-secret fingerprint helper for assignment job identity in app/Support/OpsUx/AssignmentJobFingerprint.php
  • T007 [P] Wire FetchAssignmentsJob identity inputs to use AssignmentJobFingerprint in app/Jobs/FetchAssignmentsJob.php
  • 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)

  • T009 [P] [US1] Add fetch summary persistence test in tests/Feature/Operations/AssignmentRunSummaryCountsTest.php
  • T010 [P] [US1] Add restore summary persistence test in tests/Feature/Operations/AssignmentRunSummaryCountsTest.php

Implementation

  • T011 [US1] Persist terminal summary counts for fetch runs in app/Jobs/FetchAssignmentsJob.php via app/Services/OperationRunService.php::updateRun(...)
  • T012 [US1] Persist terminal summary counts for restore runs in app/Jobs/RestoreAssignmentsJob.php via app/Services/OperationRunService.php::updateRun(...)
  • T013 [US1] Ensure summary counts reflect final attempt (overwrite on completion) in app/Services/OperationRunService.php usage from app/Jobs/FetchAssignmentsJob.php
  • 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)

  • T015 [P] [US2] Add dedupe test for fetch job in tests/Feature/Operations/AssignmentJobDedupeTest.php
  • T016 [P] [US2] Add dedupe test for restore job in tests/Feature/Operations/AssignmentJobDedupeTest.php

Implementation

  • T017 [US2] Implement dispatch-time dedupe (reuse active OperationRun) for fetch in app/Jobs/FetchAssignmentsJob.php using app/Services/OperationRunService.php::ensureRunWithIdentity(...)
  • T018 [US2] Implement dispatch-time dedupe (reuse active OperationRun) for restore in app/Jobs/RestoreAssignmentsJob.php using app/Services/OperationRunService.php::ensureRunWithIdentity(...)
  • T019 [US2] Implement execute-time guard (skip when not canonical run) for fetch in app/Jobs/FetchAssignmentsJob.php
  • T020 [US2] Implement execute-time guard (skip when not canonical run) for restore in app/Jobs/RestoreAssignmentsJob.php
  • 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
  • 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)

  • T023 [P] [US3] Add reconcile job success tracking test in tests/Feature/Operations/ReconcileAdapterRunsJobTrackingTest.php
  • T024 [P] [US3] Add reconcile job failure tracking test in tests/Feature/Operations/ReconcileAdapterRunsJobTrackingTest.php

Implementation

  • T025 [US3] Create/reuse workspace-scoped run for housekeeping in app/Jobs/ReconcileAdapterRunsJob.php via app/Services/OperationRunService.php::ensureWorkspaceRunWithIdentity(...)
  • T026 [US3] Persist terminal outcome + sanitized failure summary for housekeeping in app/Jobs/ReconcileAdapterRunsJob.php using app/Services/OperationRunService.php::updateRun(...)
  • 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)

  • T028 [P] [US4] Add seed external_id UUID test in tests/Feature/Seed/PoliciesSeederExternalIdTest.php

Implementation

  • T029 [US4] Generate UUID v4 external_id for seed tenant in database/seeders/PoliciesSeeder.php (do not reuse INTUNE_TENANT_ID)
  • T034 [US4] Ensure seed workflow sets workspace_id for seeded tenant + policies to satisfy NOT NULL constraints in database/seeders/PoliciesSeeder.php
  • 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.

  • T030 Run formatter on changed files (app/, database/, tests/**) via vendor/bin/sail bin pint --dirty
  • T031 Run spec-focused tests in tests/Feature/Operations/AssignmentRunSummaryCountsTest.php and tests/Feature/Operations/AssignmentJobDedupeTest.php
  • T032 Run spec-focused tests in tests/Feature/Operations/ReconcileAdapterRunsJobTrackingTest.php and tests/Feature/Seed/PoliciesSeederExternalIdTest.php

Addendum: Constitution-required idempotency (queued/scheduled jobs)

  • 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 12.
  • After MVP validation: implement US2 next to reduce operational risk.