# Implementation Plan: OperationRun Reconciliation Adapter Framework & Review Compose Adapter **Branch**: `359-operationrun-reconciliation-adapter-framework-review-compose-adapter` | **Date**: 2026-06-06 | **Spec**: `specs/359-operationrun-reconciliation-adapter-framework-review-compose-adapter/spec.md` **Input**: Feature specification from `specs/359-operationrun-reconciliation-adapter-framework-review-compose-adapter/spec.md` ## Summary Implement a narrow business-truth reconciliation seam for `OperationRun` that reuses existing service-owned lifecycle writes and existing review-compose start/monitoring UX. The slice introduces one typed adapter contract plus one `environment.review.compose` adapter, proves same-scope `EnvironmentReview` truth, recovers duplicate fingerprint collisions deterministically, and keeps restore-specific reconciliation behavior intact as existing context rather than reopening it as a second feature. This plan must stay smaller than a universal reconciliation engine. It extends current repo seams only where current review-compose truth cannot be proven safely by the existing scheduled stale-run reconciler or the hard-coded restore adapter. ## Technical Context **Language/Version**: PHP 8.4.15, Laravel 12.52, Filament 5.2.1, Livewire 4.1.4 **Primary Dependencies**: existing `OperationRunService`, `OperationRun`, `OperationCatalog`, current restore adapter reconciler, current review-compose services/jobs/resources, Pest 4.3 **Storage**: PostgreSQL `operation_runs` and `environment_reviews`; no schema change planned **Testing**: Pest Unit + Feature + one bounded Browser smoke; PGSQL lane required for duplicate-index/locking proof **Validation Lanes**: fast-feedback, confidence, pgsql, browser **Target Platform**: Laravel monolith in `apps/platform` **Project Type**: web application **Performance Goals**: reuse current DB-only monitoring posture, avoid new render-time Graph work, and keep adapter evaluation to scoped local DB reads only **Constraints**: no new `OperationRun` status/outcome field, no new review status family, no new panel/provider/asset change, no provider-boundary widening, no destructive cleanup, and no broad restore/report/evidence adapter expansion **Scale/Scope**: one new review-compose path on the existing adapter reconciliation seam plus the smallest local decision/result helper needed to make adapter reconciliation auditable and repeatable ## Likely Affected Repo Surfaces - Existing reconciliation and lifecycle seams: - `apps/platform/app/Services/OperationRunService.php` - `apps/platform/app/Models/OperationRun.php` - `apps/platform/app/Services/Operations/OperationLifecycleReconciler.php` - `apps/platform/app/Services/AdapterRunReconciler.php` - `apps/platform/app/Support/OperationCatalog.php` - `apps/platform/app/Support/OperationRunType.php` - `apps/platform/app/Support/OperationRunStatus.php` - `apps/platform/app/Support/OperationRunOutcome.php` - Existing review-compose runtime seams: - `apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewService.php` - `apps/platform/app/Jobs/ComposeEnvironmentReviewJob.php` - `apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewComposer.php` - `apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewFingerprint.php` - `apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewLifecycleService.php` - `apps/platform/app/Models/EnvironmentReview.php` - Existing operator-facing surfaces likely to consume richer metadata: - `apps/platform/app/Support/OpsUx/OperationUxPresenter.php` - `apps/platform/app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.php` - `apps/platform/app/Support/OperationRunLinks.php` - `apps/platform/app/Filament/Pages/Monitoring/Operations.php` - `apps/platform/app/Filament/Pages/Operations/TenantlessOperationRunViewer.php` - `apps/platform/app/Filament/Resources/OperationRunResource.php` - `apps/platform/app/Filament/Resources/EnvironmentReviewResource.php` - `apps/platform/app/Filament/Widgets/Dashboard/RecentOperations.php` - `apps/platform/app/Filament/System/Pages/Ops/Runs.php` - `apps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummaryBuilder.php` - `apps/platform/lang/en/localization.php` - `apps/platform/lang/de/localization.php` - Focused tests: - `apps/platform/tests/Unit/Support/Operations/Reconciliation/` - `apps/platform/tests/Feature/Operations/` - `apps/platform/tests/Feature/EnvironmentReview/` - `apps/platform/tests/Feature/Monitoring/` - `apps/platform/tests/Browser/` ## Domain And Data Implications - `operation_runs` remains the only persisted run-lifecycle truth. Reconciliation remains a context extension, not a new status model. - `environment_reviews` remains the only domain-truth source for review availability. The adapter proves truth from existing review rows only. - The partial unique index `environment_reviews_fingerprint_mutable_unique` remains the core duplicate-collision constraint. The feature must adapt to it, not replace it. - Existing mutable/superseded semantics remain authoritative: - mutable: `draft`, `ready`, `failed` - historical/terminal lineage: `published`, `archived`, `superseded` - No migration is planned. If implementation appears to need one, that is a scope alarm and should stop for review. ## UI / Surface Guardrail Plan - **Guardrail scope**: existing operator-facing monitoring surfaces plus existing review-start feedback - **Affected routes/pages/actions/states/navigation/panel/provider surfaces**: - `/admin/workspaces/{workspace}/operations` - `/admin/workspaces/{workspace}/operations/{run}` - `EnvironmentReviewResource` create/refresh notifications and open-link feedback - tenant dashboard recent-operations widget - system operations list - environment dashboard recent/attention summaries - **No-impact class, if applicable**: non-material existing-surface wording/state handling only - **Native vs custom classification summary**: native Filament surfaces plus existing action notifications - **Shared-family relevance**: monitoring-state messaging, reconciliation diagnostics, run-start feedback - **State layers in scope**: page, detail, action feedback - **Audience modes in scope**: operator-MSP, support-platform - **Decision/diagnostic/raw hierarchy plan**: decision-first reconciliation result, diagnostics second, raw evidence third - **Raw/support gating plan**: existing detail/raw context remains secondary and must never become the primary explanation - **One-primary-action / duplicate-truth control**: keep the existing open-run/open-review actions authoritative and avoid a second local “duplicate recovered” surface - **Handling modes by drift class or surface**: - review-compose succeeded from domain truth: `review-mandatory` - blocked/attention without safe proof: `review-mandatory` - any raw SQL/constraint leak: `hard-stop-candidate` - **Repository-signal treatment**: review-mandatory - **Special surface test profiles**: monitoring-state-page, shared-detail-family - **Required tests or manual smoke**: Unit + Feature + PGSQL + one bounded Browser smoke - **Exception path and spread control**: any move toward new operator-center UX, report/evidence adapter copy, or customer-facing surface changes is `reject-or-split` - **Active feature PR close-out entry**: Guardrail / Smoke Coverage - **UI/Productization coverage decision**: existing surface follow-through only - **Coverage artifacts to update**: none by default; update existing page reports only if final visible hierarchy materially changes - **No-impact rationale**: no route or page identity change - **Navigation / Filament provider-panel handling**: unchanged; provider registration stays in `apps/platform/bootstrap/providers.php` - **Screenshot or page-report need**: no new page-report identity; one bounded browser smoke screenshot is sufficient only if implementation materially changes visible wording hierarchy ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes - **Systems touched**: - scheduled reconciliation path - restore-specific adapter reconciliation precedent - review-compose start/complete flow - monitoring list/detail surfaces - review-create notifications - **Shared abstractions reused**: - `OperationRunService::updateRunWithReconciliation()` - `OperationRun::reconciliation()` - `OperationUxPresenter` - `OperationRunLinks` - `ArtifactTruthPresenter` - `EnvironmentReviewResource::executeCreateReview()` - **New abstraction introduced? why?**: yes; one local review-compose decision/result helper is introduced because the current restore-only adapter path is too hard-coded to absorb review fingerprint/scope/supersession proof safely. - **Why the existing abstraction was sufficient or insufficient**: current abstractions already own run lifecycle and generic stale truth, but `AdapterRunReconciler` currently only knows `restore.execute`; this slice extends that seam rather than adding a parallel registry. - **Bounded deviation / spread control**: keep the new helper local to adapter reconciliation and explicitly bounded to review-compose plus existing restore context ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: yes - **Central contract reused**: current service-owned lifecycle plus current review-create queued-toast/open-run path - **Delegated UX behaviors**: - create/refresh keeps the current queued toast and `Open operation` link - adapter completion writes terminal truth through `OperationRunService` - operations list/detail continue to read one reconciliation metadata shape - **Surface-owned behavior kept local**: only review-create body copy and any additional review-available/recovered wording - **Queued DB-notification policy**: unchanged - **Terminal notification path**: unchanged central lifecycle mechanism - **Exception path**: none ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: no - **Provider-owned seams**: N/A - **Platform-core seams**: `OperationRun` lifecycle truth and `EnvironmentReview` artifact truth only - **Neutral platform terms / contracts preserved**: `operation`, `reconciliation`, `review`, `workspace`, `managed environment` - **Retained provider-specific semantics and why**: none - **Bounded extraction or follow-up path**: none ## Authorization, Audit, And Observability - Existing workspace-first and managed-environment entitlement checks remain unchanged. - Adapter lookup must not widen who can see or use a review; it only determines which local record may prove the run. - `OperationRunService` remains the owner of terminal audit emission. - Reconciliation evidence must stay bounded to safe identifiers and state: - allowed: workspace ID, managed environment ID, review ID, review status, fingerprint hash, considered review IDs, timestamps - forbidden: raw Graph payloads, signed URLs, tokens, raw SQL errors, full snapshot blobs - Optional operational logging may emit adapter name, run ID, type, decision, and related review ID only. ## Constitution Check - Inventory-first: unchanged; `EnvironmentReview` remains the local artifact truth and still derives from anchored evidence snapshots. - Read/write separation: adapter reconciliation mutates only `OperationRun`, not the provider or remote state. - Graph contract path: unchanged; no Graph calls are introduced. - Deterministic capabilities: unchanged; current capability checks remain authoritative. - Workspace and tenant isolation: unchanged and still mandatory for both runs and reviews. - Run observability: strengthened; late or duplicate review-compose work remains visible on `OperationRun` instead of being silently inferred elsewhere. - Proportionality / anti-bloat: pass only if the adapter contract stays narrow and does not become a universal business-reconciliation engine. - No premature abstraction: this is allowed only because queue correctness and auditability already justify a typed seam, and the repo already ships one restore-specific adapter precedent. - Persisted truth: no new tables or persisted status families. - Shared pattern first: reuse current run lifecycle, current monitoring/detail surfaces, and current review-start feedback. - Filament v5 / Livewire v4 posture: unchanged; no panel/provider or asset work is allowed. ## Test Governance Check - **Test purpose / classification by changed surface**: - Unit: reconciliation decisions, supported-type handling, adapter same-scope proof - Feature: service/job/idempotency/reconciliation metadata flow - Browser: visible operations/review wording smoke - **Affected validation lanes**: fast-feedback, confidence, pgsql, browser - **Why this lane mix is the narrowest sufficient proof**: duplicate fingerprint recovery depends on a PGSQL partial unique index and scope-safe DB truth, while visible monitoring wording needs only one bounded browser smoke rather than a broad productization run. - **Narrowest proving command(s)**: - `cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec359` - `cd apps/platform && ./vendor/bin/sail php vendor/bin/pest -c phpunit.pgsql.xml --filter=Spec359` - `cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec358` - `git diff --check` - **Fixture / helper / factory / seed / context cost risks**: reuse existing review/evidence/run factories; do not widen default tenant/workspace setup - **Expensive defaults or shared helper growth introduced?**: none planned - **Heavy-family additions, promotions, or visibility changes**: none - **Surface-class relief / special coverage rule**: monitoring-state-page plus shared-detail-family; one explicit browser smoke only - **Closing validation and reviewer handoff**: reviewers should compare ready-review reuse, ambiguous duplicate collisions, repeated create/refresh triggers, and visible operations detail wording before merge - **Budget / baseline / trend follow-up**: none expected beyond feature-local tests - **Review-stop questions**: - Did implementation add a second persisted status shape? - Did implementation widen into report/evidence/restore business reconciliation? - Can any duplicate/superseded case still remain queued/running forever? - Does any visible copy leak SQL/constraint wording? - **Escalation path**: `reject-or-split` for universal reconciliation scope growth - **Active feature PR close-out entry**: Guardrail / Smoke Coverage - **Why no dedicated follow-up spec is needed**: this slice is already the follow-through over Spec 358 and must remain bounded to review-compose truth only ## Implementation Phases ### Phase 1 — Lock repo truth and convergence boundaries - Reconfirm the current scheduled reconciler, restore-specific adapter reconciler, and review-compose seams. - Decide whether the existing restore adapter stays as-is or is bridged behind the new contract without behavioral change. - Freeze the current visible operations/review feedback vocabulary that must remain consistent. ### Phase 2 — Add the narrow reconciliation contract - Extend the existing adapter reconciliation seam with one local review-compose decision/result helper and explicit supported-type handling. - Extend or wrap `OperationRunService::updateRunWithReconciliation()` so richer metadata can be merged idempotently. - Keep all persistence shapes unchanged. ### Phase 3 — Implement review-compose proof and recovery - Add a same-scope review-compose adapter that proves ready/published review truth and fails closed on ambiguity. - Integrate duplicate recovery and pre/post compose checks into `ComposeEnvironmentReviewJob`. - Tighten `EnvironmentReviewService` repeated-trigger behavior so active review truth or active run truth is reused rather than multiplied. ### Phase 4 — Retrofit existing operator surfaces - Keep current monitoring list/detail surfaces authoritative for reconciled review-compose explanation. - Reuse current review-start feedback and current `Open operation` / `View review` patterns. - Add bounded EN/DE copy only where the existing language is too generic or too technical. ### Phase 5 — Validate and hand off - Add Unit + Feature + PGSQL + Browser proof. - Re-run Spec 358 plus the named review/report regressions. - Record final guardrail, smoke, and bounded-scope notes in the feature close-out entry. ## Risks and Mitigations - **Framework creep**: mitigate by forbidding new adapter families and by treating restore/report/evidence follow-through as out of scope. - **Scope-safety mistakes**: mitigate with explicit cross-workspace, cross-environment, and wrong-fingerprint negative tests. - **PGSQL-only blind spots**: mitigate with an explicit `phpunit.pgsql.xml` lane for duplicate-index and lock behavior. - **Visible copy drift**: mitigate by keeping all user-facing wording on current operations/review paths and adding one bounded browser smoke. ## Project Structure ### Documentation ```text specs/359-operationrun-reconciliation-adapter-framework-review-compose-adapter/ ├── spec.md ├── plan.md ├── tasks.md └── checklists/ └── requirements.md ``` ### Likely Runtime Structure ```text apps/platform/app/Services/ ├── OperationRunService.php ├── AdapterRunReconciler.php └── EnvironmentReviews/ ├── EnvironmentReviewService.php ├── EnvironmentReviewComposer.php ├── EnvironmentReviewFingerprint.php └── EnvironmentReviewLifecycleService.php apps/platform/app/Jobs/ └── ComposeEnvironmentReviewJob.php apps/platform/app/Filament/ ├── Pages/Monitoring/Operations.php ├── Pages/Operations/TenantlessOperationRunViewer.php └── Resources/ ├── OperationRunResource.php └── EnvironmentReviewResource.php ```