create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'type' => 'policy.sync', 'status' => 'running', 'outcome' => 'pending', 'started_at' => now()->subMinutes(20), 'created_at' => now()->subMinutes(20), ]); $reconciledRun = OperationRun::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'type' => 'restore.execute', 'status' => 'completed', 'outcome' => 'failed', 'context' => [ 'reason_code' => 'run.adapter_out_of_sync', 'reconciliation' => [ 'reconciled_at' => now()->toIso8601String(), 'reason' => 'run.adapter_out_of_sync', 'reason_code' => 'run.adapter_out_of_sync', 'source' => 'adapter_reconciler', ], ], 'failure_summary' => [[ 'code' => 'run.adapter_out_of_sync', 'reason_code' => 'run.adapter_out_of_sync', 'message' => 'A related restore record reached terminal truth before the operation run was updated.', ]], ]); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]) ->get('/admin/operations') ->assertOk() ->assertSee('Likely stale') ->assertSee('run(s) have already been automatically reconciled'); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]) ->get(route('admin.operations.view', ['run' => (int) $reconciledRun->getKey()])) ->assertOk() ->assertSee('Automatically reconciled'); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]) ->get(route('admin.operations.view', ['run' => (int) $staleRun->getKey()])) ->assertOk() ->assertSee('Likely stale run'); }); it('renders lifecycle outcome fallbacks when historical runs are missing stored outcomes', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $staleRun = OperationRun::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'type' => 'policy.sync', 'status' => 'running', 'outcome' => '', 'started_at' => now()->subMinutes(20), 'created_at' => now()->subMinutes(20), ]); $reconciledRun = OperationRun::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'type' => 'restore.execute', 'status' => 'completed', 'outcome' => '', 'context' => [ 'reason_code' => 'run.adapter_out_of_sync', 'reconciliation' => [ 'reconciled_at' => now()->toIso8601String(), 'reason' => 'run.adapter_out_of_sync', 'reason_code' => 'run.adapter_out_of_sync', 'source' => 'adapter_reconciler', ], ], 'failure_summary' => [[ 'code' => 'run.adapter_out_of_sync', 'reason_code' => 'run.adapter_out_of_sync', 'message' => 'A related restore record reached terminal truth before the operation run was updated.', ]], ]); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]) ->get('/admin/operations') ->assertOk() ->assertSee('Awaiting result'); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]) ->get(route('admin.operations.view', ['run' => (int) $staleRun->getKey()])) ->assertOk() ->assertSee('Awaiting result'); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]) ->get(route('admin.operations.view', ['run' => (int) $reconciledRun->getKey()])) ->assertOk() ->assertSee('Reconciled failed'); });