TenantAtlas/apps/platform/tests/Feature/Reviews/CustomerReviewWorkspacePageTest.php
ahmido 12ea7f9924 feat: review pack output contract and readiness semantics (spec 347/348) (#419)
Implemented the output contract and readiness semantics for review packs. Also added spec 348.
Includes changes to ChooseEnvironment, CustomerReviewWorkspace, GenerateReviewPackJob and related blade views.
Added comprehensive tests.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #419
2026-06-02 23:17:08 +00:00

693 lines
32 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\Pages\Reviews\CustomerReviewWorkspace;
use App\Filament\Resources\EnvironmentReviewResource;
use App\Models\Finding;
use App\Models\FindingException;
use App\Models\ManagedEnvironment;
use App\Models\ReviewPack;
use App\Models\User;
use App\Support\EnvironmentReviewStatus;
use App\Support\Governance\Controls\ComplianceEvidenceMappingV1;
use App\Support\Workspaces\WorkspaceContext;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
uses(RefreshDatabase::class);
it('keeps the Spec 326 repo truth map available for customer review workspace productization', function (): void {
$path = repo_path('specs/326-customer-review-workspace-v1-productization/repo-truth-map.md');
expect($path)->toBeFile();
$contents = file_get_contents($path);
expect($contents)->toContain('Tenant Reviews / Environment Reviews')
->and($contents)->toContain('Evidence Snapshots')
->and($contents)->toContain('Review Packs / exports')
->and($contents)->toContain('Accepted Risks / Risk Exceptions')
->and($contents)->toContain('OperationRuns')
->and($contents)->toContain('Audit log');
});
it('lists only the latest published review per entitled environment on the customer review workspace', function (): void {
$tenantA = ManagedEnvironment::factory()->create(['name' => 'Alpha ManagedEnvironment']);
[$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'readonly');
$tenantB = ManagedEnvironment::factory()->create([
'workspace_id' => (int) $tenantA->workspace_id,
'name' => 'Beta ManagedEnvironment',
]);
createUserWithTenant(tenant: $tenantB, user: $user, role: 'readonly');
$tenantDenied = ManagedEnvironment::factory()->create([
'workspace_id' => (int) $tenantA->workspace_id,
'name' => 'Denied ManagedEnvironment',
]);
$otherOwner = User::factory()->create();
createUserWithTenant(tenant: $tenantDenied, user: $otherOwner, role: 'owner');
$tenantASnapshot = seedEnvironmentReviewEvidence($tenantA);
$tenantBSnapshot = seedEnvironmentReviewEvidence($tenantB);
$tenantDeniedSnapshot = seedEnvironmentReviewEvidence($tenantDenied);
$olderPublishedReview = composeEnvironmentReviewForTest($tenantA, $user, $tenantASnapshot);
$olderPublishedReview->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'generated_at' => now()->subDays(3),
'published_at' => now()->subDays(3),
'published_by_user_id' => (int) $user->getKey(),
])->save();
$newerInternalReview = $olderPublishedReview->replicate();
$newerInternalReview->forceFill([
'managed_environment_id' => (int) $tenantA->getKey(),
'workspace_id' => (int) $tenantA->workspace_id,
'evidence_snapshot_id' => (int) $tenantASnapshot->getKey(),
'status' => EnvironmentReviewStatus::Ready->value,
'generated_at' => now()->subDay(),
'published_at' => null,
'published_by_user_id' => null,
])->save();
$latestPublishedReview = $olderPublishedReview->replicate();
$latestPublishedReview->forceFill([
'managed_environment_id' => (int) $tenantA->getKey(),
'workspace_id' => (int) $tenantA->workspace_id,
'evidence_snapshot_id' => (int) $tenantASnapshot->getKey(),
'status' => EnvironmentReviewStatus::Published->value,
'generated_at' => now(),
'published_at' => now(),
'published_by_user_id' => (int) $user->getKey(),
])->save();
$betaPublishedReview = composeEnvironmentReviewForTest($tenantB, $user, $tenantBSnapshot);
$betaPublishedReview->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'generated_at' => now()->subHours(2),
'published_at' => now()->subHours(2),
'published_by_user_id' => (int) $user->getKey(),
])->save();
$deniedPublishedReview = composeEnvironmentReviewForTest($tenantDenied, $otherOwner, $tenantDeniedSnapshot);
$deniedPublishedReview->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'generated_at' => now()->subHours(3),
'published_at' => now()->subHours(3),
'published_by_user_id' => (int) $otherOwner->getKey(),
])->save();
$this->actingAs($user);
setAdminPanelContext();
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);
Livewire::actingAs($user)
->test(CustomerReviewWorkspace::class)
->assertCanSeeTableRecords([$tenantA->fresh(), $tenantB->fresh()])
->assertCanNotSeeTableRecords([$tenantDenied->fresh()])
->assertSee(EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $latestPublishedReview->fresh()], $tenantA), false)
->assertSee('Customer-safe review packages')
->assertSee('Review released governance packages, evidence readiness, accepted risks, and handoff status across entitled environments.')
->assertSee('Service delivery summary only. Does not replace formal audit opinion, certification, or legal attestation.')
->assertSee('Review package index')
->assertSee('Released reviews and customer-safe package entries available in this workspace.')
->assertDontSee('for each entitled tenant')
->assertDontSee('Each row is an index entry')
->assertSee('Governance package')
->assertSee('Status')
->assertSee('Evidence')
->assertSee('Next step')
->assertSee('Open')
->assertSee('Open review')
->assertDontSee('Assessment status')
->assertDontSee('Publishable')
->assertDontSee('No mapped controls')
->assertDontSee('Compliance evidence mapping v1')
->assertDontSee(ComplianceEvidenceMappingV1::VERSION_KEY)
->assertSee(EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $betaPublishedReview->fresh()], $tenantB), false)
->assertDontSee(EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $olderPublishedReview->fresh()], $tenantA), false)
->assertDontSee(EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $newerInternalReview->fresh()], $tenantA), false)
->assertDontSee('Publish review')
->assertDontSee('Refresh review')
->assertDontSee('Create next review')
->assertDontSee('Regenerate')
->assertDontSee('Expire snapshot')
->assertDontSee(EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $deniedPublishedReview->fresh()], $tenantDenied), false);
});
it('renders the Spec 326 decision-first review workspace without default raw diagnostics', function (): void {
$tenant = ManagedEnvironment::factory()->create(['name' => 'Decision Ready ManagedEnvironment']);
[$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'readonly');
$snapshot = seedEnvironmentReviewEvidence($tenant);
$review = composeEnvironmentReviewForTest($tenant, $user, $snapshot);
$summary = is_array($review->summary) ? $review->summary : [];
$summary['debug_payload'] = 'raw payload should stay hidden';
$summary['stack_trace'] = 'stack trace should stay hidden';
$summary['internal_exception'] = 'internal exception should stay hidden';
$summary['provider_secret'] = 'provider secret should stay hidden';
$summary['debug_metadata'] = 'debug metadata should stay hidden';
$summary['source_fingerprint'] = 'source fingerprint should stay hidden';
$summary['control_interpretation']['version_key'] = ComplianceEvidenceMappingV1::VERSION_KEY;
$summary['control_interpretation']['controls'] = [
[
'control_key' => 'customer-handoff-readiness',
'title' => 'Customer handoff readiness',
'readiness_bucket' => 'evidence_on_record',
'readiness_label' => 'Evidence on record',
'primary_reason' => 'Evidence path is complete.',
'recommended_next_action' => 'Share the current review pack.',
],
];
$summary['governance_package']['decision_summary']['entries'][] = [
'title' => 'Customer acceptance checkpoint',
'summary' => 'Confirm stakeholder awareness before handoff.',
'next_action' => 'Record the customer decision trail before the next review.',
];
$review->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'summary' => $summary,
'published_at' => now(),
'published_by_user_id' => (int) $user->getKey(),
])->save();
$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) $user->getKey(),
]);
$review->forceFill(['current_export_review_pack_id' => (int) $pack->getKey()])->save();
$this->actingAs($user);
setAdminPanelContext();
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
Livewire::actingAs($user)
->test(CustomerReviewWorkspace::class)
->assertSee('Customer Review Workspace')
->assertSee('What is the current review pack output state?')
->assertSee('Review consumption flow')
->assertSee('Evidence')
->assertSee('Findings needing attention')
->assertSee('Evidence path')
->assertSeeHtml('data-testid="customer-review-evidence-aside"')
->assertSee('Review pack state')
->assertSee('Review pack')
->assertSee('Decision trail')
->assertSee('Accepted risks')
->assertSee('Expiring soon')
->assertSee('Expired')
->assertSee('Pending approval')
->assertSee('Needs review')
->assertSee('Operation proof')
->assertSee('Customer-safe follow-ups')
->assertSee('Review package index')
->assertSee('Disclosure rule')
->assertSee('Decision')
->assertSee('Visible')
->assertSee('Diagnostics')
->assertSee('Collapsed')
->assertSee('Raw/support')
->assertSee('Hidden')
->assertSee('Support details stay on authorized diagnostic surfaces')
->assertSee('Customer acceptance checkpoint')
->assertSee('Open review')
->assertSee('Download review pack with limitations')
->assertDontSee('raw payload should stay hidden')
->assertDontSee('stack trace should stay hidden')
->assertDontSee('internal exception should stay hidden')
->assertDontSee('provider secret should stay hidden')
->assertDontSee('debug metadata should stay hidden')
->assertDontSee('source fingerprint should stay hidden')
->assertDontSee('Publish review')
->assertDontSee('Refresh review')
->assertDontSee('Regenerate')
->assertDontSee('Expire snapshot');
});
it('does not show ready to share when accepted-risk follow-up is required', function (): void {
$environment = ManagedEnvironment::factory()->create(['name' => 'Accepted Risk Follow-up ManagedEnvironment']);
[$user, $environment] = createUserWithTenant(tenant: $environment, role: 'readonly');
$snapshot = seedEnvironmentReviewEvidence($environment, findingCount: 0, driftCount: 0);
$review = composeEnvironmentReviewForTest($environment, $user, $snapshot);
$summary = is_array($review->summary) ? $review->summary : [];
$summary['control_interpretation']['version_key'] = ComplianceEvidenceMappingV1::VERSION_KEY;
$summary['control_interpretation']['controls'] = [
[
'control_key' => 'customer-handoff-readiness',
'title' => 'Customer handoff readiness',
'readiness_bucket' => 'evidence_on_record',
'readiness_label' => 'Evidence on record',
'primary_reason' => 'Evidence path is complete.',
'recommended_next_action' => 'Share the current review pack.',
],
];
$summary['governance_package']['decision_summary'] = [
'status' => 'none',
'total_count' => 0,
'summary' => 'No decisions require customer awareness.',
'next_action' => 'No customer action is needed.',
'entries' => [],
];
$summary['governance_package']['accepted_risks'] = [
[
'title' => 'Accepted risk renewal',
'governance_state' => 'expiring_exception',
'customer_summary' => 'Review the accepted-risk follow-up before customer handoff.',
],
];
$review->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'summary' => $summary,
'published_at' => now(),
'published_by_user_id' => (int) $user->getKey(),
])->save();
$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,
],
]);
$review->forceFill(['current_export_review_pack_id' => (int) $pack->getKey()])->save();
$this->actingAs($user);
setAdminPanelContext();
session()->put(WorkspaceContext::SESSION_KEY, (int) $environment->workspace_id);
Livewire::actingAs($user)
->test(CustomerReviewWorkspace::class)
->assertSee('What is the current review pack output state?')
->assertSee('Published with limitations')
->assertSee('Accepted-risk follow-up is recorded for this review')
->assertSee('The pack can be shared only with the accepted-risk context included in the customer handoff.')
->assertSee('Needs review')
->assertSee('Follow-up required')
->assertSee('Accepted-risk follow-up is required.')
->assertSee('Open review')
->assertSeeInOrder(['Published with limitations', 'Open review'])
->assertSee('Download review pack with limitations')
->assertDontSee('Ready to share');
});
it('customer_review_workspace_does_not_use_tenant_as_platform_context_copy', function (): void {
$environment = ManagedEnvironment::factory()->create(['name' => 'Vocabulary ManagedEnvironment']);
[$user, $environment] = createUserWithTenant(tenant: $environment, role: 'readonly');
$snapshot = seedEnvironmentReviewEvidence($environment);
$review = composeEnvironmentReviewForTest($environment, $user, $snapshot);
$review->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'published_at' => now(),
'published_by_user_id' => (int) $user->getKey(),
])->save();
$this->actingAs($user);
setAdminPanelContext();
session()->put(WorkspaceContext::SESSION_KEY, (int) $environment->workspace_id);
Livewire::actingAs($user)
->test(CustomerReviewWorkspace::class)
->assertSee('Customer-safe review packages')
->assertSee('entitled environments')
->assertDontSee('entitled tenant')
->assertDontSee('entitled tenants')
->assertDontSee('current tenant')
->assertDontSee('tenant filter')
->assertDontSee('for each entitled tenant');
});
it('shows explicit unavailable proof states instead of false share readiness', function (): void {
$tenant = ManagedEnvironment::factory()->create(['name' => 'Needs Evidence ManagedEnvironment']);
[$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'readonly');
$snapshot = seedPartialEnvironmentReviewEvidence($tenant, findingCount: 0, driftCount: 0);
$review = composeEnvironmentReviewForTest($tenant, $user, $snapshot);
$review->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'published_at' => now(),
'published_by_user_id' => (int) $user->getKey(),
])->save();
$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) $user->getKey(),
'options' => [
'include_pii' => false,
'include_operations' => true,
],
]);
$review->forceFill(['current_export_review_pack_id' => (int) $pack->getKey()])->save();
$this->actingAs($user);
setAdminPanelContext();
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
Livewire::actingAs($user)
->test(CustomerReviewWorkspace::class)
->assertSee('What is the current review pack output state?')
->assertSee('Published with limitations')
->assertSee('The review package is published, but the evidence basis is incomplete.')
->assertSee('No operation proof linked')
->assertSee('Export ready')
->assertDontSee('Ready to share')
->assertSee('Download review pack with limitations');
});
it('shows the current released review using deterministic published review ordering', function (): void {
$publishedAt = now()->subHour();
$tenantA = ManagedEnvironment::factory()->create(['name' => 'Alpha ManagedEnvironment']);
[$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'readonly');
$tenantB = ManagedEnvironment::factory()->create([
'workspace_id' => (int) $tenantA->workspace_id,
'name' => 'Beta ManagedEnvironment',
]);
createUserWithTenant(tenant: $tenantB, user: $user, role: 'readonly');
$snapshotA = seedEnvironmentReviewEvidence($tenantA);
$snapshotB = seedEnvironmentReviewEvidence($tenantB);
$alphaReview = composeEnvironmentReviewForTest($tenantA, $user, $snapshotA);
$alphaReview->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'generated_at' => $publishedAt,
'published_at' => $publishedAt,
'published_by_user_id' => (int) $user->getKey(),
])->save();
$betaReview = composeEnvironmentReviewForTest($tenantB, $user, $snapshotB);
$betaReview->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'generated_at' => $publishedAt,
'published_at' => $publishedAt,
'published_by_user_id' => (int) $user->getKey(),
])->save();
$this->actingAs($user);
setAdminPanelContext();
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);
Livewire::actingAs($user)
->test(CustomerReviewWorkspace::class)
->assertSeeInOrder([
'Latest released review',
'Beta ManagedEnvironment',
$publishedAt->format('M j, Y'),
'Decision trail',
'No governance decisions require customer awareness in this released review.',
])
->assertSee(EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $betaReview->fresh()], $tenantB), false);
});
it('excludes entitled environments without a published review from customer workspace rows', function (): void {
$tenantPublished = ManagedEnvironment::factory()->create(['name' => 'Published ManagedEnvironment']);
[$user, $tenantPublished] = createUserWithTenant(tenant: $tenantPublished, role: 'readonly');
$tenantWithoutPublished = ManagedEnvironment::factory()->create([
'workspace_id' => (int) $tenantPublished->workspace_id,
'name' => 'No Published ManagedEnvironment',
]);
createUserWithTenant(tenant: $tenantWithoutPublished, user: $user, role: 'readonly');
$publishedSnapshot = seedEnvironmentReviewEvidence($tenantPublished);
$noPublishedSnapshot = seedEnvironmentReviewEvidence($tenantWithoutPublished);
$publishedReview = composeEnvironmentReviewForTest($tenantPublished, $user, $publishedSnapshot);
$publishedReview->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'published_at' => now()->subHour(),
'published_by_user_id' => (int) $user->getKey(),
])->save();
$internalOnlyReview = composeEnvironmentReviewForTest($tenantWithoutPublished, $user, $noPublishedSnapshot);
$internalOnlyReview->forceFill([
'status' => EnvironmentReviewStatus::Ready->value,
'published_at' => null,
'published_by_user_id' => null,
])->save();
$this->actingAs($user);
setAdminPanelContext();
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantPublished->workspace_id);
Livewire::actingAs($user)
->test(CustomerReviewWorkspace::class)
->assertCanSeeTableRecords([$tenantPublished->fresh()])
->assertCanNotSeeTableRecords([$tenantWithoutPublished->fresh()])
->assertDontSee('No published review')
->assertDontSee('No published review available yet')
->assertDontSee(EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $internalOnlyReview->fresh()], $tenantWithoutPublished), false)
->assertSee(EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $publishedReview->fresh()], $tenantPublished), false);
});
it('uses a filter-aware empty state when the active environment has no released review', function (): void {
$tenantPublished = ManagedEnvironment::factory()->create(['name' => 'Published ManagedEnvironment']);
[$user, $tenantPublished] = createUserWithTenant(tenant: $tenantPublished, role: 'readonly');
$tenantWithoutPublished = ManagedEnvironment::factory()->create([
'workspace_id' => (int) $tenantPublished->workspace_id,
'name' => 'Filtered ManagedEnvironment',
]);
createUserWithTenant(tenant: $tenantWithoutPublished, user: $user, role: 'readonly');
$publishedReview = composeEnvironmentReviewForTest($tenantPublished, $user, seedEnvironmentReviewEvidence($tenantPublished));
$publishedReview->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'published_at' => now(),
'published_by_user_id' => (int) $user->getKey(),
])->save();
$internalReview = composeEnvironmentReviewForTest($tenantWithoutPublished, $user, seedEnvironmentReviewEvidence($tenantWithoutPublished));
$internalReview->forceFill([
'status' => EnvironmentReviewStatus::Ready->value,
'published_at' => null,
'published_by_user_id' => null,
])->save();
$this->actingAs($user);
setAdminPanelContext();
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantPublished->workspace_id);
Livewire::withQueryParams(['environment_id' => (int) $tenantWithoutPublished->getKey()])
->actingAs($user)
->test(CustomerReviewWorkspace::class)
->assertSet('tableFilters.managed_environment_id.value', (string) $tenantWithoutPublished->getKey())
->assertSee('Environment filter:')
->assertSee('No released customer reviews match the active environment filter.')
->assertSee('Clear the environment filter to view other released reviews in this workspace.')
->assertCanNotSeeTableRecords([$tenantPublished->fresh(), $tenantWithoutPublished->fresh()])
->assertDontSee('Publish an environment review before it appears in the customer-safe workspace.');
});
it('uses a page-level empty state when no entitled environment has a released review', function (): void {
$tenant = ManagedEnvironment::factory()->create(['name' => 'Internal Only ManagedEnvironment']);
[$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'readonly');
$snapshot = seedEnvironmentReviewEvidence($tenant);
$internalOnlyReview = composeEnvironmentReviewForTest($tenant, $user, $snapshot);
$internalOnlyReview->forceFill([
'status' => EnvironmentReviewStatus::Ready->value,
'published_at' => null,
'published_by_user_id' => null,
])->save();
$this->actingAs($user);
setAdminPanelContext();
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
Livewire::actingAs($user)
->test(CustomerReviewWorkspace::class)
->assertCanNotSeeTableRecords([$tenant->fresh()])
->assertSee('No released customer reviews match this view')
->assertSee('Publish an environment review before it appears in the customer-safe workspace.')
->assertDontSee(EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $internalOnlyReview->fresh()], $tenant), false);
});
it('summarizes accepted risks from the released review without exposing internal accountability details', function (): void {
$tenant = ManagedEnvironment::factory()->create(['name' => 'Governed ManagedEnvironment']);
[$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'readonly');
$owner = User::factory()->create(['name' => 'Risk Owner']);
$finding = Finding::factory()->create([
'managed_environment_id' => (int) $tenant->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
'status' => Finding::STATUS_RISK_ACCEPTED,
]);
FindingException::query()->create([
'workspace_id' => (int) $tenant->workspace_id,
'managed_environment_id' => (int) $tenant->getKey(),
'finding_id' => (int) $finding->getKey(),
'status' => FindingException::STATUS_ACTIVE,
'current_validity_state' => FindingException::VALIDITY_VALID,
'requested_by_user_id' => (int) $user->getKey(),
'request_reason' => 'Vendor patch window accepted by the customer.',
'owner_user_id' => (int) $owner->getKey(),
'approved_by_user_id' => (int) $owner->getKey(),
'requested_at' => now()->subDays(2),
'approved_at' => now()->subDay(),
'effective_from' => now()->subDay(),
'review_due_at' => now()->addDays(14),
]);
$snapshot = seedEnvironmentReviewEvidence($tenant, findingCount: 0, driftCount: 0);
$review = composeEnvironmentReviewForTest($tenant, $user, $snapshot);
$review->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'published_at' => now(),
'published_by_user_id' => (int) $user->getKey(),
])->save();
$this->actingAs($user);
setAdminPanelContext();
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
Livewire::actingAs($user)
->test(CustomerReviewWorkspace::class)
->assertCanSeeTableRecords([$tenant->fresh()])
->assertSee('Accepted risks')
->assertSee('Accepted risk')
->assertSee('Included in the released review evidence basis.')
->assertSee('Needs review')
->assertSee('Open review')
->assertDontSee('Ready for release')
->assertSee('Risk Owner')
->assertSee('Vendor patch window accepted by the customer.')
->assertSee(now()->addDays(14)->toDateString())
->assertDontSee('1 evidence signal(s) reference this control.')
->assertDontSee('1 accepted-risk finding(s) qualify this view.')
->assertDontSee('Accepted risk influences this view');
});
it('renders legacy released reviews without a spec-308 decision summary as customer-safe unavailable evidence', function (): void {
$tenant = ManagedEnvironment::factory()->create(['name' => 'Legacy ManagedEnvironment']);
[$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'readonly');
$review = composeEnvironmentReviewForTest($tenant, $user, seedEnvironmentReviewEvidence($tenant));
$review->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'published_at' => now(),
'published_by_user_id' => (int) $user->getKey(),
'summary' => [
'finding_count' => 1,
'debug_payload' => 'raw evidence JSON',
'source_fingerprint' => 'legacy-fingerprint-abc123',
'operation_run_url' => '/admin/t/legacy/operation-runs/999',
],
])->save();
$this->actingAs($user);
setAdminPanelContext();
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
Livewire::actingAs($user)
->test(CustomerReviewWorkspace::class)
->assertSee('Decision trail')
->assertSee('Unavailable')
->assertSee('Customer-safe decision evidence is unavailable for this released review.')
->assertDontSee('raw evidence JSON')
->assertDontSee('legacy-fingerprint-abc123')
->assertDontSee('operation-runs')
->assertDontSee('/admin/t', false);
});
it('keeps the customer review workspace unfiltered when remembered environment context is available', function (): void {
$tenantA = ManagedEnvironment::factory()->create(['name' => 'Alpha ManagedEnvironment']);
[$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'readonly');
$tenantB = ManagedEnvironment::factory()->create([
'workspace_id' => (int) $tenantA->workspace_id,
'name' => 'Beta ManagedEnvironment',
]);
createUserWithTenant(tenant: $tenantB, user: $user, role: 'readonly');
$snapshotA = seedEnvironmentReviewEvidence($tenantA);
$snapshotB = seedEnvironmentReviewEvidence($tenantB);
$reviewA = composeEnvironmentReviewForTest($tenantA, $user, $snapshotA);
$reviewA->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'published_at' => now()->subDay(),
'published_by_user_id' => (int) $user->getKey(),
])->save();
$reviewB = composeEnvironmentReviewForTest($tenantB, $user, $snapshotB);
$reviewB->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'published_at' => now(),
'published_by_user_id' => (int) $user->getKey(),
])->save();
$this->actingAs($user);
setAdminPanelContext();
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);
session()->put(WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY, [
(string) $tenantA->workspace_id => (int) $tenantB->getKey(),
]);
Livewire::actingAs($user)
->test(CustomerReviewWorkspace::class)
->assertSet('tableFilters.managed_environment_id.value', null)
->assertCanSeeTableRecords([$tenantA->fresh(), $tenantB->fresh()])
->filterTable('managed_environment_id', (string) $tenantB->getKey())
->assertCanSeeTableRecords([$tenantB->fresh()])
->assertCanNotSeeTableRecords([$tenantA->fresh()]);
});
it('prefilters the customer review workspace from an explicit tenant query parameter and accepts external tenant identifiers', function (): void {
$tenantA = ManagedEnvironment::factory()->create(['name' => 'Alpha ManagedEnvironment']);
[$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'readonly');
$tenantB = ManagedEnvironment::factory()->create([
'workspace_id' => (int) $tenantA->workspace_id,
'name' => 'Beta ManagedEnvironment',
]);
createUserWithTenant(tenant: $tenantB, user: $user, role: 'readonly');
$snapshotA = seedEnvironmentReviewEvidence($tenantA);
$snapshotB = seedEnvironmentReviewEvidence($tenantB);
$reviewA = composeEnvironmentReviewForTest($tenantA, $user, $snapshotA);
$reviewA->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'published_at' => now(),
'published_by_user_id' => (int) $user->getKey(),
])->save();
$reviewB = composeEnvironmentReviewForTest($tenantB, $user, $snapshotB);
$reviewB->forceFill([
'status' => EnvironmentReviewStatus::Published->value,
'published_at' => now()->subDay(),
'published_by_user_id' => (int) $user->getKey(),
])->save();
$this->actingAs($user);
setAdminPanelContext();
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);
Livewire::withQueryParams(['environment_id' => (int) $tenantA->getKey()])
->test(CustomerReviewWorkspace::class)
->assertSet('tableFilters.managed_environment_id.value', (string) $tenantA->getKey())
->filterTable('managed_environment_id', (string) $tenantA->getKey())
->assertCanSeeTableRecords([$tenantA->fresh()])
->assertCanNotSeeTableRecords([$tenantB->fresh()]);
});