diff --git a/api/blade-actions-surfaced.json b/api/blade-actions-surfaced.json index 2edffa564..5fc7f3cf1 100644 --- a/api/blade-actions-surfaced.json +++ b/api/blade-actions-surfaced.json @@ -1,14 +1,14 @@ { - "generated_at": "2026-04-19T17:05:01.629888", + "generated_at": "2026-04-19T17:10:02.091136", "stats": { - "total": 450, - "pending": 861, + "total": 449, + "pending": 859, "kaouther_surfaced": 29, "chrome_surfaced": 10, "notif_only_done": 0, "autofix_archived": 0, "cerebras_archived": 0, - "older_3d_archived": 2, + "older_3d_archived": 1, "unknown": 409, "errors": 0 }, diff --git a/api/blade-tasks/task_20260416_170718_e16e10.json b/api/blade-tasks/task_20260416_170718_e16e10.json deleted file mode 100644 index 832f7d089..000000000 --- a/api/blade-tasks/task_20260416_170718_e16e10.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "id": "task_20260416_170718_e16e10", - "type": "powershell", - "cmd": "az ad app list --all --query \"[].{name:displayName,appId:appId}\" --output table 2>&1 | Out-String", - "label": "AZ-AD-APPS-V3", - "priority": 10, - "status": "pending", - "created": "2026-04-16T17:07:18+00:00", - "started": null, - "completed": null, - "result": null, - "error": null, - "source": "api" -} \ No newline at end of file diff --git a/api/opus5-orphans-hub.php b/api/opus5-orphans-hub.php new file mode 100644 index 000000000..43dd3c150 --- /dev/null +++ b/api/opus5-orphans-hub.php @@ -0,0 +1,105 @@ +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