# Tasks: OperationRun Canonical Cutover Cleanup **Input**: `specs/360-operationrun-canonical-cutover-cleanup/spec.md`, `plan.md`, and `checklists/requirements.md` **Prerequisites**: `spec.md` and `plan.md` **Tests**: REQUIRED (Pest). Keep proof bounded to Unit + Feature + PGSQL + one explicit Browser smoke. **Operations**: Reuse current `OperationRun` lifecycle ownership. No new run status column, no new queue family, no new schema, and no destructive cleanup. **RBAC**: Reuse current workspace-first run access plus current review capabilities. No new capability strings, no widened route access, and no cross-scope artifact resolution. **Shared Pattern Reuse**: Reuse `OperationRunService`, current operations surfaces, `OperationRunLinks`, `ArtifactTruthPresenter`, and current review-start feedback. Introduce only one bounded adapter contract/registry-orchestrator seam plus one bounded run-correlation resolver. **Filament / Panel Guardrails**: Filament remains v5 on Livewire v4. Provider registration stays in `apps/platform/bootstrap/providers.php`. No new panel, route family, or asset strategy is allowed. **Organization**: Tasks are grouped by user story so the adapter seam, dispatch/correlation truth, read-side canonicalization, and spec-closeout work remain independently reviewable. ## Repo Baseline At Prep Time - **Branch**: `360-operationrun-canonical-cutover-cleanup` - **HEAD**: `3a750726 feat: implement review compose reconciliation adapter (spec 359) (#430)` - **`git status --short --branch` before Spec 360 prep**: clean on `platform-dev`; Spec Kit created this feature branch and copied the spec/plan templates - **Spec 359 merge baseline**: merged runtime behavior is the functional starting point; PGSQL validation remained locally blocked at merge time - **Relevant runtime surfaces**: - `apps/platform/app/Services/AdapterRunReconciler.php` - `apps/platform/app/Services/OperationRunService.php` - `apps/platform/app/Jobs/ComposeEnvironmentReviewJob.php` - `apps/platform/app/Jobs/Middleware/TrackOperationRun.php` - `apps/platform/app/Jobs/Concerns/BridgesFailedOperationRun.php` - `apps/platform/app/Support/Operations/Reconciliation/EnvironmentReviewComposeDecision.php` - `apps/platform/app/Support/OperationCatalog.php` - `apps/platform/app/Support/OperationRunType.php` - `apps/platform/app/Support/OperationRunLinks.php` - `apps/platform/app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php` - `apps/platform/app/Support/OpsUx/OperationUxPresenter.php` - `apps/platform/app/Filament/Resources/OperationRunResource.php` - `apps/platform/app/Filament/Pages/Operations/TenantlessOperationRunViewer.php` - `apps/platform/app/Filament/Resources/EnvironmentReviewResource.php` - `apps/platform/database/factories/OperationRunFactory.php` - `apps/platform/tests/Unit/Support/OperationTypeResolutionTest.php` - **Completed-spec context only**: Spec 358 is the generic queue-truth baseline; do not rewrite its historical readiness or validation record - **Historical numbering note**: older references to another placeholder `Spec 360` in `specs/355-platform-sellable-smoke-matrix/` are context only and must not be treated as an existing spec package ## Test Governance Checklist - [x] Lane assignment is named and is the narrowest sufficient proof for the changed behavior. - [x] New or changed tests stay in the smallest honest family, and the Browser or PGSQL additions remain explicit. - [x] Shared helpers, factories, seeds, fixtures, and context defaults stay cheap by default; any widening is isolated or documented. - [x] Planned validation commands cover the change without widening into unrelated lane cost. - [x] The declared monitoring/detail surface profile is explicit. - [x] Any material budget, baseline, trend, or escalation note is recorded in the active feature close-out. ## Phase 1: Setup (Repo Truth Inventory) **Purpose**: confirm the merged Spec 359 baseline, the current cutover gaps, and the exact repo surfaces before runtime edits begin. - [ ] T001 Re-read `spec.md`, `plan.md`, `checklists/requirements.md`, `.specify/memory/constitution.md`, `docs/ai-coding-rules.md`, `docs/architecture-guidelines.md`, `docs/testing-guidelines.md`, `docs/security-guidelines.md`, `docs/filament-guidelines.md`, and `specs/358-operationrun-queue-truth-foundation/{spec,plan,tasks}.md` plus `specs/359-operationrun-reconciliation-adapter-framework-review-compose-adapter/{spec,plan,tasks}.md` together before touching runtime code. - [ ] T002 [P] Confirm the current reconciliation and write seams in `apps/platform/app/Services/AdapterRunReconciler.php`, `apps/platform/app/Services/OperationRunService.php`, `apps/platform/app/Models/OperationRun.php`, and `apps/platform/app/Support/Operations/Reconciliation/EnvironmentReviewComposeDecision.php`. - [ ] T003 [P] Confirm the current queue correlation seams in `apps/platform/app/Jobs/Middleware/TrackOperationRun.php`, `apps/platform/app/Jobs/Concerns/BridgesFailedOperationRun.php`, and the job classes that currently expose `operationRunId`, `operationRun`, or other correlation properties. - [ ] T004 [P] Confirm the current canonical type and read-side seams in `apps/platform/app/Support/OperationCatalog.php`, `apps/platform/app/Support/OperationRunType.php`, `apps/platform/app/Support/OperationRunLinks.php`, `apps/platform/app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php`, and `apps/platform/database/factories/OperationRunFactory.php`. - [ ] T005 Confirm that no new schema, no new panel/provider path, no new asset registration, and no new business adapter family are required; record any tension as `reject-or-split` instead of silently widening scope. - [x] T005A Update `specs/359-operationrun-reconciliation-adapter-framework-review-compose-adapter/tasks.md` so the merged baseline, blocked PGSQL note, and deferred Spec 360 follow-through are explicit; completed during Spec 360 prep. --- ## Phase 2: Foundational (Canonical Adapter and Service-Owned Metadata) **Purpose**: settle one canonical adapter extension seam and keep all reconciliation writes in `OperationRunService` before touching jobs or readers. **Critical**: no user-story runtime work should begin until this phase is complete. - [ ] T006 [P] Add failing Unit coverage in `apps/platform/tests/Unit/Support/Operations/Reconciliation/Spec360CanonicalAdapterRegistryTest.php` for adapter resolution of `restore.execute`, `environment.review.compose`, and unsupported types. - [ ] T007 [P] Add failing Unit coverage in `apps/platform/tests/Unit/Support/Operations/Reconciliation/Spec360ReconciliationContextFormatTest.php` for canonical `context.reconciliation` shape, idempotent merge behavior, previous status/outcome preservation, and related metadata normalization. - [ ] T008 Introduce the canonical adapter contract and registration or orchestration seam under `apps/platform/app/Support/Operations/Reconciliation/` and refactor `apps/platform/app/Services/AdapterRunReconciler.php` so future adapters register instead of expanding a central `match`. - [ ] T009 Extend `apps/platform/app/Services/OperationRunService.php` so `updateRunWithReconciliation()` writes only the canonical `context.reconciliation` payload, normalizes `related.type` and `related.id`, and removes duplicate compatibility fields that are no longer justified. - [ ] T010 Keep restore behavior intact by moving `restore.execute` onto the same canonical adapter seam without broadening restore business logic or introducing a second write path. - [ ] T011 Update or add focused Unit coverage to prove adapter-owned paths cannot persist reconciliation state directly outside `OperationRunService`. **Checkpoint**: one canonical adapter extension seam exists, `OperationRunService` still owns lifecycle writes, and current restore behavior remains functionally intact. --- ## Phase 3: User Story 1 - Canonicalize the adapter-owned reconciliation seam (Priority: P1) **Goal**: review-compose reconciliation becomes fully adapter or decision owned, and `ComposeEnvironmentReviewJob` becomes orchestration only. **Independent Test**: run focused Unit and Feature coverage showing that review-compose decisions finalize through the canonical adapter seam and that the job no longer owns business reconciliation logic. ### Tests for User Story 1 - [ ] T012 [P] [US1] Add `apps/platform/tests/Feature/Operations/Spec360CanonicalReconciliationCutoverTest.php` covering adapter-owned review-compose finalization, unsupported handling, and service-owned reconciliation writes. - [ ] T013 [P] [US1] Add or extend focused duplicate and lineage coverage in `apps/platform/tests/Feature/EnvironmentReview/Spec360ReviewComposeAdapterOwnershipTest.php` so duplicate fingerprint recovery and superseded review lineages prove the adapter-owned path rather than job-local fallback behavior. ### Implementation for User Story 1 - [ ] T014 [US1] Refactor `apps/platform/app/Jobs/ComposeEnvironmentReviewJob.php` so it loads scope, delegates reconciliation decisions, delegates composition, and never writes business reconciliation metadata directly. - [ ] T015 [US1] Keep review-compose business truth inside `apps/platform/app/Support/Operations/Reconciliation/EnvironmentReviewComposeDecision.php` and any new local adapter class under `apps/platform/app/Support/Operations/Reconciliation/`, including duplicate recovery, ambiguous lineage, and scope-safety decisions. - [ ] T016 [US1] Keep `apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewService.php` and `apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewComposer.php` free of direct `OperationRun` reconciliation mutation and broad adapter knowledge. - [ ] T017 [US1] Ensure duplicate fingerprint recovery still ends in deterministic succeeded, blocked, or attention-required outcomes without ghost runs and without raw SQL becoming primary operator-facing truth. **Checkpoint**: review-compose reconciliation is fully adapter-owned and the job is orchestration only. --- ## Phase 4: User Story 2 - Align queued dispatch and failed-job correlation truth (Priority: P1) **Goal**: queued dispatch metadata and failed-job correlation resolve through one canonical contract. **Independent Test**: run focused Unit and Feature coverage showing that queued runs record canonical `context.dispatch` and that middleware plus failed-job bridging resolve the same `OperationRun`. ### Tests for User Story 2 - [ ] T018 [P] [US2] Add `apps/platform/tests/Unit/Support/OperationRunDispatchContextTest.php` for canonical `context.dispatch` keys, no synthetic job id, and canonical correlation version behavior. - [ ] T019 [P] [US2] Add `apps/platform/tests/Feature/Operations/Spec360DispatchCorrelationTest.php` covering shared correlation between `TrackOperationRun`, `BridgesFailedOperationRun`, and `OperationRunService::dispatchOrFail()`. - [ ] T020 [P] [US2] Add PGSQL-sensitive duplicate or lock-aware follow-through to the Spec360 feature coverage where queue correlation or duplicate recovery depends on partial unique-index truth. ### Implementation for User Story 2 - [ ] T021 [US2] Extend `apps/platform/app/Services/OperationRunService.php` so `dispatchOrFail()` or the shared dispatch seam writes canonical `context.dispatch` metadata with `job_class`, `queue`, `connection`, `dispatched_at`, `correlation_version`, and `operation_run_id`. - [ ] T022 [US2] Introduce one shared run-correlation resolver or contract under `apps/platform/app/Jobs/` or `apps/platform/app/Support/Operations/` and update only `apps/platform/app/Jobs/Middleware/TrackOperationRun.php` plus `apps/platform/app/Jobs/Concerns/BridgesFailedOperationRun.php` to use it. - [ ] T023 [US2] Normalize only the directly touched `OperationRunService::dispatchOrFail()` lifecycle path to the canonical `operationRunId` or equivalent shared correlation contract, and remove hidden fallback property scanning there where it is no longer justified. - [ ] T024 [US2] Ensure unsupported or out-of-scope jobs fail closed: they may skip correlation cleanly, but they must not claim a wrong `OperationRun`, invent orphan semantics from missing queue ids, or pull unrelated `bulkRunId` or `runId` cleanup into this spec. **Checkpoint**: dispatch metadata is canonical and middleware plus failed-job bridging share one correlation rule. --- ## Phase 5: User Story 3 - Cut readers and operation-type truth over to canonical metadata (Priority: P2) **Goal**: readers, writers, and operator-facing copy rely on canonical related metadata and canonical operation-type values instead of broad legacy fallback behavior. **Independent Test**: run focused Unit, Feature, and one bounded Browser smoke to prove canonical type writes, canonical related metadata resolution, and calm operator wording on existing operations surfaces. ### Tests for User Story 3 - [ ] T025 [P] [US3] Add `apps/platform/tests/Unit/Support/OperationTypeCanonicalizationTest.php` or extend `apps/platform/tests/Unit/Support/OperationTypeResolutionTest.php` so current write paths and read-side alias inventory reflect the new canonical-only posture. - [ ] T026 [P] [US3] Add or extend focused read-side coverage for canonical related metadata in `apps/platform/tests/Feature/Operations/Spec360CanonicalReconciliationCutoverTest.php` or a companion feature file that exercises `OperationRunLinks` and `ArtifactTruthPresenter`. - [ ] T027 [P] [US3] Add `apps/platform/tests/Browser/Spec360OperationRunCanonicalCutoverSmokeTest.php` covering reconciled review-compose, stale queue truth from Spec 358, and canonical related review link behavior on the existing operations surfaces. ### Implementation for User Story 3 - [ ] T028 [US3] Update `apps/platform/app/Support/OperationCatalog.php`, `apps/platform/app/Support/OperationRunType.php`, `apps/platform/app/Models/OperationRun.php`, and `apps/platform/database/factories/OperationRunFactory.php` so touched writers use canonical operation types and unnecessary alias compatibility is removed or explicitly justified. - [ ] T029 [US3] Update `apps/platform/app/Support/OperationRunLinks.php` and `apps/platform/app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php` to prefer `context.reconciliation.related` before falling back to historical `operation_run_id` linkage, removing the fallback where pre-production history is the only reason it exists. - [ ] T030 [US3] Update `apps/platform/app/Support/OpsUx/OperationUxPresenter.php`, `apps/platform/app/Filament/Resources/OperationRunResource.php`, `apps/platform/app/Filament/Pages/Operations/TenantlessOperationRunViewer.php`, and `apps/platform/app/Filament/Resources/EnvironmentReviewResource.php` only as needed so existing operator surfaces stay calm and canonical. **Checkpoint**: touched writers are canonical-only, readers prefer canonical related metadata, and existing operations surfaces explain the cutover calmly. --- ## Phase 6: Polish & Validation - [ ] T032 [P] Refresh `spec.md`, `plan.md`, and `checklists/requirements.md` only if implementation proves a thinner or broader touched-file boundary than this prep package. - [ ] T033 [P] Run the primary in-scope fast-feedback or confidence gate: - `cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec360` - `cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec359` - `cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec358` - [ ] T034 [P] Run `cd apps/platform && ./vendor/bin/sail php vendor/bin/pest -c phpunit.pgsql.xml --filter=Spec360`. - [ ] T035 [P] Run the primary in-scope browser smoke: - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec360OperationRunCanonicalCutoverSmokeTest.php` - [ ] T036 [P] Run the bounded contextual review/report regressions from the active spec: - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/CustomerReviewWorkspaceSmokeTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec357ReportProfilesSmokeTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ReviewPack/Spec357RenderedReportProfileTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ReviewPack/ReviewPackDownloadTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ReviewPack/EnvironmentReviewDerivedReviewPackTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ReviewPack/EnvironmentReviewExecutivePackTest.php` - [ ] T037A [P] Run the known external probes separately and record them explicitly instead of silently folding them into the primary merge gate: - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec347ReviewPackOutputReadinessSmokeTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/EnvironmentReviewHeaderDisciplineTest.php` - [ ] T038 [P] Run `cd apps/platform && ./vendor/bin/pint --dirty`. - [ ] T039 [P] Run `git diff --check`. - [ ] T040 [P] Record the final adapter contract shape, dispatch contract shape, correlation rule, alias-retirement decision, and bounded UI wording outcome in the active feature close-out entry `Guardrail / Smoke Coverage`. --- ## Dependencies & Execution Order ### Phase Dependencies - **Setup (Phase 1)**: no dependencies - **Foundational (Phase 2)**: depends on Setup and blocks all story work - **US1 (Phase 3)**: depends on Foundational completion - **US2 (Phase 4)**: depends on Foundational completion and should land before broad reader cleanup - **US3 (Phase 5)**: depends on US1 and US2 because canonical related metadata and canonical type truth rely on the settled adapter and dispatch contracts - **Polish (Phase 6)**: depends on all desired user stories ### Parallel Opportunities - `T002`, `T003`, and `T004` can run in parallel. - `T006` and `T007` can run in parallel. - `T012` and `T013` can run in parallel. - `T018`, `T019`, and `T020` can run in parallel. - `T025`, `T026`, and `T027` can run in parallel. - `T033` through `T039` can run in parallel after implementation stabilizes, but the primary merge gate should be read out separately from contextual regressions and external probes. ### Implementation Strategy 1. Freeze the merged Spec 359 baseline and remove misleading artifact drift first. 2. Land the canonical adapter and service-owned metadata seam before job or reader cleanup. 3. Land dispatch and failed-job correlation on one contract before cutting readers and type writes over. 4. Finish with canonical related-metadata readers, calm operator wording, and the bounded validation suite. ## Non-Goals / Must-Not-Do - [ ] NT001 Do not add a new `reconciled` status column, boolean, or separate `OperationRun` truth table. - [ ] NT002 Do not add report, evidence, sync, backup, restore, or alert delivery business adapters in this feature. - [ ] NT003 Do not add a new queue/job family, a second operator-center UI, or a speculative provider framework. - [ ] NT004 Do not add compatibility shims or dual-write logic solely to preserve pre-production historical aliases or old fixtures. - [ ] NT005 Do not expose raw SQL, duplicate-key, or low-level framework error wording on operator-primary surfaces.