ensureRunWithIdentity( tenant: $tenant, type: 'inventory_sync', identityInputs: ['selection_hash' => 'abc123'], context: ['selection_hash' => 'abc123'], initiator: $user, ); $service->updateRun( $run, status: OperationRunStatus::Completed->value, outcome: OperationRunOutcome::Succeeded->value, summaryCounts: [ 'total' => 3, 'processed' => 3, 'succeeded' => 3, 'failed' => 0, ], ); $audit = AuditLog::query() ->where('operation_run_id', (int) $run->getKey()) ->latest('id') ->first(); expect($audit)->not->toBeNull(); expect($audit?->action)->toBe('operation.completed') ->and($audit?->summaryText())->toBe('Inventory sync completed') ->and($audit?->resource_type)->toBe('operation_run') ->and((string) $audit?->resource_id)->toBe((string) $run->getKey()) ->and($audit?->normalizedOutcome())->toBe(AuditOutcome::Success) ->and($audit?->actorDisplayLabel())->toBe($user->name) ->and(data_get($audit?->metadata, 'operation_type'))->toBe('inventory_sync'); }); it('writes blocked terminal audit semantics for blocked runs', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $service = app(OperationRunService::class); $run = $service->ensureRunWithIdentity( tenant: $tenant, type: 'restore.execute', identityInputs: ['restore_run_id' => 44], context: ['restore_run_id' => 44], initiator: $user, ); $service->finalizeBlockedRun( $run, reasonCode: 'intune_rbac.not_configured', message: 'Restore is blocked until RBAC is configured.', ); $audit = AuditLog::query() ->where('operation_run_id', (int) $run->getKey()) ->latest('id') ->first(); expect($audit)->not->toBeNull(); expect($audit?->action)->toBe('operation.blocked') ->and($audit?->summaryText())->toBe('Restore execution blocked') ->and($audit?->normalizedOutcome())->toBe(AuditOutcome::Blocked) ->and(data_get($audit?->metadata, 'failure_summary.0.reason_code'))->toBe('intune_rbac.not_configured'); });