# Implementation Plan: Spec 386 - Review Publication Resolution Workflow v1 **Branch**: `386-review-publication-resolution-workflow-v1` | **Date**: 2026-06-18 | **Spec**: [spec.md](./spec.md) **Input**: Feature specification from `/specs/386-review-publication-resolution-workflow-v1/spec.md` ## Summary Create a bounded, review-publication-specific resolution workflow for blocked Environment Reviews. The implementation should add narrow case/step persistence, derive a step plan from existing review/evidence/report/review-pack readiness, execute only source-owned domain actions, link OperationRun and artifact proof, support pause/resume/currentness, audit lifecycle events, and keep customer-facing surfaces free of internal resolution details. The plan explicitly excludes a generic workflow engine, top-level navigation, global search, CRUD resource exposure, auto-publish behavior, cross-domain adapters, customer self-resolution, and generic proof/currentness infrastructure. ## Technical Context **Language/Version**: PHP 8.4.15 **Primary Dependencies**: Laravel 12.52.0, Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1, PostgreSQL via Sail/Dokploy **Storage**: New review-publication-specific case/step tables plus existing `EnvironmentReview`, `EvidenceSnapshot`, `StoredReport`, `ReviewPack`, and `OperationRun` truth. **Testing**: Pest Unit, Feature, Filament/Livewire Feature, PostgreSQL migration/constraint lane, and one bounded Browser smoke. **Validation Lanes**: fast-feedback, confidence, pgsql, browser. **Target Platform**: Laravel monolith in `apps/platform`, Sail locally, Dokploy for staging/production. **Project Type**: Laravel/Filament web application inside `apps/platform`. **Performance Goals**: Resolution page renders from DB-local readiness and proof references; no Graph/provider calls during render; planner evaluation remains bounded to one review and its known evidence/report/pack/run references. **Constraints**: no generic workflow registry; no raw provider/report/evidence payloads in case metadata; no direct `OperationRun.status`/`outcome` transitions outside existing services; no new panel provider or assets by default; no auto-publish. **Scale/Scope**: one blocked Environment Review at a time, one active current resolution case per subject/action/currentness, ordered sequential steps for review publication only. ## Existing Repository Surfaces Likely Affected ```text apps/platform/database/migrations/ apps/platform/app/Models/ apps/platform/app/Policies/ apps/platform/app/Services/EnvironmentReviews/ apps/platform/app/Services/Evidence/ apps/platform/app/Services/ReviewPacks/ apps/platform/app/Services/OperationRunService.php apps/platform/app/Support/ResolutionGuidance/ apps/platform/app/Support/ReviewPacks/ReviewPackOutputResolutionGuidance.php apps/platform/app/Support/ReviewPacks/ReviewPackOutputReadiness.php apps/platform/app/Support/OpsUx/OperationUxPresenter.php apps/platform/app/Support/OperationRunLinks.php apps/platform/app/Support/Rbac/UiEnforcement.php apps/platform/app/Support/Rbac/WorkspaceUiEnforcement.php apps/platform/app/Filament/Resources/EnvironmentReviewResource.php apps/platform/app/Filament/Resources/EnvironmentReviewResource/Pages/ViewEnvironmentReview.php apps/platform/app/Filament/Pages/Reviews/CustomerReviewWorkspace.php apps/platform/resources/views/filament/infolists/entries/environment-review-summary.blade.php apps/platform/resources/views/filament/pages/reviews/customer-review-workspace.blade.php apps/platform/tests/Unit/ apps/platform/tests/Feature/ apps/platform/tests/Browser/ docs/ui-ux-enterprise-audit/route-inventory.md docs/ui-ux-enterprise-audit/design-coverage-matrix.md docs/ui-ux-enterprise-audit/page-reports/ ``` Likely new implementation paths, subject to repo verification: ```text apps/platform/app/Models/ReviewPublicationResolutionCase.php apps/platform/app/Models/ReviewPublicationResolutionStep.php apps/platform/app/Policies/ReviewPublicationResolutionCasePolicy.php apps/platform/app/Support/ReviewPublicationResolution/ apps/platform/app/Filament/Resources/EnvironmentReviewResource/Pages/ResolveReviewPublication.php ``` If implementation proves an existing resource/page naming convention is better, use the repo convention and keep the subject-driven/no-top-level-nav boundary. ## Data and Migration Plan Prefer review-specific table names: ```text review_publication_resolution_cases review_publication_resolution_steps ``` Case fields should include: - `id` - `workspace_id` required - `managed_environment_id` or the repo-current environment FK required for review publication - `environment_review_id` required or a subject reference constrained to Environment Review only - `action_key` required and fixed to `review.publication` for v1 - `status` - `current_step_key` - `readiness_fingerprint` - `last_evaluated_at` - `created_by` - `assigned_to` - `started_at`, `completed_at`, `cancelled_at`, `superseded_at` - `summary` JSONB for safe derived summary - `metadata` JSONB for safe workflow metadata only - timestamps Step fields should include: - `id` - case FK - `position` - `step_key` - `status` - `primary_action_key` - `operation_run_id` nullable - `proof_type`, `proof_id`, `proof_status` nullable - lifecycle timestamps - `summary` JSONB for safe step summary - `metadata` JSONB for safe workflow metadata only - timestamps Indexes/constraints: - PostgreSQL-enforced unique active/current case constraint for one active case per workspace/environment/review/action/currentness, backed by transactional service locking/idempotency for double-click and concurrent Livewire requests. - unique `case_id` + `step_key`. - indexes for workspace/environment/action/status/current step/operation run/proof reference. - PostgreSQL JSONB lane validation for JSONB/default/index behavior. Do not use polymorphic subject persistence unless implementation updates this spec/plan/tasks first. A generic `action_resolution_*` schema requires a proportionality update before coding. No persisted `reason_code` column or reason-code enum is approved in v1. Step reasons remain evaluator/planner-derived and may appear only as safe summary text unless the spec/plan/tasks are updated with `STATE-001` consequences and tests. ## UI / Surface Guardrail Plan - **Guardrail scope**: existing Environment Review blocked-state change, new subject-driven resolution workflow page/action, high-impact step actions, OperationRun/artifact proof links, and customer-safe non-leakage. - **Affected routes/pages/actions/states/navigation/panel/provider surfaces**: - Environment Review detail - new Review Publication Resolution page or page action route - Customer Review Workspace non-leakage/preparation wording - existing OperationRun/evidence/report/pack proof destinations - **No-impact class, if applicable**: N/A. - **Native vs custom classification summary**: use native Filament Resource/Page actions and shared primitives first. Custom Blade only where existing review summary/customer workspace views already use it. - **Shared-family relevance**: next-action guidance, review readiness, OperationRun proof links, evidence/report viewers, audit/status messaging, customer-safe disclosure. - **State layers in scope**: persisted case, persisted steps, page current step, detail action state, URL route parameters, proof links. - **Audience modes in scope**: operator-MSP, workspace manager, support-platform, customer-safe viewer. - **Decision/diagnostic/raw hierarchy plan**: decision-first blocked reason, missing requirements, next safe action, and no-auto-publish note by default; proof and diagnostics secondary/collapsed; raw/support detail never customer default. - **Raw/support gating plan**: raw provider payloads, raw report content, full evidence JSON, internal reason families, and OperationRun context stay behind existing gated diagnostics or are not exposed. - **One-primary-action / duplicate-truth control**: one primary CTA on blocked review and one primary action for the current step. Completed/secondary proof links are demoted into technical disclosure. - **Handling modes by drift class or surface**: new strategic workflow surface is `review-mandatory`; high-impact actions are `exception-required` only if deviating from existing confirmation/audit patterns. - **Repository-signal treatment**: UI-COV-001 applies because a new reachable route/action surface is planned. - **Special surface test profiles**: workflow detail surface, shared-detail-family, and browser smoke. - **Required tests or manual smoke**: Unit, Feature, Filament/Livewire, PostgreSQL, and Browser smoke. - **Exception path and spread control**: no generic workflow exception approved. - **Active feature PR close-out entry**: Review Publication Resolution Workflow. - **UI/Productization coverage decision**: update route inventory, design coverage matrix, and page reports for the new workflow surface and affected review/customer surfaces. - **Coverage artifacts to update**: - `docs/ui-ux-enterprise-audit/route-inventory.md` - `docs/ui-ux-enterprise-audit/design-coverage-matrix.md` - relevant `docs/ui-ux-enterprise-audit/page-reports/...` - **No-impact rationale**: N/A. - **Navigation / Filament provider-panel handling**: no top-level navigation and no panel provider changes. Laravel 12 panel providers remain in `apps/platform/bootstrap/providers.php`. - **Screenshot or page-report need**: yes for the new workflow and blocked/recovery/customer-safe states. ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes. - **Systems touched**: Review readiness, evidence/report/pack readiness, OperationRun proof, Filament action UX, audit logging, RBAC UI enforcement, customer-safe disclosure. - **Shared abstractions reused**: `ReviewPackOutputResolutionGuidance`, `ReviewPackOutputReadiness`, `ResolutionGuidance` DTOs where useful, `OperationRunLinks`, `OperationUxPresenter`, `BadgeCatalog`, `UiEnforcement`, `WorkspaceUiEnforcement`, existing review/evidence/pack services. - **New abstraction introduced? why?**: yes, a review-publication-specific evaluator/planner/case/action/proof service family. It exists because the workflow must persist/resume state and proof over time. - **Why the existing abstraction was sufficient or insufficient**: existing derived guidance can explain and select actions but cannot persist case lifecycle, steps, proof references, currentness, or audit lifecycle. - **Bounded deviation / spread control**: no registry, no generic adapters, no cross-domain workflows. Namespace/service names should include `ReviewPublication` to preserve scope. ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: yes. - **Central contract reused**: existing OperationRun service/job creation and link/presenter helpers. - **Delegated UX behaviors**: queued toast, run link, artifact link, run-enqueued browser event, dedupe/already-running messaging, blocked/failed-to-start messaging, tenant/workspace-safe URL resolution, and terminal notifications stay in shared/source-owned paths. - **Surface-owned behavior kept local**: internal case status/current step selection, operator-facing next-action explanation, collapsed proof reference display, "Open operation", "Retry", and "Return to review" placement. - **Queued DB-notification policy**: unchanged unless spec is updated. - **Terminal notification path**: unchanged central lifecycle mechanism. - **Exception path**: none approved. Implementation must never mark `OperationRun.status` or `OperationRun.outcome` directly from the resolution page. It should link runs and re-evaluate domain truth. ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: yes, indirectly. - **Provider-owned seams**: raw provider IDs, raw Graph payloads, provider permission details, and provider-specific report internals. - **Platform-core seams**: review publication, evidence basis, report requirement, operation proof, artifact proof, readiness currentness, customer-ready boundary. - **Neutral platform terms / contracts preserved**: review publication, resolution case, resolution step, publication blocker, proof reference, evidence basis, report requirement, artifact proof. - **Retained provider-specific semantics and why**: only inside existing proof/diagnostics where needed; never as primary customer or operator workflow vocabulary. - **Bounded extraction or follow-up path**: follow-up-spec for provider onboarding adapter or generic proof/currentness. ## Constitution Check - Inventory-first: readiness derives from last-observed evidence/review/report/pack truth; no provider calls during render. - Read/write separation: publication is not automatic. Step actions that create/refresh TenantPilot artifacts or queue operations use existing services, explicit operator intent, authorization, audit, and tests. - Graph contract path: no direct Graph calls. Any existing evidence/report generation must continue through approved services/jobs and `GraphClientInterface`. - Deterministic capabilities: step action availability must derive from existing capabilities/policies and be testable. - RBAC-UX: `/admin` and `/system` remain separated; non-members 404; entitled users missing capability get safe denial/disabled state; customer users cannot access case internals. - Workspace isolation: cases and proof links are workspace scoped. - Tenant/environment isolation: review publication cases are environment scoped; no cross-environment proof leakage. - Global search: no global-search resource for cases in v1. - Destructive/high-impact actions: high-impact queued/artifact actions, retry that queues/regenerates work, case cancellation, and operator-triggered supersede/restart use `->action(...)`, authorization, confirmation, audit, notification, and tests. URL-only actions are navigation only. The initial `Resolve publication blockers` CTA creates/resumes an internal TenantPilot case and does not require confirmation, but must communicate scope and audit create/resume. - Run observability: long-running/queued step actions create or reuse `OperationRun` through existing paths and link the run to the step. - OperationRun start UX: shared start/link/presenter paths are reused; no local queued-toast/run-link composition. - Ops-UX lifecycle: no direct OperationRun lifecycle transitions outside service-owned paths. - Ops-UX summary counts: no new summary count keys unless `OperationSummaryKeys::all()` and tests are updated. - Data minimization: case and step metadata contain safe identifiers/summaries only. - Test governance: Unit, Feature, Filament/Livewire, PostgreSQL, and Browser lanes are explicit. - Proportionality: new persistence is justified by pause/resume, audit, currentness, and proof-linked workflow needs. - No premature abstraction: namespace and persistence remain review-publication-specific. - Persisted truth: new tables store workflow state, not readiness or artifact truth. - Behavioral state: case/step statuses affect routing/actionability/audit/lifecycle; v1 does not persist `skipped`, `not_applicable`, or a separate reason-code family for steps. - UI semantics: use existing badges/disclosure/action-group patterns, no local color/status framework. Default page copy stays operator-facing; technical proof and implementation terms remain behind explicit disclosure. - Shared pattern first: existing guidance/proof/action helpers are reused before local composition. - Provider boundary: platform-core workflow vocabulary stays provider-neutral. - V1 explicitness / few layers: direct review-specific services, no registry. - UI/Productization coverage: new reachable workflow surface must update UI coverage artifacts. Gate result for preparation: PASS. ## Test Governance Check - **Test purpose / classification by changed surface**: - Unit: evaluator, planner, fingerprint, proof resolver. - Feature: migrations/models, case service, step actions, audit, RBAC, scope, customer boundary. - Filament/Livewire Feature: CTA, resolution page, action enabled/disabled/executed states. - PostgreSQL: JSONB/index/unique/constraint behavior. - Browser: critical workflow smoke and non-leakage. - **Affected validation lanes**: fast-feedback, confidence, pgsql, browser. - **Why this lane mix is the narrowest sufficient proof**: the feature adds stateful workflow persistence and a new operator workflow page; SQLite-only tests cannot prove all PostgreSQL constraints and feature tests cannot prove full browser workflow presentation. - **Narrowest proving command(s)**: - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/ReviewPublicationResolution` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ReviewPublicationResolution tests/Feature/EnvironmentReview tests/Feature/ReviewPack` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/Spec386ReviewPublicationResolutionUiTest.php` - `cd apps/platform && ./vendor/bin/sail php vendor/bin/pest -c phpunit.pgsql.xml --filter Spec386` - `cd apps/platform && ./vendor/bin/sail php vendor/bin/pest tests/Browser/Spec386ReviewPublicationResolutionWorkflowTest.php` - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - `git diff --check` - **Fixture / helper / factory / seed / context cost risks**: review/evidence/report/pack/operation fixtures can grow expensive. Keep new fixtures local and explicit unless existing helpers already provide cheap setup. - **Expensive defaults or shared helper growth introduced?**: none planned. - **Heavy-family additions, promotions, or visibility changes**: none planned. - **Surface-class relief / special coverage rule**: no standard-native relief for the new workflow page; it needs explicit page/action/browser coverage. - **Closing validation and reviewer handoff**: verify no generic workflow spread, no stale proof, no customer leakage, correct audit/RBAC, and updated UI coverage artifacts. - **Budget / baseline / trend follow-up**: document-in-feature if pgsql/browser runtime or fixture cost materially grows. - **Review-stop questions**: duplicate truth, generic naming, proof currentness, unauthorized action execution, raw detail leakage, OperationRun lifecycle misuse, no-Graph-during-render. - **Escalation path**: document-in-feature for bounded implementation choices; follow-up-spec for structural proof/currentness or additional adapters. - **Active feature PR close-out entry**: Review Publication Resolution Workflow. - **Why no dedicated follow-up spec is needed**: Spec 386 itself is the bounded review-publication workflow. Generic proof/currentness and other adapters are listed as future specs. ## Project Structure ### Documentation (this feature) ```text specs/386-review-publication-resolution-workflow-v1/ ├── checklists/ │ └── requirements.md ├── plan.md ├── spec.md └── tasks.md ``` ### Source Code (repository root) ```text apps/platform/ ├── app/ │ ├── Models/ │ │ ├── ReviewPublicationResolutionCase.php │ │ └── ReviewPublicationResolutionStep.php │ ├── Policies/ │ │ └── ReviewPublicationResolutionCasePolicy.php │ ├── Support/ │ │ └── ReviewPublicationResolution/ │ │ ├── ReviewPublicationReadinessEvaluator.php │ │ ├── ReviewPublicationResolutionPlanner.php │ │ ├── ReviewPublicationResolutionCaseService.php │ │ ├── ReviewPublicationResolutionActionService.php │ │ ├── ReviewPublicationResolutionProofResolver.php │ │ └── DTOs and enums/value objects as needed │ ├── Services/ │ │ ├── EnvironmentReviews/ │ │ ├── Evidence/ │ │ └── ReviewPacks/ │ └── Filament/ │ └── Resources/ │ └── EnvironmentReviewResource/ │ └── Pages/ │ └── ResolveReviewPublication.php ├── database/ │ └── migrations/ ├── resources/views/ └── tests/ ├── Unit/ReviewPublicationResolution/ ├── Feature/ReviewPublicationResolution/ ├── Feature/Filament/ └── Browser/ ``` **Structure Decision**: Laravel monolith under `apps/platform`; review-publication-specific support namespace; subject-driven Filament page/action under Environment Review; no top-level resource/navigation. ## Complexity Tracking | Violation | Why Needed | Simpler Alternative Rejected Because | |---|---|---| | New persisted case/step tables | Operator workflow must survive navigation, queued operation completion, permission fixes, audit review, and currentness changes | Derived cards cannot preserve pause/resume, proof linkage, lifecycle audit, or current step over time | | New case/step statuses | Status changes drive next action, wait state, failure handling, completion, cancellation, and supersession | Presentation-only labels would not support resume, audit, or safe action routing | | New review-specific service family | Evaluation, planning, persistence, action execution, and proof/currentness must remain thin and testable | Putting this behavior in Filament closures would bury business logic and make RBAC/audit hard to verify | ## Implementation Phases 1. Confirm current review/evidence/report/pack/OperationRun services, capabilities, audit helpers, and UI patterns. 2. Add migration/model/policy tests first, including isolation and pgsql-specific constraints. 3. Add review-publication-specific models, migrations, enums/value objects, and policy. 4. Implement readiness evaluator, planner, fingerprinting, case service, action service, and proof resolver. 5. Integrate Environment Review blocked-state CTA and subject-driven resolution page/action. 6. Wire step actions through existing services/jobs and link OperationRun/artifact proof. 7. Add audit events and customer-boundary safeguards. 8. Update UI coverage artifacts. 9. Run focused Unit/Feature/Filament/PostgreSQL/Browser/Pint/diff validation. 10. Record implementation close-out with Filament v5 output contract and deployment impact. ## Data Truth Separation - **Execution truth**: `OperationRun`. - **Artifact truth**: `EvidenceSnapshot`, `StoredReport`, `EnvironmentReview`, `ReviewPack`. - **Backup/snapshot truth**: unchanged and out of scope. - **Recovery/evidence truth**: existing evidence/report/review/pack services. - **Operator next action**: Review Publication Resolution Case current step and planner output. The case may store a pointer to proof but must re-evaluate current truth before completing steps or the case. ## Rollout and Deployment Considerations - Migrations are required and must be safe on PostgreSQL. - Queue workers are already involved through existing evidence/report/review/pack operations; no new queue name is planned. - No new environment variables are planned. - No new scheduler entry is planned. - No new storage volume is planned. - No Filament asset registration is planned. If assets are added later, include `cd apps/platform && php artisan filament:assets` in deploy. - Staging validation must include migration, focused tests, and browser smoke before production promotion. ## Filament v5 Output Contract For Implementation Close-Out The implementation close-out must explicitly state: 1. Livewire v4.0+ compliance is preserved; current repo uses Livewire 4.1.4. 2. Filament panel provider registration remains in `apps/platform/bootstrap/providers.php`; no provider registration change unless explicitly made. 3. No globally searchable Resolution Case resource is added. If any Resource is added unexpectedly, global search is disabled or a safe View/Edit page exists. 4. Destructive/high-impact actions: list all new case/step actions and explain confirmation, authorization, audit, and notification behavior. 5. Asset strategy: no assets by default; if assets are registered, deploy includes `php artisan filament:assets`. 6. Tests added/updated: Unit, Feature, Filament/Livewire, PostgreSQL, Browser. 7. Deployment impact: migrations, queues, scheduler, env vars, storage, Dokploy/staging notes. ## Spec Readiness Gate Preparation readiness is expected to pass after `spec.md`, `plan.md`, `tasks.md`, and `checklists/requirements.md` are present and consistent. Implementation must stop and update artifacts first if it needs any of: - generic `action_resolution_*` persistence; - generic workflow registry/adapter; - top-level navigation; - global-searchable case resource; - customer self-resolution; - auto-publish behavior; - new Graph/provider call path; - new OperationRun type outside existing services; - new public state/status family beyond the case/step statuses listed in the spec.