Files
html/api/wevia-quality-engine.php
2026-04-12 22:57:03 +02:00

216 lines
9.7 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* WEVIA QUALITY ENGINE v1.0 — Lean/Six Sigma/Theory of Constraints
*
* Intégré dans le pipeline dev comme étape de contrôle qualité.
* Contrôlé par WEVIA Master + L99.
*
* LEAN: Cycle time, Waste detection, Value Stream Mapping
* SIX SIGMA: Defect rate, DPMO, Process capability (Cp/Cpk)
* TOC: Bottleneck identification, 5 Focusing Steps
* AGILE: Sprint velocity, WIP limits, Lead time
*/
header('Content-Type: application/json; charset=utf-8');
$action = $_GET['action'] ?? 'dashboard';
switch ($action) {
case 'dashboard':
// Collect all quality metrics
$metrics = ['timestamp' => date('Y-m-d H:i'), 'methodology' => []];
// ═══ LEAN METRICS ═══
$lean = [];
// Waste detection: unused routes, orphan files, dead Docker
$fast = @file_get_contents('/var/www/html/api/weval-ia-fast.php') ?: '';
$total_routes = substr_count($fast, '// Route');
// Dead code: routes that reference non-existent files
preg_match_all('/file_get_contents\("([^"]+)"\)/', $fast, $file_refs);
$dead_refs = 0;
foreach (array_unique($file_refs[1] ?? []) as $ref) {
if (strpos($ref, 'http') === false && !file_exists($ref)) $dead_refs++;
}
$lean['waste_dead_refs'] = $dead_refs;
// Orphan files in /api/ not referenced anywhere
$api_files = glob('/var/www/html/api/*.php');
$orphans = 0;
foreach ($api_files as $f) {
$name = basename($f, '.php');
if (strlen($name) > 5 && stripos($fast, $name) === false) $orphans++;
}
$lean['waste_orphan_apis'] = $orphans;
// Docker waste: containers using >500MB
exec("docker stats --no-stream --format '{{.Name}}:{{.MemUsage}}' 2>/dev/null | head -10", $docker_stats);
$lean['docker_containers'] = count($docker_stats);
// Cycle time: git commits last 24h
$commits_24h = intval(trim(shell_exec('cd /var/www/html && git log --since="24 hours ago" --oneline 2>/dev/null | wc -l') ?? '0'));
$lean['cycle_commits_24h'] = $commits_24h;
// Value: routes per 100 lines of code
$fast_lines = intval(trim(shell_exec('wc -l < /var/www/html/api/weval-ia-fast.php 2>/dev/null') ?? '0'));
$lean['value_routes_per_100L'] = round($total_routes / max($fast_lines, 1) * 100, 1);
$lean['score'] = round(100 - ($dead_refs * 5) - ($orphans * 2), 1);
$metrics['methodology']['lean'] = $lean;
// ═══ SIX SIGMA METRICS ═══
$sigma = [];
// Defect rate from L99
$l99 = json_decode(@file_get_contents('/var/www/html/api/l99-results.json') ?: '{}', true);
$l99_pass = 0; $l99_total = 0; $l99_fail = 0; $l99_warn = 0;
if (isset($l99['results'])) {
foreach ($l99['results'] as $r) {
$l99_total++;
if (($r['status'] ?? '') === 'PASS') $l99_pass++;
elseif (($r['status'] ?? '') === 'FAIL') $l99_fail++;
else $l99_warn++;
}
}
$sigma['l99_pass'] = $l99_pass;
$sigma['l99_total'] = $l99_total;
$sigma['l99_fail'] = $l99_fail;
$sigma['l99_warn'] = $l99_warn;
$sigma['defect_rate'] = $l99_total > 0 ? round($l99_fail / $l99_total * 100, 2) : 0;
// NonReg
$nr = json_decode(@file_get_contents('https://weval-consulting.com/api/nonreg-api.php?cat=all') ?: '{}', true);
$sigma['nonreg_pass'] = $nr['pass'] ?? 0;
$sigma['nonreg_total'] = $nr['total'] ?? 0;
$sigma['nonreg_score'] = $nr['score'] ?? 0;
// DPMO (defects per million opportunities)
$total_ops = max($l99_total + ($nr['total'] ?? 0), 1);
$total_defects = $l99_fail;
$sigma['dpmo'] = round($total_defects / $total_ops * 1000000);
// Sigma level approximation
$dpmo = $sigma['dpmo'];
if ($dpmo == 0) $sigma['sigma_level'] = '6σ+';
elseif ($dpmo < 3.4) $sigma['sigma_level'] = '6σ';
elseif ($dpmo < 233) $sigma['sigma_level'] = '5σ';
elseif ($dpmo < 6210) $sigma['sigma_level'] = '4σ';
elseif ($dpmo < 66807) $sigma['sigma_level'] = '3σ';
else $sigma['sigma_level'] = '2σ';
$metrics['methodology']['six_sigma'] = $sigma;
// ═══ THEORY OF CONSTRAINTS ═══
$toc = [];
// Identify bottleneck: slowest component
$bottlenecks = [];
// RAM constraint
$ram_used = intval(trim(shell_exec("free -m | grep Mem | awk '{print $3}'") ?? '0'));
$ram_total = intval(trim(shell_exec("free -m | grep Mem | awk '{print $2}'") ?? '1'));
$ram_pct = round($ram_used / max($ram_total, 1) * 100);
$bottlenecks['ram'] = ['usage' => "{$ram_pct}%", 'constraint' => $ram_pct > 85];
// Disk constraint
$disk_pct = intval(trim(shell_exec("df -h / | tail -1 | awk '{print $5}' | tr -d '%'") ?? '0'));
$bottlenecks['disk'] = ['usage' => "{$disk_pct}%", 'constraint' => $disk_pct > 90];
// CPU constraint
$load = floatval(trim(shell_exec('cat /proc/loadavg | cut -d" " -f1') ?? '0'));
$cores = intval(trim(shell_exec('nproc') ?? '4'));
$bottlenecks['cpu'] = ['load' => $load, 'cores' => $cores, 'constraint' => $load > $cores * 0.8];
// API rate limit constraint
$gap = json_decode(@file_get_contents('/var/www/html/api/gap-detector.json') ?: '{}', true);
$bottlenecks['wiring'] = ['score' => ($gap['score'] ?? 0) . '%', 'constraint' => ($gap['score'] ?? 100) < 80];
// Find THE bottleneck (5 Focusing Steps)
$main_bottleneck = null;
foreach ($bottlenecks as $name => $b) {
if ($b['constraint']) { $main_bottleneck = $name; break; }
}
$toc['bottlenecks'] = $bottlenecks;
$toc['main_constraint'] = $main_bottleneck ?? 'none';
$toc['five_steps'] = [
'1_identify' => $main_bottleneck ? "Constraint: $main_bottleneck" : "No active constraint",
'2_exploit' => $main_bottleneck ? "Maximize throughput of $main_bottleneck" : "System balanced",
'3_subordinate' => "Other processes aligned to constraint",
'4_elevate' => $main_bottleneck ? "Add capacity to $main_bottleneck" : "Monitor for new constraints",
'5_repeat' => "Check if constraint has shifted",
];
$metrics['methodology']['toc'] = $toc;
// ═══ AGILE METRICS ═══
$agile = [];
$agile['sprint_velocity'] = $commits_24h; // commits = velocity proxy
$agile['wip'] = intval(trim(shell_exec('cd /var/www/html && git status --porcelain 2>/dev/null | wc -l') ?? '0'));
$agile['lead_time_estimate'] = $commits_24h > 10 ? 'fast (<1h)' : ($commits_24h > 3 ? 'medium (1-4h)' : 'slow (>4h)');
$agile['routes_total'] = $total_routes;
$agile['test_coverage'] = round(($sigma['nonreg_pass'] ?? 0) / max(($sigma['nonreg_total'] ?? 1), 1) * 100, 1) . '%';
$metrics['methodology']['agile'] = $agile;
// ═══ GLOBAL QUALITY SCORE ═══
$lean_score = $lean['score'];
$sigma_score = $sigma['defect_rate'] == 0 ? 100 : max(0, 100 - $sigma['defect_rate'] * 10);
$toc_score = $main_bottleneck ? 70 : 100;
$agile_score = min(100, $commits_24h * 5 + 50);
$metrics['global_score'] = round(($lean_score + $sigma_score + $toc_score + $agile_score) / 4, 1);
$metrics['grade'] = $metrics['global_score'] >= 90 ? 'A+' : ($metrics['global_score'] >= 80 ? 'A' : ($metrics['global_score'] >= 70 ? 'B' : 'C'));
echo json_encode($metrics, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
break;
case 'lean':
// Detailed Lean analysis
echo json_encode(['action' => 'lean', 'note' => 'Use dashboard for full metrics']);
break;
case 'toc':
// Theory of Constraints deep analysis
echo json_encode(['action' => 'toc', 'note' => 'Use dashboard for full metrics']);
break;
case 'evolve':
// L99 AUTO-EVOLUTION: scan architecture changes and add new tests
$changes = [];
// Check for new PHP files not in L99
$api_files = glob('/var/www/html/api/*.php');
$l99_content = @file_get_contents('/opt/weval-l99/l99-functional-test.py') ?: '';
$new_apis = [];
foreach ($api_files as $f) {
$name = basename($f, '.php');
if (strlen($name) > 8 && stripos($l99_content, $name) === false) {
$new_apis[] = $name;
}
}
$changes['new_apis_not_in_l99'] = $new_apis;
// Check for new crons
$cron_files = glob('/etc/cron.d/weval-*');
$changes['total_crons'] = count($cron_files);
// Check routes growth
$fast = @file_get_contents('/var/www/html/api/weval-ia-fast.php') ?: '';
$changes['total_routes'] = substr_count($fast, '// Route');
// Suggest new L99 tests
$suggestions = [];
foreach (array_slice($new_apis, 0, 5) as $api) {
$suggestions[] = "Add L99 test for /api/$api.php (HTTP 200 + JSON valid)";
}
$changes['l99_suggestions'] = $suggestions;
$changes['l99_current_scripts'] = intval(trim(shell_exec('ls /opt/weval-l99/l99-*.py 2>/dev/null | wc -l') ?? '0'));
echo json_encode($changes, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
break;
default:
echo json_encode(['engine' => 'WEVIA Quality v1.0', 'actions' => ['dashboard', 'lean', 'toc', 'evolve']]);
}