TenantAtlas/specs/359-operationrun-reconciliation-adapter-framework-review-compose-adapter/plan.md
ahmido 3a750726fd feat: implement review compose reconciliation adapter (spec 359) (#430)
Spec 359: add a narrow review-compose reconciliation path, deterministic duplicate/superseded recovery, shared review truth resolution, and bounded unit/feature/browser coverage. PGSQL validation remains locally blocked because the pgsql host/Docker runtime was unavailable.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #430
2026-06-06 14:58:16 +00:00

274 lines
18 KiB
Markdown

# 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
```