--- /mnt/data/ed_runtime001/original/reconcile_ADR002.WP2_20260808_0/src/Provider/Xtree/XtreeJsonApiClient.php	2026-08-08 06:46:43.000000000 +0000
+++ /mnt/data/ed_runtime001/reconcile_ADR002.WP2_20260808_0/src/Provider/Xtree/XtreeJsonApiClient.php	2026-08-10 09:25:05.321682765 +0000
@@ -131,7 +131,6 @@
         if ($response === false) {
             $errno = curl_errno($ch);
             $error = curl_error($ch);
-            curl_close($ch);
             throw new ExternalServiceRequestException(
                 message: 'xTree login failed: ' . $error,
                 service: 'xtree',
@@ -143,8 +142,6 @@
         }
 
         $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
-        curl_close($ch);
-
        # if ($httpCode < 200 || $httpCode >= 300) {
         if (
             ($httpCode < 200 || $httpCode >= 300)
@@ -204,7 +201,6 @@
         if ($response === false) {
             $errno = curl_errno($ch);
             $error = curl_error($ch);
-            curl_close($ch);
             throw new ExternalServiceRequestException(
                 message: 'xTree API request failed: ' . $error,
                 service: 'xtree',
@@ -216,8 +212,6 @@
         }
 
         $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
-        curl_close($ch);
-
         if ($httpCode < 200 || $httpCode >= 300) {
             throw new ExternalServiceRequestException(
                 message: 'xTree API returned HTTP ' . $httpCode,
--- /mnt/data/ed_runtime001/original/reconcile_ADR002.WP2_20260808_0/src/Provider/Xtree/XtreeRdfPreviewClient.php	2026-06-25 19:16:10.000000000 +0000
+++ /mnt/data/ed_runtime001/reconcile_ADR002.WP2_20260808_0/src/Provider/Xtree/XtreeRdfPreviewClient.php	2026-08-10 09:25:05.321901710 +0000
@@ -1,180 +1,178 @@
-<?php
-
-declare(strict_types=1);
-
-namespace App\Provider\Xtree;
-
-final class XtreeRdfPreviewClient
-{
-    public function fetch(string $id): array
-    {
-        $rdfUrl = $this->toRdfUrl($id);
-
-        $ch = curl_init($rdfUrl);
-
-        curl_setopt_array($ch, [
-            CURLOPT_HEADER => false,
-            CURLOPT_RETURNTRANSFER => true,
-            CURLOPT_FOLLOWLOCATION => true,
-            CURLOPT_TIMEOUT => 10,
-            CURLOPT_HTTPHEADER => [
-                'Accept: application/rdf+xml, application/xml;q=0.9, text/xml;q=0.8',
-            ],
-        ]);
-
-        $response = curl_exec($ch);
-
-        if ($response === false) {
-            throw new \RuntimeException('xTree RDF request failed: ' . curl_error($ch));
-        }
-
-        $httpCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
-        curl_close($ch);
-
-        if ($httpCode < 200 || $httpCode >= 300) {
-            throw new \RuntimeException('xTree RDF returned HTTP ' . $httpCode);
-        }
-
-        return $this->parse($response, $rdfUrl);
-    }
-
-    private function toRdfUrl(string $id): string
-    {
-        $parts = parse_url($id);
-
-        if (
-            !isset($parts['scheme'], $parts['host'])
-            || !in_array($parts['scheme'], ['http', 'https'], true)
-        ) {
-            throw new \RuntimeException('Invalid preview id: ' . $id);
-        }
-
-        $path = $parts['path'] ?? '';
-        $path = '/' . ltrim($path, '/');
-
-        if (!str_starts_with($path, '/rdf/')) {
-            $path = '/rdf' . $path;
-        }
-
-        return $parts['scheme'] . '://' . $parts['host'] . $path;
-    }
-
-    private function parse(string $xml, string $rdfUrl): array
-    {
-        libxml_use_internal_errors(true);
-
-        $rdf = simplexml_load_string($xml);
-
-        if (!$rdf instanceof \SimpleXMLElement) {
-            throw new \RuntimeException('Invalid RDF XML from ' . $rdfUrl);
-        }
-
-        $rdf->registerXPathNamespace('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
-        $rdf->registerXPathNamespace('skos', 'http://www.w3.org/2004/02/skos/core#');
-        $rdf->registerXPathNamespace('dcterms', 'http://purl.org/dc/terms/');
-        $rdf->registerXPathNamespace('xe', 'http://xe.vocnet.org/');
-        $rdf->registerXPathNamespace('iso-thes', 'http://purl.org/iso25964/skos-thes#');
-
-        $concepts = $rdf->xpath('//skos:Concept');
-
-        if (!is_array($concepts) || count($concepts) === 0) {
-            throw new \RuntimeException('No skos:Concept found in RDF from ' . $rdfUrl);
-        }
-
-        $concept = $concepts[0];
-
-        return [
-            'about' => $this->rdfAttribute($concept, 'about'),
-            'prefLabels' => $this->literalValues($concept, 'skos:prefLabel'),
-            'altLabels' => $this->literalValues($concept, 'skos:altLabel'),
-            'broader' => $this->resourceValues($concept, 'skos:broader'),
-            'closeMatch' => $this->resourceValues($concept, 'skos:closeMatch'),
-            'exactMatch' => $this->resourceValues($concept, 'skos:exactMatch'),
-            'broadMatch' => $this->resourceValues($concept, 'skos:broadMatch'),
-            'narrowMatch' => $this->resourceValues($concept, 'skos:narrowMatch'),
-            'relatedMatch' => $this->resourceValues($concept, 'skos:relatedMatch'),
-            'definitions' => $this->literalValues($concept, 'skos:definition'),
-            'scopeNotes' => $this->literalValues($concept, 'skos:scopeNote'),
-            'status' => $this->firstLiteral($concept, ['xe:status', 'iso-thes:status']),
-            'modified' => $this->firstLiteral($concept, ['dcterms:modified']),
-        ];
-    }
-
-    private function rdfAttribute(\SimpleXMLElement $element, string $name): ?string
-    {
-        $attributes = $element->attributes('http://www.w3.org/1999/02/22-rdf-syntax-ns#');
-
-        return isset($attributes[$name]) ? (string)$attributes[$name] : null;
-    }
-
-    private function literalValues(\SimpleXMLElement $context, string $xpath): array
-    {
-        $nodes = $context->xpath($xpath);
-
-        if (!is_array($nodes)) {
-            return [];
-        }
-
-        $values = [];
-
-        foreach ($nodes as $node) {
-            $value = trim((string)$node);
-
-            if ($value === '') {
-                continue;
-            }
-
-            $langAttributes = $node->attributes('http://www.w3.org/XML/1998/namespace');
-            $lang = isset($langAttributes['lang']) ? (string)$langAttributes['lang'] : '';
-
-            $values[] = [
-                'value' => $value,
-                'lang' => $lang,
-            ];
-        }
-
-        return $values;
-    }
-
-    private function resourceValues(\SimpleXMLElement $context, string $xpath): array
-    {
-        $nodes = $context->xpath($xpath);
-
-        if (!is_array($nodes)) {
-            return [];
-        }
-
-        $values = [];
-
-        foreach ($nodes as $node) {
-            $resource = $this->rdfAttribute($node, 'resource');
-
-            if ($resource !== null && $resource !== '') {
-                $values[] = $resource;
-            }
-        }
-
-        return $values;
-    }
-
-    private function firstLiteral(\SimpleXMLElement $context, array $xpaths): ?string
-    {
-        foreach ($xpaths as $xpath) {
-            $nodes = $context->xpath($xpath);
-
-            if (!is_array($nodes)) {
-                continue;
-            }
-
-            foreach ($nodes as $node) {
-                $value = trim((string)$node);
-
-                if ($value !== '') {
-                    return $value;
-                }
-            }
-        }
-
-        return null;
-    }
+<?php
+
+declare(strict_types=1);
+
+namespace App\Provider\Xtree;
+
+final class XtreeRdfPreviewClient
+{
+    public function fetch(string $id): array
+    {
+        $rdfUrl = $this->toRdfUrl($id);
+
+        $ch = curl_init($rdfUrl);
+
+        curl_setopt_array($ch, [
+            CURLOPT_HEADER => false,
+            CURLOPT_RETURNTRANSFER => true,
+            CURLOPT_FOLLOWLOCATION => true,
+            CURLOPT_TIMEOUT => 10,
+            CURLOPT_HTTPHEADER => [
+                'Accept: application/rdf+xml, application/xml;q=0.9, text/xml;q=0.8',
+            ],
+        ]);
+
+        $response = curl_exec($ch);
+
+        if ($response === false) {
+            throw new \RuntimeException('xTree RDF request failed: ' . curl_error($ch));
+        }
+
+        $httpCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
+        if ($httpCode < 200 || $httpCode >= 300) {
+            throw new \RuntimeException('xTree RDF returned HTTP ' . $httpCode);
+        }
+
+        return $this->parse($response, $rdfUrl);
+    }
+
+    private function toRdfUrl(string $id): string
+    {
+        $parts = parse_url($id);
+
+        if (
+            !isset($parts['scheme'], $parts['host'])
+            || !in_array($parts['scheme'], ['http', 'https'], true)
+        ) {
+            throw new \RuntimeException('Invalid preview id: ' . $id);
+        }
+
+        $path = $parts['path'] ?? '';
+        $path = '/' . ltrim($path, '/');
+
+        if (!str_starts_with($path, '/rdf/')) {
+            $path = '/rdf' . $path;
+        }
+
+        return $parts['scheme'] . '://' . $parts['host'] . $path;
+    }
+
+    private function parse(string $xml, string $rdfUrl): array
+    {
+        libxml_use_internal_errors(true);
+
+        $rdf = simplexml_load_string($xml);
+
+        if (!$rdf instanceof \SimpleXMLElement) {
+            throw new \RuntimeException('Invalid RDF XML from ' . $rdfUrl);
+        }
+
+        $rdf->registerXPathNamespace('rdf', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
+        $rdf->registerXPathNamespace('skos', 'http://www.w3.org/2004/02/skos/core#');
+        $rdf->registerXPathNamespace('dcterms', 'http://purl.org/dc/terms/');
+        $rdf->registerXPathNamespace('xe', 'http://xe.vocnet.org/');
+        $rdf->registerXPathNamespace('iso-thes', 'http://purl.org/iso25964/skos-thes#');
+
+        $concepts = $rdf->xpath('//skos:Concept');
+
+        if (!is_array($concepts) || count($concepts) === 0) {
+            throw new \RuntimeException('No skos:Concept found in RDF from ' . $rdfUrl);
+        }
+
+        $concept = $concepts[0];
+
+        return [
+            'about' => $this->rdfAttribute($concept, 'about'),
+            'prefLabels' => $this->literalValues($concept, 'skos:prefLabel'),
+            'altLabels' => $this->literalValues($concept, 'skos:altLabel'),
+            'broader' => $this->resourceValues($concept, 'skos:broader'),
+            'closeMatch' => $this->resourceValues($concept, 'skos:closeMatch'),
+            'exactMatch' => $this->resourceValues($concept, 'skos:exactMatch'),
+            'broadMatch' => $this->resourceValues($concept, 'skos:broadMatch'),
+            'narrowMatch' => $this->resourceValues($concept, 'skos:narrowMatch'),
+            'relatedMatch' => $this->resourceValues($concept, 'skos:relatedMatch'),
+            'definitions' => $this->literalValues($concept, 'skos:definition'),
+            'scopeNotes' => $this->literalValues($concept, 'skos:scopeNote'),
+            'status' => $this->firstLiteral($concept, ['xe:status', 'iso-thes:status']),
+            'modified' => $this->firstLiteral($concept, ['dcterms:modified']),
+        ];
+    }
+
+    private function rdfAttribute(\SimpleXMLElement $element, string $name): ?string
+    {
+        $attributes = $element->attributes('http://www.w3.org/1999/02/22-rdf-syntax-ns#');
+
+        return isset($attributes[$name]) ? (string)$attributes[$name] : null;
+    }
+
+    private function literalValues(\SimpleXMLElement $context, string $xpath): array
+    {
+        $nodes = $context->xpath($xpath);
+
+        if (!is_array($nodes)) {
+            return [];
+        }
+
+        $values = [];
+
+        foreach ($nodes as $node) {
+            $value = trim((string)$node);
+
+            if ($value === '') {
+                continue;
+            }
+
+            $langAttributes = $node->attributes('http://www.w3.org/XML/1998/namespace');
+            $lang = isset($langAttributes['lang']) ? (string)$langAttributes['lang'] : '';
+
+            $values[] = [
+                'value' => $value,
+                'lang' => $lang,
+            ];
+        }
+
+        return $values;
+    }
+
+    private function resourceValues(\SimpleXMLElement $context, string $xpath): array
+    {
+        $nodes = $context->xpath($xpath);
+
+        if (!is_array($nodes)) {
+            return [];
+        }
+
+        $values = [];
+
+        foreach ($nodes as $node) {
+            $resource = $this->rdfAttribute($node, 'resource');
+
+            if ($resource !== null && $resource !== '') {
+                $values[] = $resource;
+            }
+        }
+
+        return $values;
+    }
+
+    private function firstLiteral(\SimpleXMLElement $context, array $xpaths): ?string
+    {
+        foreach ($xpaths as $xpath) {
+            $nodes = $context->xpath($xpath);
+
+            if (!is_array($nodes)) {
+                continue;
+            }
+
+            foreach ($nodes as $node) {
+                $value = trim((string)$node);
+
+                if ($value !== '') {
+                    return $value;
+                }
+            }
+        }
+
+        return null;
+    }
 }
\ No newline at end of file
--- /mnt/data/ed_runtime001/original/reconcile_ADR002.WP2_20260808_0/src/Provider/Lobid/LobidGndReconcileClient.php	2026-08-08 06:04:28.000000000 +0000
+++ /mnt/data/ed_runtime001/reconcile_ADR002.WP2_20260808_0/src/Provider/Lobid/LobidGndReconcileClient.php	2026-08-10 09:25:05.322055309 +0000
@@ -116,7 +116,6 @@
         if ($response === false) {
             $errno = curl_errno($curl);
             $error = curl_error($curl);
-            curl_close($curl);
             throw new ExternalServiceRequestException(
                 message: 'lobid GND reconciliation API request failed: ' . $error,
                 service: 'lobid',
@@ -128,8 +127,6 @@
         }
 
         $httpCode = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE);
-        curl_close($curl);
-
         if ($httpCode < 200 || $httpCode >= 300) {
             throw new ExternalServiceRequestException(
                 message: 'lobid GND reconciliation API returned HTTP ' . $httpCode . '.',
--- /mnt/data/ed_runtime001/original/reconcile_ADR002.WP2_20260808_0/src/Infrastructure/Persistence/Repository/RelationalReconciliationResultRepository.php	2026-07-20 20:42:57.000000000 +0000
+++ /mnt/data/ed_runtime001/reconcile_ADR002.WP2_20260808_0/src/Infrastructure/Persistence/Repository/RelationalReconciliationResultRepository.php	2026-08-10 09:25:05.874972755 +0000
@@ -51,6 +51,12 @@
         } catch (PersistenceException $exception) {
             throw $exception;
         } catch (Throwable $exception) {
+            error_log(sprintf(
+                '[reconciliation-result-persistence] %s: %s',
+                $exception::class,
+                str_replace(["\r", "\n"], ' ', $exception->getMessage()),
+            ));
+
             throw new PersistenceException('Unable to persist ReconciliationResult aggregate.', previous: $exception);
         }
     }
