date('c'), 'source'=>'opus5-orphans-hub-merged']; // === 1. Fetch V82 mapper (8 suites métier) === $ch = curl_init('http://127.0.0.1/api/wevia-orphans-mapper.php'); curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>8, CURLOPT_FOLLOWLOCATION=>true]); $v82_raw = curl_exec($ch); curl_close($ch); $v82 = @json_decode((string)$v82_raw, true) ?: []; // === 2. Fetch doctrine 91 classifier === $ch = curl_init('http://127.0.0.1/api/opus5-orphans-classifier.php'); curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>8, CURLOPT_FOLLOWLOCATION=>true]); $d91_raw = curl_exec($ch); curl_close($ch); $d91 = @json_decode((string)$d91_raw, true) ?: []; // === 3. Index by page name for cross-reference === // V82: mapping[suite] = [ {name, url, size_kb, class, title}, ... ] // D91: classification[LEGITIMATE_ARCHIVE|ACTIVE_ORPHAN|DORMANT_CANDIDATE] = [ {page, reason, ...} ] $suite_by_page = []; foreach (($v82['mapping'] ?? []) as $suite => $items) { foreach ($items as $item) { $suite_by_page[$item['name'] ?? ''] = [ 'suite' => $suite, 'title' => $item['title'] ?? '', 'size_kb' => $item['size_kb'] ?? 0, 'class' => $item['class'] ?? '' ]; } } $d91_by_page = []; foreach ($d91['classification']['LEGITIMATE_ARCHIVE'] ?? [] as $p) $d91_by_page[$p['page']] = ['status'=>'ARCHIVE','reason'=>$p['reason']]; foreach ($d91['classification']['ACTIVE_ORPHAN'] ?? [] as $p) $d91_by_page[$p['page']] = ['status'=>'ACTIVE','reason'=>$p['reason']]; foreach ($d91['classification']['DORMANT_CANDIDATE'] ?? [] as $p) $d91_by_page[$p['page']] = ['status'=>'DORMANT','reason'=>'user_decision_required']; // === 4. Merge : pour chaque orphan, donne suite + status classifier === $merged = []; foreach ($suite_by_page as $page => $meta) { $classif = $d91_by_page[$page] ?? ['status'=>'UNKNOWN','reason'=>'']; $merged[] = [ 'page' => $page, 'url' => '/' . $page, 'title' => $meta['title'], 'size_kb' => $meta['size_kb'], 'class' => $meta['class'], 'suite_v82' => $meta['suite'], 'classif_d91' => $classif['status'], 'reason' => $classif['reason'] ]; } // Sort : ACTIVE first (priorité action), puis DORMANT, puis ARCHIVE usort($merged, function($a,$b) { $order = ['ACTIVE'=>0, 'DORMANT'=>1, 'ARCHIVE'=>2, 'UNKNOWN'=>3]; return ($order[$a['classif_d91']] ?? 99) - ($order[$b['classif_d91']] ?? 99); }); // === 5. Action generator : snippet HTML prêt à injecter dans WTP drawer === $active_pages = array_filter($merged, fn($x) => $x['classif_d91'] === 'ACTIVE'); $snippet_lines = ['', '']; $snippet_lines[] = '
'; $snippet_html = implode("\n", $snippet_lines); // === 6. Stats === $stats = [ 'total_orphans' => count($merged), 'active_to_link' => count($active_pages), 'dormant_candidate' => count(array_filter($merged, fn($x) => $x['classif_d91'] === 'DORMANT')), 'archive_legit' => count(array_filter($merged, fn($x) => $x['classif_d91'] === 'ARCHIVE')), 'suites_v82' => count($v82['mapping'] ?? []), 'v82_total' => $v82['total_orphans'] ?? 0, 'd91_total' => $d91['summary']['total_orphans'] ?? 0, 'sync_ok' => ($v82['total_orphans'] ?? 0) === ($d91['summary']['total_orphans'] ?? 0) ]; $R['stats'] = $stats; $R['merged'] = $merged; $R['snippet_html'] = $snippet_html; $R['wtp_inject_ready'] = true; $R['wtp_inject_note'] = 'Copier snippet_html AVANT