toBeTrue(); }); it('backfills summary, actor, and outcome semantics for legacy audit rows', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $audit = AuditLog::query()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'tenant_id' => (int) $tenant->getKey(), 'actor_email' => 'ops@example.com', 'action' => 'restore.failed', 'resource_type' => 'restore_run', 'resource_id' => '55', 'status' => 'error', 'metadata' => [ 'reason_code' => 'graph.unavailable', ], 'recorded_at' => now(), ])->refresh(); expect($audit->summaryText())->toBe('Restore failed for Restore run #55') ->and($audit->normalizedOutcome())->toBe(AuditOutcome::Failed) ->and($audit->actorSnapshot()->type)->toBe(AuditActorType::Human) ->and($audit->actorDisplayLabel())->toBe('ops@example.com') ->and($audit->targetDisplayLabel())->toBe('Restore run #55'); }); it('keeps target labels intelligible when the source record no longer exists', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $audit = AuditLog::query()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'tenant_id' => (int) $tenant->getKey(), 'action' => 'backup.archived', 'resource_type' => 'backup_set', 'resource_id' => '999999', 'status' => 'success', 'metadata' => [], 'recorded_at' => now(), ])->refresh(); expect($audit->targetDisplayLabel())->toBe('Backup set #999999') ->and($audit->summaryText())->toBe('Backup set archived for Backup set #999999'); });