now()->subMinutes(10), ]); workspaceOverviewSeedRestoreHistory($tenant, $backupSet, 'completed'); OperationRun::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'type' => 'inventory_sync', 'status' => OperationRunStatus::Running->value, 'outcome' => 'pending', ]); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]) ->get('/admin') ->assertOk() ->assertSee('Workspace overview') ->assertSee('Accessible tenants') ->assertSee('Governance attention') ->assertSee('Backup attention') ->assertSee('Recovery attention') ->assertSee('Active operations') ->assertSee('Needs attention') ->assertSee('Recent operations') ->assertSee('Choose tenant') ->assertSee('Open operations') ->assertSee('Open alerts') ->assertSee('Review current and recent workspace-wide operations.') ->assertSee('Activity only. Active execution does not imply governance health.') ->assertSee('Visible tenants with non-healthy backup posture.') ->assertSee('Visible tenants with weakened or unvalidated recovery evidence.') ->assertSee('Governance risk counts affected tenants') ->assertSee('Backup health stays separate from recovery evidence') ->assertSee('Calm wording stays bounded to visible tenants and checked domains') ->assertSee('Inventory sync'); }); it('keeps multi-tenant backup and recovery metric drilldowns on the registry when multiple tenants remain in scope', function (): void { [$user, $anchorTenant] = createUserWithTenant(role: 'owner', workspaceRole: 'readonly'); workspaceOverviewSeedQuietTenantTruth($anchorTenant); $backupTenant = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $anchorTenant->workspace_id, 'name' => 'Backup Attention Tenant', ]); createUserWithTenant($backupTenant, $user, role: 'owner', workspaceRole: 'readonly'); workspaceOverviewSeedQuietTenantTruth($backupTenant); workspaceOverviewSeedHealthyBackup($backupTenant, [ 'completed_at' => now()->subDays(2), ]); $backupTenantB = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $anchorTenant->workspace_id, 'name' => 'Backup Attention Tenant B', ]); createUserWithTenant($backupTenantB, $user, role: 'owner', workspaceRole: 'readonly'); workspaceOverviewSeedQuietTenantTruth($backupTenantB); workspaceOverviewSeedHealthyBackup($backupTenantB, [ 'completed_at' => now()->subMinutes(19), ], [ 'payload' => [], 'metadata' => [ 'source' => 'metadata_only', 'assignments_fetch_failed' => true, ], 'assignments' => [], ]); $recoveryTenantA = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $anchorTenant->workspace_id, 'name' => 'Recovery Attention Tenant A', ]); createUserWithTenant($recoveryTenantA, $user, role: 'owner', workspaceRole: 'readonly'); workspaceOverviewSeedQuietTenantTruth($recoveryTenantA); $recoveryBackupA = workspaceOverviewSeedHealthyBackup($recoveryTenantA, [ 'completed_at' => now()->subMinutes(18), ]); workspaceOverviewSeedRestoreHistory($recoveryTenantA, $recoveryBackupA, 'failed'); $recoveryTenantB = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $anchorTenant->workspace_id, 'name' => 'Recovery Attention Tenant B', ]); createUserWithTenant($recoveryTenantB, $user, role: 'owner', workspaceRole: 'readonly'); workspaceOverviewSeedQuietTenantTruth($recoveryTenantB); $recoveryBackupB = workspaceOverviewSeedHealthyBackup($recoveryTenantB, [ 'completed_at' => now()->subMinutes(17), ]); workspaceOverviewSeedRestoreHistory($recoveryTenantB, $recoveryBackupB, 'follow_up'); $overview = app(WorkspaceOverviewBuilder::class)->build($anchorTenant->workspace()->firstOrFail(), $user); $metrics = collect($overview['summary_metrics'])->keyBy('key'); expect($metrics->get('backup_attention_tenants')['destination']['kind'])->toBe('choose_tenant') ->and($metrics->get('backup_attention_tenants')['destination_url'])->toContain(TenantResource::getUrl('index', panel: 'admin')) ->and($metrics->get('backup_attention_tenants')['destination_url'])->not->toContain('arrival=') ->and($metrics->get('recovery_attention_tenants')['destination']['kind'])->toBe('choose_tenant') ->and($metrics->get('recovery_attention_tenants')['destination_url'])->toContain(TenantResource::getUrl('index', panel: 'admin')) ->and($metrics->get('recovery_attention_tenants')['destination_url'])->not->toContain('arrival='); });