TenantAtlas/specs/360-operationrun-canonical-cutover-cleanup/plan.md
ahmido 840c9bd28d refactor: rename ManagedEnvironment context badge to Environment context (#431)
Renames ManagedEnvironment context badge to Environment context as requested.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #431
2026-06-06 20:30:26 +00:00

15 KiB

Implementation Plan: OperationRun Canonical Cutover Cleanup

Branch: 360-operationrun-canonical-cutover-cleanup | Date: 2026-06-06 | Spec: specs/360-operationrun-canonical-cutover-cleanup/spec.md
Input: Feature specification from /specs/360-operationrun-canonical-cutover-cleanup/spec.md

Note: This plan follows the repo's Spec Kit preparation workflow, but this prep intentionally stops before application implementation.

Summary

Consolidate the merged Spec 359 runtime into one canonical OperationRun reconciliation foundation before any new adapter family is added. The plan keeps OperationRunService as the only reconciliation write seam, replaces growth-by-type-match with one bounded adapter extension seam, introduces canonical dispatch and correlation metadata, cuts current writers/readers over to canonical operation and related-artifact truth, and closes Spec 359 prep artifacts accurately.

Technical Context

Language/Version: PHP 8.4.15
Primary Dependencies: Laravel 12.52, Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1
Storage: PostgreSQL 16 (operation_runs, environment_reviews, existing related artifact tables only; no new schema)
Testing: Pest 4 Unit + Feature + Browser + PGSQL lane
Validation Lanes: fast-feedback, confidence, browser, pgsql
Target Platform: Laravel monolith in apps/platform
Project Type: web application / Laravel monolith
Performance Goals: no measurable runtime slowdown on normal queued dispatch or operations monitoring surfaces; no added polling or extra remote calls
Constraints: no new migration, no new persisted status column, no new panel/provider work, no asset changes, no legacy compatibility layer for pre-production history, no new business adapter families
Scale/Scope: bounded cleanup across the current restore/review-compose adapter seam, queue correlation, canonical type writes, and current operations/read-side surfaces

UI / Surface Guardrail Plan

  • Guardrail scope: changed surfaces
  • Affected routes/pages/actions/states/navigation/panel/provider surfaces:
    • /admin/workspaces/{workspace}/operations
    • /admin/workspaces/{workspace}/operations/{run}
    • existing review-start feedback inside App\Filament\Resources\EnvironmentReviewResource
  • No-impact class, if applicable: N/A
  • Native vs custom classification summary: native
  • Shared-family relevance: operations monitoring family, run detail family, review-start feedback family
  • State layers in scope: page, detail
  • Audience modes in scope: operator-MSP, support-platform
  • Decision/diagnostic/raw hierarchy plan: decision-first, diagnostics-second, support-raw-third
  • Raw/support gating plan: keep raw context and duplicate-error evidence on detail only
  • One-primary-action / duplicate-truth control: preserve one canonical inspect action and one canonical related-artifact link per surface; do not restate dispatch, reconciliation, and artifact truth in competing summaries
  • Handling modes by drift class or surface: review-mandatory
  • Repository-signal treatment: report-only unless implementation proves a materially new visible hierarchy
  • Special surface test profiles: monitoring-state-page, shared-detail-family
  • Required tests or manual smoke: functional-core, state-contract, manual-smoke
  • Exception path and spread control: none expected
  • Active feature PR close-out entry: Guardrail / Smoke Coverage
  • UI/Productization coverage decision: no new reachable UI surface; existing operations and review-start families only
  • Coverage artifacts to update: none expected
  • No-impact rationale: existing routes and surface families only; no new page, panel, navigation, or action model
  • Navigation / Filament provider-panel handling: checked no-impact rationale because rendered access paths stay the same
  • Screenshot or page-report need: no, unless implementation proves a materially new visible state hierarchy

Shared Pattern & System Fit

  • Cross-cutting feature marker: yes
  • Systems touched:
    • App\Services\OperationRunService
    • App\Services\AdapterRunReconciler
    • App\Support\Operations\Reconciliation\EnvironmentReviewComposeDecision
    • App\Support\OperationCatalog
    • App\Support\OperationRunType
    • App\Support\OperationRunLinks
    • App\Support\Ui\GovernanceArtifactTruth\ArtifactTruthPresenter
    • App\Jobs\Middleware\TrackOperationRun
    • App\Jobs\Concerns\BridgesFailedOperationRun
  • Shared abstractions reused: current OperationRunService lifecycle ownership, current operations monitoring/detail surfaces, current review-start feedback, current read-side link and artifact-truth helpers
  • New abstraction introduced? why?: one bounded adapter contract/registry or orchestrator plus one bounded correlation resolver are justified because the repo already has two real adapter consumers and currently inconsistent job-correlation rules
  • Why the existing abstraction was sufficient or insufficient: existing shared paths are sufficient for service-owned lifecycle writes and operator-facing surfaces, but insufficient for canonical adapter registration and canonical queued correlation truth
  • Bounded deviation / spread control: keep the new abstraction limited to the current restore and review-compose adapter cases and to one run-correlation contract; no universal business reconciliation engine

OperationRun UX Impact

  • Touches OperationRun start/completion/link UX?: yes
  • Central contract reused: OperationRunService, OperationUxPresenter, OperationRunLinks
  • Delegated UX behaviors: queued feedback, tenant/workspace-safe run links, related-artifact links, and terminal lifecycle ownership stay on the current shared paths
  • Surface-owned behavior kept local: review-start form inputs and review-specific secondary wording only
  • Queued DB-notification policy: unchanged explicit opt-in only
  • Terminal notification path: current central lifecycle mechanism
  • Exception path: none expected

Provider Boundary & Portability Fit

  • Shared provider/platform boundary touched?: no
  • Provider-owned seams: N/A
  • Platform-core seams: OperationRun, reconciliation metadata, dispatch metadata, operation catalog
  • Neutral platform terms / contracts preserved: operation, dispatch, correlation, reconciliation, related artifact
  • Retained provider-specific semantics and why: none
  • Bounded extraction or follow-up path: none

Constitution Check

GATE: Must pass before implementation planning and again before implementation begins.

  • Inventory-first: pass; no inventory or snapshot truth change
  • Read/write separation: pass; no new direct write path outside OperationRunService
  • Graph contract path: pass; no Graph work is added
  • Deterministic capabilities: pass; no capability derivation change
  • Workspace and tenant isolation: pass; adapter and reader resolution stay scoped to stored workspace and managed environment
  • Run observability: pass; this spec tightens OperationRun observability rather than widening it
  • Ops-UX lifecycle ownership: pass; status and outcome transitions stay service-owned
  • Proportionality / no premature abstraction: pass if the adapter and correlation extraction remain bounded to the two repo-real cases
  • Persisted truth / behavioral state: pass; no new table, column, or persisted state family
  • Shared pattern first: pass; reuse shared monitoring, run-link, artifact-truth, and service-owned lifecycle paths
  • Provider boundary: pass; entirely platform-core
  • UI/Productization coverage: pass; existing operator-facing surfaces only, with bounded browser smoke
  • Test governance: pass if Unit + Feature + Browser + PGSQL stay explicit and no heavy-governance family is added

Test Governance Check

  • Test purpose / classification by changed surface: Unit + Feature + Browser
  • Affected validation lanes: fast-feedback, confidence, browser, pgsql
  • Why this lane mix is the narrowest sufficient proof: adapter resolution and canonical metadata are low-cost Unit or Feature proof, PGSQL is required for duplicate-index behavior, and one Browser smoke is sufficient for existing operations surfaces
  • Narrowest proving command(s):
    • cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec360
    • cd apps/platform && ./vendor/bin/sail php vendor/bin/pest -c phpunit.pgsql.xml --filter=Spec360
    • cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec360OperationRunCanonicalCutoverSmokeTest.php
    • git diff --check
  • Fixture / helper / factory / seed / context cost risks: keep existing operation-run, workspace, environment, and review fixtures cheap by default; do not widen full-context helpers globally
  • Expensive defaults or shared helper growth introduced?: no
  • Heavy-family additions, promotions, or visibility changes: none
  • Surface-class relief / special coverage rule: named monitoring-state-page and shared-detail-family; no heavy-governance expansion
  • Closing validation and reviewer handoff: re-run the primary merge gate (Spec360, Spec359, Spec358, Spec360 PGSQL, Spec360 browser smoke) before merge, then run contextual regressions and finally the separately recorded external probes
  • Budget / baseline / trend follow-up: none expected
  • Review-stop questions: does the adapter extraction stay bounded, does dispatch truth stay shared, do readers prefer canonical related metadata, and do no new UI families appear
  • Escalation path: reject-or-split if implementation broadens into Spec 361 scope or new persistence
  • Active feature PR close-out entry: Guardrail / Smoke Coverage
  • Why no dedicated follow-up spec is needed: this spec is itself the dedicated cleanup slice that should land before Spec 361

Repo-Verified Runtime Surfaces Likely Affected

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/Services/EnvironmentReviews/EnvironmentReviewService.php
apps/platform/app/Support/Operations/Reconciliation/EnvironmentReviewComposeDecision.php
apps/platform/app/Support/OperationCatalog.php
apps/platform/app/Support/OperationRunType.php
apps/platform/app/Models/OperationRun.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

Technical Approach

  1. Convert the current AdapterRunReconciler growth path into one canonical extension seam. The implementation may keep the class name or split it into an orchestrator plus local contract types, but future adapters must register instead of expanding a central type match.
  2. Keep OperationRunService as the only reconciliation write owner. Reconciliation and dispatch metadata normalization should live there so jobs and adapters stay pure orchestrators or pure decisions.
  3. Move remaining review-compose duplicate and lineage finalization out of ComposeEnvironmentReviewJob. The job should load scope, call the adapter or decision seam, call the composer, and delegate failures back to the shared run lifecycle path.
  4. Introduce canonical context.dispatch on the shared dispatch seam. The contract must record job class, queue, connection, timestamp, correlation version, and run id without inventing unsupported queue job ids.
  5. Align runtime middleware and failed-job bridging around one correlation contract for the current OperationRun dispatch/failure-bridge path touched by this cutover. Collapse the current property scanning only on that bounded path; unrelated historical bulkRunId or runId seams remain out of scope.
  6. Cut the read side over to canonical reconciliation related metadata and canonical operation-type truth. Legacy fallbacks should be removed where they only protect pre-production history.

Risk Controls

  • Keep the adapter extraction bounded to the two current concrete cases.
  • Keep correlation cleanup bounded to TrackOperationRun, BridgesFailedOperationRun, and the directly touched OperationRunService::dispatchOrFail() path; do not widen into repo-wide job identity normalization.
  • Avoid new schema, state families, or compatibility shims.
  • Prefer additive helper extraction only where it replaces contradictory existing logic.
  • Keep operator-facing wording on existing surfaces only; do not open UI redesign scope.
  • Treat PGSQL proof as mandatory for duplicate-index sensitive paths.

Implementation Phases

Phase 1: Baseline and Close-Out Context

  • Freeze the merged Spec 359 baseline and the repo-verified drift that remains.
  • Update specs/359-.../tasks.md so the merge baseline, deferred Spec 360 items, and blocked PGSQL validation status are explicit.

Phase 2: Canonical Adapter and Write Seam

  • Add the canonical adapter contract or registry-orchestrator seam.
  • Keep OperationRunService as the only reconciliation write path and normalize context.reconciliation.

Phase 3: Job Ownership and Dispatch/Correlation Truth

  • Remove remaining review-compose business fallback from the job.
  • Add canonical context.dispatch.
  • Align middleware and failed-job bridging to one correlation rule.

Phase 4: Canonical Type and Reader Cutover

  • Reduce broad legacy alias inventory and touched write paths to canonical operation types.
  • Prefer context.reconciliation.related in link and artifact readers.
  • Keep operations surfaces calm and canonical.

Phase 5: Validation and Close-Out

  • Run Spec360, Spec359, Spec358, PGSQL, and the named bounded browser or review regressions.
  • Re-run the explicitly named external probes separately and record them as separate review signals instead of silently folding them into the primary merge gate.
  • Run pint --dirty and git diff --check.
  • Record the final cutover decisions in the active feature close-out.

Project Structure

Documentation (this feature)

specs/360-operationrun-canonical-cutover-cleanup/
├── spec.md
├── plan.md
├── tasks.md
└── checklists/
    └── requirements.md

Source Code (repository root)

apps/platform/
├── app/
├── database/
└── tests/

Assumptions

  • No additional preparation artifact beyond spec.md, plan.md, tasks.md, and checklists/requirements.md is required for this bounded cleanup.
  • The repo's current Prompt or Agent-based speckit plan/tasks/analyze flow is manual in this surface, so readiness is validated by explicit artifact review rather than a standalone local generator command.

Open Preparation Decision

The implementation may keep AdapterRunReconciler as the public orchestrator name or replace it with a more explicit adapter-registry/orchestrator pair, but the final shape must satisfy the same constraints:

  • one extension seam only
  • no growing type-match addition path
  • no direct write path outside OperationRunService
  • no new adapter family beyond restore and review-compose