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
18 KiB
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.phpapps/platform/app/Models/OperationRun.phpapps/platform/app/Services/Operations/OperationLifecycleReconciler.phpapps/platform/app/Services/AdapterRunReconciler.phpapps/platform/app/Support/OperationCatalog.phpapps/platform/app/Support/OperationRunType.phpapps/platform/app/Support/OperationRunStatus.phpapps/platform/app/Support/OperationRunOutcome.php
- Existing review-compose runtime seams:
apps/platform/app/Services/EnvironmentReviews/EnvironmentReviewService.phpapps/platform/app/Jobs/ComposeEnvironmentReviewJob.phpapps/platform/app/Services/EnvironmentReviews/EnvironmentReviewComposer.phpapps/platform/app/Services/EnvironmentReviews/EnvironmentReviewFingerprint.phpapps/platform/app/Services/EnvironmentReviews/EnvironmentReviewLifecycleService.phpapps/platform/app/Models/EnvironmentReview.php
- Existing operator-facing surfaces likely to consume richer metadata:
apps/platform/app/Support/OpsUx/OperationUxPresenter.phpapps/platform/app/Support/Ui/GovernanceArtifactTruth/ArtifactTruthPresenter.phpapps/platform/app/Support/OperationRunLinks.phpapps/platform/app/Filament/Pages/Monitoring/Operations.phpapps/platform/app/Filament/Pages/Operations/TenantlessOperationRunViewer.phpapps/platform/app/Filament/Resources/OperationRunResource.phpapps/platform/app/Filament/Resources/EnvironmentReviewResource.phpapps/platform/app/Filament/Widgets/Dashboard/RecentOperations.phpapps/platform/app/Filament/System/Pages/Ops/Runs.phpapps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummaryBuilder.phpapps/platform/lang/en/localization.phpapps/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_runsremains the only persisted run-lifecycle truth. Reconciliation remains a context extension, not a new status model.environment_reviewsremains 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_uniqueremains 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
- mutable:
- 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}EnvironmentReviewResourcecreate/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
- review-compose succeeded from domain truth:
- 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()OperationUxPresenterOperationRunLinksArtifactTruthPresenterEnvironmentReviewResource::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
AdapterRunReconcilercurrently only knowsrestore.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 operationlink - adapter completion writes terminal truth through
OperationRunService - operations list/detail continue to read one reconciliation metadata shape
- create/refresh keeps the current queued toast and
- 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:
OperationRunlifecycle truth andEnvironmentReviewartifact 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.
OperationRunServiceremains 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;
EnvironmentReviewremains 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
OperationRuninstead 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=Spec359cd apps/platform && ./vendor/bin/sail php vendor/bin/pest -c phpunit.pgsql.xml --filter=Spec359cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec358git 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-splitfor 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
EnvironmentReviewServicerepeated-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 reviewpatterns. - 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.xmllane 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
specs/359-operationrun-reconciliation-adapter-framework-review-compose-adapter/
├── spec.md
├── plan.md
├── tasks.md
└── checklists/
└── requirements.md
Likely Runtime Structure
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