Implemented the first version of review output resolve actions. Included a ReviewOutputResolveActionMapper, commands to seed browser fixtures, updated CustomerReviewWorkspace, EnvironmentReviewResource, UI enforcement, and related views. Also added extensive unit, feature, and browser tests, and updated the design coverage matrix. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #422
17 KiB
17 KiB
Implementation Plan: Spec 351 - Review Output Resolve Actions v1
Branch: 351-review-output-resolve-actions-v1 | Date: 2026-06-03 | Spec: specs/351-review-output-resolve-actions-v1/spec.md
Input: Direct user-provided Spec 351 draft plus repo truth from the current review-output guidance path and existing review lifecycle actions.
Summary
Productize Spec 350's review-output-first contract into one bounded review-output resolve-action layer that can surface a real next step where the repo already supports one:
- choose the strongest safe next action
- explain why it is recommended
- execute it only through existing source-owned Filament actions and services
- degrade honestly to navigation or disclosure when execution is unavailable
This slice stays review-output-only and touches only the current review-output consumers:
CustomerReviewWorkspace- Environment Review detail
It must not:
- broaden into provider readiness, governance inbox, or dashboard reuse
- invent a new workflow engine or action runtime
- create fake remediation or fake draft discovery
- add persistence, schema, or new lifecycle states
Technical Context
- Language/Version: PHP 8.4.15, Laravel 12.52.x
- Primary Dependencies: Filament 5.2.x, Livewire 4.1.x, Pest 4, Tailwind CSS 4
- Storage: PostgreSQL; no schema change expected
- Testing: Pest Unit + Feature/Livewire + one bounded Browser smoke
- Validation Lanes: fast-feedback + confidence + browser
- Target Platform:
apps/platformLaravel monolith, Sail-first locally - Project Type: server-rendered Filament web application
- Performance Goals: derived-only action selection, no new remote calls during render, no new queue family, no duplicate lifecycle dispatch
- Constraints: no fake executable actions, no direct service calls from Blade, no duplicate primary CTAs on detail, no provider/dashboard scope growth
- Scale/Scope: one deterministic mapper, one review-output adapter integration, one workspace-side executable action bridge, one non-duplicative detail alignment
UI / Surface Guardrail Plan
- Guardrail scope: changed strategic workspace surface plus changed review-detail guidance semantics
- Affected routes/pages/actions/states/navigation/panel/provider surfaces:
/admin/reviews/workspace- existing Environment Review detail route(s)
- existing workspace-mounted page actions and Environment Review header lifecycle actions
- No-impact class, if applicable: N/A
- Native vs custom classification summary: native Filament page/resource surfaces plus existing custom Blade rendering
- Shared-family relevance: review-output guidance, lifecycle actions, evidence/proof follow-up links
- State layers in scope: page, detail, URL-query, derived action-state envelope
- Audience modes in scope: operator-MSP, manager, readonly reviewer, customer-workspace detail context
- Decision/diagnostic/raw hierarchy plan: dominant next action first; limitations and evidence second; technical detail third
- Raw/support gating plan: unchanged; raw/support detail stays on source-owned surfaces
- One-primary-action / duplicate-truth control: workspace gets one dominant resolve action; detail aligns to one dominant lifecycle action without creating a second equal-weight rail
- Handling modes by drift class or surface: review-mandatory
- Repository-signal treatment: review-mandatory because the slice makes high-impact review actions more visible
- Special surface test profiles:
global-context-shell+shared-detail-family - Required tests or manual smoke: Unit + Feature + one bounded Browser smoke
- Exception path and spread control: if workspace execution requires more than mounting source-owned Filament actions, stop and keep the action as fallback navigation/disclosure
- Active feature PR close-out entry: Guardrail / Confirmation / Smoke Coverage
- UI/Productization coverage decision: update
ui-006andui-040only; no new route archetype or registry row is required - Coverage artifacts to update:
docs/ui-ux-enterprise-audit/page-reports/ui-006-customer-review-workspace.md,docs/ui-ux-enterprise-audit/page-reports/ui-040-environment-review-detail.md - No-impact rationale: N/A
- Navigation / Filament provider-panel handling: no route or provider change
- Screenshot or page-report need: yes; this is a first-screen CTA trust change on existing strategic surfaces
Shared Pattern & System Fit
- Cross-cutting feature marker: yes
- Systems touched:
App\Support\ReviewPacks\ReviewPackOutputResolutionGuidanceApp\Support\ResolutionGuidance\ResolutionActionApp\Support\ResolutionGuidance\ResolutionCaseApp\Support\ResolutionGuidance\Adapters\ReviewPackOutputResolutionAdapterApp\Filament\Pages\Reviews\CustomerReviewWorkspaceApp\Filament\Resources\EnvironmentReviewResourceApp\Filament\Resources\EnvironmentReviewResource\Pages\ViewEnvironmentReviewApp\Support\Ui\GovernanceActions\GovernanceActionCatalog
- Shared abstractions reused:
- current review-output readiness derivation
- existing
ResolutionCase/ResolutionActioncontract - existing Filament page-action mounting pattern on
CustomerReviewWorkspace - existing lifecycle actions and services on
ViewEnvironmentReview - current scoped route helpers and
OperationRunLinks
- New abstraction introduced? why?: yes, one
ReviewOutputResolveActionMapperis required because the repo has multiple real action sources and fallbacks, but current review-output guidance remains link-first and not execution-aware - Why the existing abstraction was sufficient or insufficient: Spec 350 standardized the case shape, but not the deterministic ranking of real resolve actions or the surface-safe execution bridge for those actions
- Bounded deviation / spread control: any action execution metadata added to
ResolutionActionmust stay optional, review-output-only, and derived-only
OperationRun UX Impact
- Touches OperationRun start/completion/link UX?: yes, indirectly
- Central contract reused:
EnvironmentReviewService::refresh()EnvironmentReviewLifecycleService::createNextReview()- existing
OperationRunLinks
- Delegated UX behaviors: queueing, dedupe, run creation, and notifications remain owned by the current services and shared UX paths
- Surface-owned behavior kept local: action ranking, explanation text, and honest fallback selection
- Queued DB-notification policy: unchanged
- Terminal notification path: unchanged
- Exception path: none
Provider Boundary & Portability Fit
N/A - the slice stays on review, evidence, pack, and operation surfaces only.
Current Repo Truth Summary
ReviewPackOutputResolutionGuidancealready derives rich output state, limitation, and link/disclosure copy fromReviewPackOutputReadiness.ReviewPackOutputResolutionAdapteralready wraps that guidance intoResolutionCase, but today it can only promote safe navigation/download/disclosure actions.ViewEnvironmentReviewalready exposes repo-real lifecycle actions:refresh_reviewbacked byEnvironmentReviewService::refresh()publish_reviewbacked byEnvironmentReviewLifecycleService::publish()create_next_reviewbacked byEnvironmentReviewLifecycleService::createNextReview()
create_next_reviewis capability-gated and audited, but it is not currently confirmation-gated even though it mutates review lifecycle state and starts the next review cycle.EnvironmentReviewLifecycleService::createNextReview()supersedes the published review and returns a mutable successor review; the repo has no generic workspace-level "open existing draft review" helper unless a concrete target review is already known.CustomerReviewWorkspacealready mounts real Filament page actions from custom Blade viamountAction()and includes<x-filament-actions::modals />, so workspace-side execution of bounded actions is feasible without inventing a second runtime.- Environment Review detail already has dominant header lifecycle actions, and customer-workspace detail mode intentionally suppresses repeated action rails inside the guidance card.
EvidenceSnapshotResource\Pages\ViewEvidenceSnapshotalready exposesrefresh_evidenceas a repo-real action, but review-output surfaces currently only link to evidence detail rather than executing evidence refresh directly.CustomerReviewWorkspaceis viewable by readonly actors, so executable resolve actions on the workspace must be capability-aware and honest when unavailable.
Implementation Approach
Phase 0 - Repo Truth Gate
- Re-read
spec.md,plan.md,tasks.md,repo-truth-map.md,contracts/review-output-resolve-action-map.md, andchecklists/requirements.md. - Re-verify:
apps/platform/app/Support/ReviewPacks/ReviewPackOutputResolutionGuidance.phpapps/platform/app/Support/ResolutionGuidance/Adapters/ReviewPackOutputResolutionAdapter.phpapps/platform/app/Filament/Pages/Reviews/CustomerReviewWorkspace.phpapps/platform/app/Filament/Resources/EnvironmentReviewResource.phpapps/platform/app/Filament/Resources/EnvironmentReviewResource/Pages/ViewEnvironmentReview.phpapps/platform/app/Services/EnvironmentReviews/EnvironmentReviewService.phpapps/platform/app/Services/EnvironmentReviews/EnvironmentReviewLifecycleService.phpapps/platform/app/Filament/Resources/EvidenceSnapshotResource/Pages/ViewEvidenceSnapshot.php
- Keep the repo-truth docs current if the narrowest safe action map changes during implementation.
Phase 1 - Tests First
- Add
apps/platform/tests/Unit/ResolutionGuidance/Spec351ReviewOutputResolveActionMapperTest.php. - Cover deterministic selection for:
- published blocked review with known successor review
- published blocked review without known successor review
- published blocked review without safe executable action
- mutable review with stale/missing evidence
- ready mutable review
- internal-only / PII / export-not-ready / no-action fallback
- Add workspace/detail feature tests:
apps/platform/tests/Feature/Filament/Spec351CustomerReviewWorkspaceResolveActionTest.phpapps/platform/tests/Feature/EnvironmentReview/Spec351EnvironmentReviewResolveActionTest.php
- Add one browser smoke:
apps/platform/tests/Browser/Spec351ReviewOutputResolveActionsSmokeTest.php, covering at least one blocked path and one ready-state path
- Reuse Spec 347/349/350 coverage instead of duplicating readiness/output assertions wholesale.
Phase 2 - Core Mapper And Contract Extension
- Create
apps/platform/app/Support/ResolutionGuidance/ReviewOutputResolveActionMapper.php. - Feed it:
- the current
EnvironmentReview - current review-output guidance/readiness truth
- known linked targets such as evidence, review detail, operation proof, download URL
- surface context (
customer_review_workspace,environment_review_detail,environment_review_detail.customer_workspace) - actor/capability availability where action execution must differ by viewer
- the current
- Deterministic ranking order:
- known successor review navigation when a concrete target exists
create_next_reviewfor blocked/limited published reviewsrefresh_reviewfor mutable reviews with stale or incomplete inputspublish_reviewfor ready mutable reviews- evidence/proof/disclosure fallback when no safe execution path exists
- Extend
ResolutionActiononly if needed so a case can carry missing source-owned execution-routing metadata such asaction_nameandexecution_surface, while reusing existingdisabled_reason, capability, confirmation, audit-event, andOperationRunmetadata. - Make the mapper the canonical selector of
resolution_case.primary_actionandsecondary_actionsfor the two in-scope surfaces.ReviewPackOutputResolutionGuidanceremains the source for readiness, limitations, and explanatory copy; its raw action fields are compatibility data and must not drive CTA ranking on workspace or detail. - Keep the contract derived-only and request-scoped.
Phase 3 - Workspace-Side Source-Owned Action Execution
- Add or reuse
CustomerReviewWorkspacepage actions for:refresh_reviewpublish_reviewcreate_next_review
- Reuse existing services,
GovernanceActionCatalogwhere already repo-real,UiEnforcement, capability checks, notifications, and audit behavior. - Mount those actions from the workspace decision card via
mountAction()and existing Filament modals. - Do not call lifecycle services directly from Blade.
- If a current actor or surface cannot safely execute the dominant action, downgrade to the strongest truthful navigation/disclosure fallback instead of showing a fake enabled button.
- If
create_next_reviewbecomes a dominant workspace CTA, addrequiresConfirmation()to the source-owned action before exposing it as executable; otherwise degrade it to truthful navigation/disclosure fallback. No exception path is allowed for executable use.
Phase 4 - Adapter Integration And Workspace Behavior
- Update
ReviewPackOutputResolutionAdapterso the dominant action comes from the new mapper while preserving current case/title/reason/impact/source/evidence data. - Preserve current findings and accepted-risk follow-up overrides on
CustomerReviewWorkspace; those remain higher-priority than the base review-output case. - Render exactly one dominant primary CTA in the workspace decision card and move all other mapped actions into a clearly secondary supporting-action group.
- Keep current technical details and grouped limitations disclosure intact unless a narrower improvement is required for clarity.
- Keep the review-consumption flow on the workspace as a supporting reference below the primary decision surfaces instead of a peer decision card.
- Do not regress qualified download wording or honest internal-only wording.
Phase 5 - Environment Review Detail Alignment
- Align
EnvironmentReviewResource::outputGuidanceState()to the same resolve-action semantics. - Preserve current
customer_workspacedetail-mode suppression and context note. - In normal detail mode, do not create two equal-weight primary action rails when the header already carries the same lifecycle action.
- Satisfy the detail requirement by aligning the guidance card
next stepsemantics and copy to the existing dominant header action. Do not move lifecycle CTA ownership out ofViewEnvironmentReviewin this slice. - Only offer successor-review-open navigation on detail when a concrete successor review target is actually known.
Phase 6 - Copy, Audit, And Browser Proof
- Update only the required copy keys in:
apps/platform/lang/en/localization.phpapps/platform/lang/de/localization.php
- Clarify acknowledgement copy so it never implies acknowledgement alone makes an output customer-ready.
- Split the workspace review-pack state presentation into package-exists, internal-export, and customer-sharing semantics without adding new persistence or workflow state.
- If repo truth keeps the current labels (
Create next review,Refresh review) instead of the user-draft wording (Create next review draft,Refresh review inputs), document that decision in the implementation close-out. - Update:
docs/ui-ux-enterprise-audit/page-reports/ui-006-customer-review-workspace.mddocs/ui-ux-enterprise-audit/page-reports/ui-040-environment-review-detail.md
- Capture screenshots under
specs/351-review-output-resolve-actions-v1/artifacts/screenshots/. - When a persistent ready-path demo is needed in local/testing, seed it via a bounded Artisan browser-fixture command instead of mutating product code or widening browser smoke scope.
Phase 7 - Validation And Close-Out
- Run focused Spec 351 Unit, Feature, and Browser coverage.
- Re-run filtered regressions for Specs 347, 349, 350, and
CustomerReviewWorkspace. - Run
pint --dirtyandgit diff --check. - Report any out-of-scope failures separately without widening implementation scope.
Validation Plan
cd apps/platform
./vendor/bin/sail artisan test tests/Unit/ResolutionGuidance/Spec351ReviewOutputResolveActionMapperTest.php --compact
./vendor/bin/sail artisan test tests/Feature/Filament/Spec351CustomerReviewWorkspaceResolveActionTest.php tests/Feature/EnvironmentReview/Spec351EnvironmentReviewResolveActionTest.php --compact
./vendor/bin/sail artisan test tests/Feature/Console/TenantpilotSeedReviewOutputBrowserFixtureCommandTest.php --compact
./vendor/bin/sail php vendor/bin/pest tests/Browser/Spec351ReviewOutputResolveActionsSmokeTest.php --compact
./vendor/bin/sail artisan tenantpilot:review-output:seed-browser-fixture --no-interaction
./vendor/bin/sail artisan test --compact --filter=Spec347
./vendor/bin/sail artisan test --compact --filter=Spec349
./vendor/bin/sail artisan test --compact --filter=Spec350
./vendor/bin/sail artisan test --compact --filter=CustomerReviewWorkspace
./vendor/bin/sail pint --dirty
git diff --check
Deployment Impact
- Env vars: none expected
- Migrations: none
- Queues / scheduler: no new queue family; existing review refresh / next-review queue behavior reused
- Storage: none
- Assets: no new Filament asset registration expected;
filament:assetsis not newly required by this slice - Panel providers / global search: unchanged; Filament v5 / Livewire v4 posture remains, and provider registration stays in
apps/platform/bootstrap/providers.php