create(['name' => 'Spec351 Detail Blocked']); [$owner, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $snapshot = seedPartialEnvironmentReviewEvidence($tenant, findingCount: 0, driftCount: 0); $review = composeEnvironmentReviewForTest($tenant, $owner, $snapshot); $review->forceFill([ 'status' => EnvironmentReviewStatus::Published->value, 'published_at' => now(), 'published_by_user_id' => (int) $owner->getKey(), 'summary' => array_replace_recursive(is_array($review->summary) ? $review->summary : [], [ 'publish_blockers' => ['Operator approval note is still missing.'], ]), ])->save(); Storage::disk('exports')->put('review-packs/spec351-detail-blocked.zip', 'PK-spec351-detail-blocked'); $pack = ReviewPack::factory()->ready()->create([ 'managed_environment_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'environment_review_id' => (int) $review->getKey(), 'evidence_snapshot_id' => (int) $snapshot->getKey(), 'initiated_by_user_id' => (int) $owner->getKey(), 'options' => [ 'include_pii' => false, 'include_operations' => true, ], 'file_path' => 'review-packs/spec351-detail-blocked.zip', 'file_disk' => 'exports', 'generated_at' => now()->subMinutes(3), ]); $review->forceFill(['current_export_review_pack_id' => (int) $pack->getKey()])->save(); setAdminEnvironmentContext($tenant); $this->actingAs($owner); $state = EnvironmentReviewResource::outputGuidanceState($review->fresh(['tenant', 'evidenceSnapshot', 'currentExportReviewPack.operationRun', 'operationRun'])); expect(data_get($state, 'resolution_case.primary_action.key'))->toBe('create_next_review') ->and(data_get($state, 'resolution_case.primary_action.action_name'))->toBe('create_next_review') ->and(data_get($state, 'suppress_primary_action_button'))->toBeTrue(); Livewire::actingAs($owner) ->test(ViewEnvironmentReview::class, ['record' => $review->getKey()]) ->assertActionExists('create_next_review', fn (Action $action): bool => $action->isConfirmationRequired()) ->mountAction('create_next_review') ->assertActionMounted('create_next_review'); }); it('aligns ready mutable detail guidance to publish review', function (): void { $tenant = ManagedEnvironment::factory()->create(['name' => 'Spec351 Detail Ready']); [$owner, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $review = composeEnvironmentReviewForTest($tenant, $owner); $review->forceFill([ 'status' => EnvironmentReviewStatus::Ready->value, 'published_at' => null, 'published_by_user_id' => null, ])->save(); setAdminEnvironmentContext($tenant); $this->actingAs($owner); $state = EnvironmentReviewResource::outputGuidanceState($review->fresh(['tenant', 'evidenceSnapshot', 'currentExportReviewPack.operationRun', 'operationRun'])); expect(data_get($state, 'resolution_case.primary_action.key'))->toBe('publish_review') ->and(data_get($state, 'resolution_case.primary_action.action_name'))->toBe('publish_review') ->and(data_get($state, 'suppress_primary_action_button'))->toBeTrue(); Livewire::actingAs($owner) ->test(ViewEnvironmentReview::class, ['record' => $review->getKey()]) ->assertActionExists('publish_review', fn (Action $action): bool => $action->isConfirmationRequired()) ->mountAction('publish_review') ->assertActionMounted('publish_review'); }); it('keeps publish review disabled when the draft is still blocked and refresh feedback stays explicit', function (): void { $tenant = ManagedEnvironment::factory()->create(['name' => 'Spec351 Detail Draft Blocked']); [$owner, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $snapshot = seedPartialEnvironmentReviewEvidence($tenant, findingCount: 0, driftCount: 0); $review = composeEnvironmentReviewForTest($tenant, $owner, $snapshot); $review->forceFill([ 'status' => EnvironmentReviewStatus::Draft->value, 'published_at' => null, 'published_by_user_id' => null, ])->save(); setAdminEnvironmentContext($tenant); $this->actingAs($owner); $state = EnvironmentReviewResource::outputGuidanceState($review->fresh(['tenant', 'sections', 'evidenceSnapshot', 'currentExportReviewPack.operationRun', 'operationRun'])); expect(data_get($state, 'resolution_case.primary_action.key'))->toBe('refresh_review'); Livewire::actingAs($owner) ->test(ViewEnvironmentReview::class, ['record' => $review->getKey()]) ->assertActionVisible('refresh_review') ->assertActionVisible('publish_review') ->assertActionDisabled('publish_review') ->callAction('refresh_review') ->assertNotified( Notification::make() ->success() ->title(GovernanceActionCatalog::rule('refresh_review')->successTitle) ->body('Review inputs refreshed. Blockers remain.'), ); });