308 lines
14 KiB
PHP
308 lines
14 KiB
PHP
<?php
|
|
/* ═══════════════════════════════════════════════════════════════════
|
|
NL AUDIT HANDLER - PHASE 1
|
|
5 sous-handlers réels pour répondre aux questions NL ouvertes
|
|
═══════════════════════════════════════════════════════════════════
|
|
Questions type couvertes:
|
|
1. "baseline / invariants / derniers commits / tags / waves"
|
|
2. "KPI source / weval-technology-platform / coverage / agents / hcps"
|
|
3. "doublons / hubs / dashboards chevauchement / référentiel"
|
|
4. "orphelines / pages non liées / API sans caller"
|
|
5. "auto-wire / intents auto-créés / autonomie"
|
|
6. "tips / selenium / tokens / recovery / cookies"
|
|
═══════════════════════════════════════════════════════════════════ */
|
|
|
|
set_time_limit(22);
|
|
ini_set("max_execution_time", 22);
|
|
|
|
function nl_audit_route($msg) {
|
|
$lo = mb_strtolower($msg);
|
|
|
|
// Keyword routing
|
|
$m_baseline = preg_match('/baseline|invariant|derniers?\s+commits?|derniers?\s+tags?|waves?\s+\d|wave-?\d/', $lo);
|
|
$m_kpi = preg_match('/kpi|weval-?technology|wtp|coverage|source|hcps|agents\s|sovereign|intents\s|skills|tools|doctrines|rag|couverage|chiffres?/', $lo);
|
|
$m_dbl = preg_match('/doublons?|chevauch|hubs?|dashboards?|refer?entiel|unique|ecrans?|consolid/', $lo);
|
|
$m_orph = preg_match('/orphelin|non\s+li[ée]|sans\s+caller|perdu|isol[ée]|sans\s+lien/', $lo);
|
|
$m_auto = preg_match('/auto-?wire|autonomie|auto-?creer?|auto-?train|autotrain|self-?wire|auto-?cree|creer\s+intent/', $lo);
|
|
$m_tips = preg_match('/tips?\s|selenium|recovery|rotation|cookies?|token(?!_)|mythos|deepseek|thuggie|gemini|qwen|claude\.ai|bypass|cracker?/', $lo);
|
|
|
|
$results = [];
|
|
|
|
if ($m_baseline) $results[] = handler_baseline();
|
|
if ($m_kpi) $results[] = handler_kpi_source();
|
|
if ($m_dbl) $results[] = handler_dashboards_overlap();
|
|
if ($m_orph) $results[] = handler_orphan_pages();
|
|
if ($m_auto) $results[] = handler_autowire_capabilities();
|
|
if ($m_tips) $results[] = handler_tips_library();
|
|
|
|
if (empty($results)) {
|
|
// Fallback: full audit
|
|
$results = [handler_baseline(), handler_kpi_source()];
|
|
}
|
|
|
|
return implode("\n\n═══════════════════════════════════════════════\n\n", $results);
|
|
}
|
|
|
|
// ═══════════════ Sous-handlers ═══════════════
|
|
|
|
function handler_baseline() {
|
|
$out = "=== BASELINE INVARIANTS ===\n";
|
|
// NR
|
|
$nr = @json_decode(@file_get_contents("http://127.0.0.1/api/nonreg-api.php?cat=summary"), true);
|
|
if ($nr) $out .= sprintf("NonReg : %d/%d (ts %s)\n", $nr['pass'] ?? 0, $nr['total'] ?? 0, $nr['ts'] ?? '?');
|
|
// L99
|
|
$l99 = @json_decode(@shell_exec("curl -sk -m 3 http://127.0.0.1/api/l99-api.php?action=stats 2>/dev/null"), true);
|
|
if ($l99 && isset($l99['passed'])) $out .= sprintf("L99 : %d/%d\n", $l99['passed'], $l99['total']);
|
|
// Commits récents
|
|
$commits = trim(@shell_exec("cd /var/www/html && git log --oneline -10 2>&1"));
|
|
$out .= "\n-- 10 derniers commits --\n" . $commits;
|
|
// Tags récents
|
|
$tags = trim(@shell_exec("cd /var/www/html && git tag --sort=-creatordate 2>&1 | head -10"));
|
|
$out .= "\n\n-- 10 derniers tags --\n" . $tags;
|
|
// Wave-267→270 + Doctrine 133/134
|
|
$doctrines = [];
|
|
foreach (["133","134"] as $n) {
|
|
$p = "/opt/wevads/vault/doctrine-{$n}-*.md";
|
|
$f = glob($p);
|
|
$doctrines[] = "doctrine-$n: " . (empty($f) ? "MISSING" : basename($f[0]));
|
|
}
|
|
$out .= "\n\n-- Doctrines récentes --\n" . implode("\n", $doctrines);
|
|
return $out;
|
|
}
|
|
|
|
function handler_kpi_source() {
|
|
$out = "=== KPI SOURCES - REFERENTIEL UNIQUE ===
|
|
";
|
|
$out .= "Source UNIQUE: /api/source-of-truth.json (rebuild cron 10min - doctrine 136)
|
|
";
|
|
$out .= "Full registry: /api/wevia-truth-registry.json (1.78MB detail)
|
|
";
|
|
$out .= "Aggregator KPI: /api/wtp-kpi-global-v2.php (cache 30s)
|
|
|
|
";
|
|
|
|
// Source primary: source-of-truth.json (fresh, rebuilt every 10min)
|
|
$sot = @json_decode(@file_get_contents("/var/www/html/api/source-of-truth.json"), true);
|
|
if ($sot) {
|
|
$age = time() - filemtime("/var/www/html/api/source-of-truth.json");
|
|
$out .= sprintf("-- source-of-truth.json (age %ds) --
|
|
", $age);
|
|
foreach (["agents_count","skills_count","intents_count","brains_count","doctrines_count","dashboards_count","providers_count","ethica_total","docker_running","nonreg_score","autonomy_score","autonomy_level"] as $k) {
|
|
if (isset($sot[$k])) $out .= sprintf(" %-20s: %s
|
|
", $k, $sot[$k]);
|
|
}
|
|
}
|
|
|
|
// Complement: wtp-kpi-global-v2
|
|
$agg = @json_decode(@file_get_contents("http://127.0.0.1/api/wtp-kpi-global-v2.php"), true);
|
|
if ($agg && isset($agg["synthesis"])) {
|
|
$out .= "
|
|
-- wtp-kpi-global-v2.php synthesis --
|
|
";
|
|
foreach ($agg["synthesis"] as $k => $v) {
|
|
$out .= sprintf(" %-25s: %s
|
|
", $k, $v === null ? "null" : $v);
|
|
}
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
function handler_dashboards_overlap() {
|
|
$out = "=== DASHBOARDS / HUBS OVERLAP ===\n";
|
|
$hubs = [
|
|
'weval-technology-platform.html' => 'WTP — ERP portal',
|
|
'all-ia-hub.html' => 'All IA Hub',
|
|
'wevia-master.html' => 'WEVIA Master chat',
|
|
'wevia-orchestrator.html' => 'Arena Orchestrator',
|
|
'ops-center.html' => 'Ops Center',
|
|
'architecture.html' => 'Architecture',
|
|
'agents-archi.html' => 'Agents archi 3D',
|
|
];
|
|
foreach ($hubs as $file => $desc) {
|
|
$path = "/var/www/html/$file";
|
|
if (!file_exists($path)) {
|
|
$out .= sprintf(" [MISSING] %-40s %s\n", $file, $desc);
|
|
continue;
|
|
}
|
|
$sz = round(filesize($path)/1024);
|
|
// Count KPI fetches in each
|
|
$c = @file_get_contents($path);
|
|
$n_fetch = preg_match_all('/fetch\s*\(\s*[\'"][^\'"]*\/api\//', $c);
|
|
$n_api = preg_match_all('/\/api\/[a-z0-9_\-]+\.(?:php|json)/i', $c);
|
|
$out .= sprintf(" %-40s %3dKB · %d fetch · %d api refs · %s\n", $file, $sz, $n_fetch, $n_api, $desc);
|
|
}
|
|
// Source unique reco
|
|
$out .= "\n-- Source unique KPI existante --\n";
|
|
$out .= " /api/wtp-kpi-global-v2.php (cache 30s, 12 KPI agrégés)\n";
|
|
$out .= " → Recommandation: TOUS les hubs consomment cette API\n";
|
|
return $out;
|
|
}
|
|
|
|
function handler_orphan_pages() {
|
|
$out = "=== PAGES ORPHELINES (detection exhaustive) ===
|
|
";
|
|
$html_dir = "/var/www/html";
|
|
$all = glob("$html_dir/*.html");
|
|
$total = count($all);
|
|
|
|
// Scanner hubs principaux
|
|
$hubs = ["weval-technology-platform.html","all-ia-hub.html","wevia-master.html",
|
|
"wevia-orchestrator.html","ops-center.html","architecture.html",
|
|
"agents-archi.html","index.html","login.html","register.html","404.html",
|
|
"dashboards-index.html","wiki.html","wevia.html"];
|
|
|
|
// Scan TOUS les .html comme referenceurs (pas juste hubs)
|
|
$linked = [];
|
|
foreach ($all as $p) {
|
|
$c = @file_get_contents($p);
|
|
if (!$c) continue;
|
|
// Pattern exhaustif: href, src, window.open, location.href, string "/foo.html"
|
|
$patterns = [
|
|
'/(?:href|src|action)=["\']([^"\']+\.html)["\']/i',
|
|
'/window\.(?:open|location\.href)\s*=\s*["\']([^"\']+\.html)/',
|
|
'/location\.(?:href|replace|assign)\s*\(\s*["\']([^"\']+\.html)/',
|
|
'/navigateTo\(["\']([^"\']+\.html)/',
|
|
'/["\'](\/[a-z0-9_\-]+\.html)["\']/i',
|
|
];
|
|
foreach ($patterns as $pat) {
|
|
if (preg_match_all($pat, $c, $mm)) {
|
|
foreach ($mm[1] as $target) {
|
|
$target = ltrim($target, "/");
|
|
$target = explode("?", explode("#", $target)[0])[0];
|
|
$linked[$target] = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$orphans = [];
|
|
foreach ($all as $p) {
|
|
$name = basename($p);
|
|
if (in_array($name, $hubs)) continue;
|
|
if (isset($linked[$name])) continue;
|
|
$orphans[] = [
|
|
"name" => $name,
|
|
"size_kb" => round(filesize($p)/1024, 1),
|
|
"age_days" => intval((time() - filemtime($p))/86400),
|
|
];
|
|
}
|
|
usort($orphans, fn($a,$b) => $b["size_kb"] - $a["size_kb"]);
|
|
|
|
$out .= sprintf("Total .html scannes: %d
|
|
", $total);
|
|
$out .= sprintf("Linked (refs JS + HTML): %d
|
|
", count($linked));
|
|
$out .= sprintf("Orphelines VRAIES (zero ref nulle part): %d
|
|
|
|
", count($orphans));
|
|
if (count($orphans) === 0) {
|
|
$out .= "Aucune orpheline detectee. Architecture totalement reliee.
|
|
";
|
|
} else {
|
|
$out .= "-- Liste detail --
|
|
";
|
|
foreach ($orphans as $o) {
|
|
$out .= sprintf(" %-60s %6.1fKB %3dj
|
|
", $o["name"], $o["size_kb"], $o["age_days"]);
|
|
}
|
|
$out .= "
|
|
-- Action PHASE 3A --
|
|
";
|
|
$out .= " Ces pages ne sont linkees de nulle part. Choix:
|
|
";
|
|
$out .= " 1. Relier dans un hub (si utile)
|
|
";
|
|
$out .= " 2. Documenter en intent explicite (chat-v2 peut y renvoyer)
|
|
";
|
|
$out .= " 3. Supprimer apres GOLD + validation Yacine (ZERO suppression sans accord)
|
|
";
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
function handler_autowire_capabilities() {
|
|
$out = "=== AUTO-WIRE CAPABILITIES ===\n";
|
|
// Opus-intents file analysis
|
|
$opus_file = "/var/www/html/api/opus-intents.php";
|
|
if (file_exists($opus_file)) {
|
|
$c = file_get_contents($opus_file);
|
|
$n_intents = preg_match_all('/^\s*(?:case\s+["\']|if\s*\(.*preg_match|elseif\s*\(.*preg_match|\$map\[.*=>)/m', $c);
|
|
$out .= sprintf("opus-intents.php : %d KB, ~%d intents detected\n", round(strlen($c)/1024), $n_intents);
|
|
}
|
|
// Priority NL intents
|
|
$pri = @json_decode(@file_get_contents("/opt/wevia-brain/priority-intents-nl.json"), true);
|
|
$out .= sprintf("priority-intents-nl.json : %d intents\n", is_array($pri) ? count($pri) : 0);
|
|
// Fast-path
|
|
$fp = "/var/www/weval/wevia-ia/wevia-fast-path-v3.php";
|
|
if (file_exists($fp)) {
|
|
$c = @file_get_contents($fp);
|
|
$n = preg_match_all('/preg_match|case\s+["\']/i', $c ?: '');
|
|
$out .= sprintf("fast-path-v3.php : %d intents approx\n", $n);
|
|
}
|
|
// Opus46 intents
|
|
$o46 = glob("/var/www/html/api/wevia-opus46-intents.php")[0] ?? null;
|
|
if ($o46) {
|
|
$c = file_get_contents($o46);
|
|
$n = preg_match_all('/^\s*(?:if|elseif)\s*\(.*preg_match/m', $c);
|
|
$out .= sprintf("opus46-intents.php : %d intents EXEC\n", $n);
|
|
}
|
|
// Auto-wired 30 days: git log filter
|
|
$auto_commits = trim(@shell_exec("cd /var/www/html && git log --since='30 days ago' --grep='intent\\|autowire\\|auto-wire' --oneline 2>&1 | wc -l"));
|
|
$out .= sprintf("Commits auto-wire 30 derniers jours : %s\n", $auto_commits ?: '0');
|
|
// Capabilities check
|
|
$out .= "\n-- Capabilities check --\n";
|
|
$out .= " [YES] Exécution shell: shell_exec disponible\n";
|
|
$out .= " [YES] Git commit: sudo NOPASSWD OK\n";
|
|
$out .= " [YES] PHP self-patch: sudo chattr +i/-i OK\n";
|
|
$sel_exists = file_exists("/opt/weval-ops/selenium-runner.py") || file_exists("/home/claude/selenium-runner.py") ? "partial" : "MISSING";
|
|
$out .= " [" . strtoupper($sel_exists) . "] Selenium Chrome: runner centralisé\n";
|
|
$blade_log = glob("/var/log/blade-sentinel.log");
|
|
$out .= " [" . (empty($blade_log) ? "MISSING" : "OK") . "] Blade Sentinel: log récent\n";
|
|
$out .= "\n-- GAP d'autonomie (à combler PHASE 3) --\n";
|
|
$out .= " * Pas d'intent 'auto_wire' capable de créer un nouvel intent depuis NL\n";
|
|
$out .= " * Pas d'intent 'clone_github_tool' capable de cloner+adapter un tool OSS\n";
|
|
$out .= " * Selenium Chrome runner centralisé absent → création compte via Blade impossible\n";
|
|
return $out;
|
|
}
|
|
|
|
function handler_tips_library() {
|
|
$out = "=== TIPS LIBRARY INVENTORY ===\n";
|
|
$cats = [
|
|
"Selenium account creation" => "selenium",
|
|
"Token renewal (GitHub/Gitea)" => "rotation.?token|github.?pat|gitea.?token",
|
|
"Office recovery (Azure AD)" => "azure.?ad|tenant.*office",
|
|
"IP rotation (CF/PMTA)" => "ip.?rotat|warmup.?ip",
|
|
"DeepSeek web cookies" => "deepseek",
|
|
"ThuggieGPT web" => "thuggie",
|
|
"Claude.ai web cookies" => "claude.ai.*cook|claude.ai.*session",
|
|
"Gemini web" => "gemini",
|
|
"Qwen web" => "qwen",
|
|
"Mythos / Opus 4.6 tips" => "mythos|opus.?4\\.6",
|
|
];
|
|
static $corpus = null;
|
|
if ($corpus === null) {
|
|
$files = [];
|
|
foreach (["/opt/wevads/vault", "/var/www/html/wiki", "/opt/weval-ops/wiki"] as $d) {
|
|
if (is_dir($d)) {
|
|
$fs = @glob("$d/*.md") ?: [];
|
|
$files = array_merge($files, array_slice($fs, 0, 200));
|
|
}
|
|
}
|
|
$corpus = "";
|
|
foreach ($files as $f) {
|
|
$corpus .= "\n=== $f ===\n" . @file_get_contents($f);
|
|
}
|
|
$out .= "Corpus: " . count($files) . " .md files, " . round(strlen($corpus)/1024) . " KB scanned\n\n";
|
|
}
|
|
foreach ($cats as $label => $regex) {
|
|
$n = @preg_match_all("/$regex/i", $corpus);
|
|
$status = $n > 0 ? "[OK $n]" : "[MISS]";
|
|
$out .= sprintf(" %-38s %s\n", $label, $status);
|
|
}
|
|
$out .= "\n-- Missing categories = PHASE 3B targets --\n";
|
|
$out .= " * Pour chaque [MISS]: rediger doctrine dediee /opt/wevads/vault/\n";
|
|
$out .= " * Creer intent execute_tip(<cat>) pilote Selenium via Blade\n";
|
|
return $out;
|
|
}
|
|
|