decision->evaluate($run); } public function reconcileException(OperationRun $run, Throwable $throwable): ?ReconciliationResult { if (! $throwable instanceof QueryException || ! $this->isUniqueViolation($throwable)) { return null; } return ReconciliationResult::attentionRequired( reasonCode: LifecycleReconciliationReason::AdapterOutOfSync->value, reasonMessage: 'TenantPilot found matching review activity, but it could not be resolved automatically.', evidence: [ 'adapter' => EnvironmentReviewComposeDecision::ADAPTER, 'exception_class' => class_basename($throwable), 'workspace_id' => (int) $run->workspace_id, 'managed_environment_id' => (int) $run->managed_environment_id, 'fingerprint' => (string) data_get($run->context, 'review_fingerprint', ''), ], ); } private function isUniqueViolation(QueryException $exception): bool { return in_array(($exception->errorInfo[0] ?? null), ['23505', '23000'], true); } }