create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'user_id' => (int) $user->getKey(), 'type' => 'policy.sync', 'status' => OperationRunStatus::Queued->value, 'outcome' => OperationRunOutcome::Pending->value, 'created_at' => now()->subMinutes(20), ]); $this->artisan('tenantpilot:operation-runs:reconcile', [ '--tenant' => [(string) $tenant->getKey()], '--type' => ['policy.sync'], ]) ->assertSuccessful() ->expectsOutputToContain('reconciled 1'); expect($run->fresh()->status)->toBe(OperationRunStatus::Completed->value) ->and(data_get($run->fresh()->context, 'reconciliation.reason_code'))->toBe('run.stale_queued'); }); it('supports dry-run mode without mutating runs', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $run = OperationRun::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'user_id' => (int) $user->getKey(), 'type' => 'policy.sync', 'status' => OperationRunStatus::Queued->value, 'outcome' => OperationRunOutcome::Pending->value, 'created_at' => now()->subMinutes(20), ]); $this->artisan('tenantpilot:operation-runs:reconcile', [ '--tenant' => [(string) $tenant->getKey()], '--type' => ['policy.sync'], '--dry-run' => true, ])->assertSuccessful(); expect($run->fresh()->status)->toBe(OperationRunStatus::Queued->value) ->and($run->fresh()->outcome)->toBe(OperationRunOutcome::Pending->value); });