create(['status' => 'active']); [$user, $tenantGovernance] = createUserWithTenant($tenantGovernance, role: 'owner', workspaceRole: 'readonly'); [$profile, $snapshot] = seedActiveBaselineForTenant($tenantGovernance); seedBaselineCompareRun($tenantGovernance, $profile, $snapshot, workspaceOverviewCompareCoverage()); Finding::factory()->for($tenantGovernance)->create([ 'workspace_id' => (int) $tenantGovernance->workspace_id, 'status' => Finding::STATUS_TRIAGED, 'due_at' => now()->subDay(), ]); $tenantActivity = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $tenantGovernance->workspace_id, 'name' => 'Busy Tenant', ]); createUserWithTenant($tenantActivity, $user, role: 'owner', workspaceRole: 'readonly'); [$activityProfile, $activitySnapshot] = seedActiveBaselineForTenant($tenantActivity); seedBaselineCompareRun($tenantActivity, $activityProfile, $activitySnapshot, workspaceOverviewCompareCoverage()); OperationRun::factory()->create([ 'tenant_id' => (int) $tenantActivity->getKey(), 'workspace_id' => (int) $tenantActivity->workspace_id, 'type' => OperationRunType::InventorySync->value, 'status' => OperationRunStatus::Running->value, 'outcome' => OperationRunOutcome::Pending->value, ]); $tenantAlerts = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $tenantGovernance->workspace_id, 'name' => 'Alerts Tenant', ]); createUserWithTenant($tenantAlerts, $user, role: 'owner', workspaceRole: 'readonly'); [$alertsProfile, $alertsSnapshot] = seedActiveBaselineForTenant($tenantAlerts); seedBaselineCompareRun($tenantAlerts, $alertsProfile, $alertsSnapshot, workspaceOverviewCompareCoverage()); AlertDelivery::factory()->create([ 'tenant_id' => (int) $tenantAlerts->getKey(), 'workspace_id' => (int) $tenantAlerts->workspace_id, 'status' => AlertDelivery::STATUS_FAILED, 'created_at' => now(), ]); $workspace = $tenantGovernance->workspace()->firstOrFail(); $overview = app(WorkspaceOverviewBuilder::class)->build($workspace, $user); expect($overview['calmness']['is_calm'])->toBeFalse() ->and($overview['attention_items'])->toHaveCount(3) ->and($overview['attention_items'][0]['key'])->toBe('tenant_overdue_findings') ->and($overview['attention_items'][0]['tenant_label'])->toBe((string) $tenantGovernance->name) ->and($overview['attention_items'][1]['key'])->toBe('tenant_active_operations') ->and($overview['attention_items'][2]['key'])->toBe('tenant_alert_delivery_failures'); }); it('surfaces expiring governance and stale compare posture as governance attention without a false calm state', function (): void { $tenantExpiring = Tenant::factory()->create(['status' => 'active']); [$user, $tenantExpiring] = createUserWithTenant($tenantExpiring, role: 'owner', workspaceRole: 'readonly'); [$expiringProfile, $expiringSnapshot] = seedActiveBaselineForTenant($tenantExpiring); seedBaselineCompareRun($tenantExpiring, $expiringProfile, $expiringSnapshot, workspaceOverviewCompareCoverage()); $finding = Finding::factory()->riskAccepted()->create([ 'workspace_id' => (int) $tenantExpiring->workspace_id, 'tenant_id' => (int) $tenantExpiring->getKey(), ]); FindingException::query()->create([ 'workspace_id' => (int) $tenantExpiring->workspace_id, 'tenant_id' => (int) $tenantExpiring->getKey(), 'finding_id' => (int) $finding->getKey(), 'requested_by_user_id' => (int) $user->getKey(), 'owner_user_id' => (int) $user->getKey(), 'approved_by_user_id' => (int) $user->getKey(), 'status' => FindingException::STATUS_EXPIRING, 'current_validity_state' => FindingException::VALIDITY_EXPIRING, 'request_reason' => 'Governance nearly expired', 'approval_reason' => 'Accepted for a short window', 'requested_at' => now()->subDays(2), 'approved_at' => now()->subDay(), 'effective_from' => now()->subDay(), 'expires_at' => now()->addDay(), 'review_due_at' => now()->addDay(), 'evidence_summary' => ['reference_count' => 0], ]); $tenantStale = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $tenantExpiring->workspace_id, 'name' => 'Stale Tenant', ]); createUserWithTenant($tenantStale, $user, role: 'owner', workspaceRole: 'readonly'); [$staleProfile, $staleSnapshot] = seedActiveBaselineForTenant($tenantStale); seedBaselineCompareRun( $tenantStale, $staleProfile, $staleSnapshot, workspaceOverviewCompareCoverage(), completedAt: now()->subDays(10), ); $workspace = $tenantExpiring->workspace()->firstOrFail(); $overview = app(WorkspaceOverviewBuilder::class)->build($workspace, $user); $items = collect($overview['attention_items'])->keyBy('key'); expect($overview['calmness']['is_calm'])->toBeFalse() ->and($items->keys()->all())->toContain('tenant_expiring_governance', 'tenant_compare_attention') ->and($items->get('tenant_compare_attention')['badge'])->toBe('Baseline') ->and($items->get('tenant_expiring_governance')['family'])->toBe('governance'); }); it('ranks lapsed governance and failed compare posture ahead of high-severity findings', function (): void { $tenantLapsed = Tenant::factory()->create(['status' => 'active']); [$user, $tenantLapsed] = createUserWithTenant($tenantLapsed, role: 'owner', workspaceRole: 'readonly'); [$lapsedProfile, $lapsedSnapshot] = seedActiveBaselineForTenant($tenantLapsed); seedBaselineCompareRun($tenantLapsed, $lapsedProfile, $lapsedSnapshot, workspaceOverviewCompareCoverage()); Finding::factory()->riskAccepted()->create([ 'workspace_id' => (int) $tenantLapsed->workspace_id, 'tenant_id' => (int) $tenantLapsed->getKey(), ]); $tenantFailedCompare = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $tenantLapsed->workspace_id, 'name' => 'Failed Compare Tenant', ]); createUserWithTenant($tenantFailedCompare, $user, role: 'owner', workspaceRole: 'readonly'); [$failedProfile, $failedSnapshot] = seedActiveBaselineForTenant($tenantFailedCompare); seedBaselineCompareRun( $tenantFailedCompare, $failedProfile, $failedSnapshot, workspaceOverviewCompareCoverage(), outcome: OperationRunOutcome::Failed->value, ); $tenantHighSeverity = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $tenantLapsed->workspace_id, 'name' => 'High Severity Tenant', ]); createUserWithTenant($tenantHighSeverity, $user, role: 'owner', workspaceRole: 'readonly'); [$highProfile, $highSnapshot] = seedActiveBaselineForTenant($tenantHighSeverity); seedBaselineCompareRun($tenantHighSeverity, $highProfile, $highSnapshot, workspaceOverviewCompareCoverage()); Finding::factory()->for($tenantHighSeverity)->create([ 'workspace_id' => (int) $tenantHighSeverity->workspace_id, 'status' => Finding::STATUS_TRIAGED, 'severity' => Finding::SEVERITY_CRITICAL, ]); $workspace = $tenantLapsed->workspace()->firstOrFail(); $overview = app(WorkspaceOverviewBuilder::class)->build($workspace, $user); expect(collect($overview['attention_items'])->pluck('key')->take(3)->all()) ->toBe([ 'tenant_lapsed_governance', 'tenant_compare_attention', 'tenant_high_severity_findings', ]); });