create(['name' => 'Spec350 Workspace Blocked']); [$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner', workspaceRole: 'manager'); $snapshot = seedPartialEnvironmentReviewEvidence($environment, findingCount: 0, driftCount: 0); $review = composeEnvironmentReviewForTest($environment, $user, $snapshot); $summary = array_replace_recursive(is_array($review->summary) ? $review->summary : [], [ 'publish_blockers' => ['Operator approval note is still missing.'], ]); $review->forceFill([ 'status' => EnvironmentReviewStatus::Published->value, 'published_at' => now(), 'published_by_user_id' => (int) $user->getKey(), 'summary' => $summary, ])->save(); Storage::disk('exports')->put('review-packs/spec350-workspace-blocked.zip', 'PK-spec350-workspace-blocked'); $pack = ReviewPack::factory()->ready()->create([ 'managed_environment_id' => (int) $environment->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'environment_review_id' => (int) $review->getKey(), 'evidence_snapshot_id' => (int) $snapshot->getKey(), 'initiated_by_user_id' => (int) $user->getKey(), 'options' => [ 'include_pii' => false, 'include_operations' => true, ], 'file_path' => 'review-packs/spec350-workspace-blocked.zip', 'file_disk' => 'exports', 'generated_at' => now()->subMinutes(3), ]); $review->forceFill(['current_export_review_pack_id' => (int) $pack->getKey()])->save(); $component = spec350WorkspaceComponent($user, $environment) ->assertSee('What is the current review pack output state?') ->assertSee('Output not customer-ready') ->assertSee('Create next review') ->assertSee('Review blockers are still recorded for this output.') ->assertSee('Inspect review blockers'); $payload = $component->instance()->latestReviewConsumptionPayload(); expect(data_get($payload, 'readiness.resolution_case.key'))->toBe('review_output.publication_blocked') ->and(data_get($payload, 'readiness.resolution_case.scope.source_surface'))->toBe(CustomerReviewWorkspace::SOURCE_SURFACE) ->and(data_get($payload, 'readiness.resolution_case.primary_action.key'))->toBe('create_next_review') ->and(data_get($payload, 'readiness.resolution_case.primary_action.action_name'))->toBe('createNextReview') ->and(data_get($payload, 'readiness.resolution_case.source_refs'))->toContainEqual(['type' => 'environment_review', 'id' => (int) $review->getKey()]) ->and(data_get($payload, 'readiness.resolution_case.source_refs'))->toContainEqual(['type' => 'review_pack', 'id' => (int) $pack->getKey()]) ->and(data_get($payload, 'readiness.resolution_case.evidence_refs'))->toHaveCount(1); }); it('preserves findings follow-up overrides above the shared review-output case', function (): void { $environment = ManagedEnvironment::factory()->create(['name' => 'Spec350 Workspace Findings']); [$user, $environment] = createUserWithTenant(tenant: $environment, role: 'owner', workspaceRole: 'manager'); $snapshot = seedEnvironmentReviewEvidence($environment, findingCount: 0, driftCount: 0); $review = composeEnvironmentReviewForTest($environment, $user, $snapshot); $review->forceFill([ 'status' => EnvironmentReviewStatus::Published->value, 'published_at' => now(), 'published_by_user_id' => (int) $user->getKey(), ])->save(); $review = markEnvironmentReviewCustomerSafeReady($review); Storage::disk('exports')->put('review-packs/spec350-workspace-findings.zip', 'PK-spec350-workspace-findings'); $pack = ReviewPack::factory()->ready()->create([ 'managed_environment_id' => (int) $environment->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'environment_review_id' => (int) $review->getKey(), 'evidence_snapshot_id' => (int) $snapshot->getKey(), 'initiated_by_user_id' => (int) $user->getKey(), 'options' => [ 'include_pii' => false, 'include_operations' => true, ], 'file_path' => 'review-packs/spec350-workspace-findings.zip', 'file_disk' => 'exports', 'generated_at' => now()->subMinutes(3), ]); $review->forceFill(['current_export_review_pack_id' => (int) $pack->getKey()])->save(); Finding::factory()->create([ 'managed_environment_id' => (int) $environment->getKey(), 'workspace_id' => (int) $environment->workspace_id, 'severity' => Finding::SEVERITY_HIGH, 'status' => Finding::STATUS_NEW, ]); $component = spec350WorkspaceComponent($user, $environment) ->assertSee('Published with limitations') ->assertSee('Keep open findings visible before customer handoff.') ->assertSee('Open review'); $payload = $component->instance()->latestReviewConsumptionPayload(); expect(data_get($payload, 'readiness.resolution_case.key'))->toBe('customer_review_workspace.findings_follow_up_required') ->and(data_get($payload, 'readiness.resolution_case.primary_action.label'))->toBe('Open review') ->and(data_get($payload, 'readiness.output_guidance.label'))->toBe('Customer-safe review pack ready'); }); function spec350WorkspaceComponent(User $user, ManagedEnvironment $environment): mixed { session()->put(WorkspaceContext::SESSION_KEY, (int) $environment->workspace_id); setAdminPanelContext(); return Livewire::actingAs($user) ->test(CustomerReviewWorkspace::class); }