Files
html/api/release-check.php
opus 34039e18b0
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
auto-commit via WEVIA vault_git intent 2026-04-18T13:40:48+00:00
2026-04-18 15:40:48 +02:00

102 lines
3.3 KiB
PHP

<?php
/**
* /api/release-check.php · Release management for multi-Opus coordination
* Detects recent commits (last 15 min) by other Claude instances to avoid:
* - Doublons
* - Régressions
* - Pertes de code
* Yacine Mahboub · WEVAL Consulting · 18avr2026
*/
header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-store');
$REPO = '/var/www/html';
$WINDOW_MIN = (int)($_GET['window'] ?? 15);
$out = [
'ok' => true,
'ts' => date('c'),
'window_min' => $WINDOW_MIN,
'recent_commits' => [],
'other_opus_commits' => [],
'playwright_latest' => [],
'conflicts' => [],
'advice' => []
];
// Recent commits (last N minutes)
$since = date('Y-m-d\TH:i:s', time() - $WINDOW_MIN * 60);
$cmd = "cd $REPO && git log --since=\"$since\" --pretty=format:'%h|%an|%at|%s' 2>&1 | head -30";
$logs = @shell_exec($cmd);
if ($logs) {
foreach (explode("\n", trim($logs)) as $line) {
if (!$line) continue;
$parts = explode('|', $line, 4);
if (count($parts) < 4) continue;
$c = [
'hash' => $parts[0],
'author' => $parts[1],
'ts' => date('c', (int)$parts[2]),
'subject' => $parts[3]
];
$out['recent_commits'][] = $c;
// Flag commits from other Opus (contains "Opus" or starts with version-like)
if (preg_match('/\b(Opus|opus|V\d+|D9\d|B\d+|autre)/', $parts[3])
&& !preg_match('/^auto-(sync|commit)/', $parts[3])) {
$out['other_opus_commits'][] = $c;
}
}
}
// Playwright latest results
foreach (['playwright-dsh-predict-latest.json', 'playwright-latest-e2e.json'] as $f) {
$p = "$REPO/api/$f";
if (is_file($p)) {
$d = @json_decode(@file_get_contents($p), true);
if (is_array($d)) {
$pages = $d['pages'] ?? [];
$out['playwright_latest'][$f] = [
'ts' => $d['ts'] ?? '?',
'total_pages' => count($pages),
'pass' => count(array_filter($pages, fn($p)=>($p['status']??'')==='PASS')),
'fail' => count(array_filter($pages, fn($p)=>($p['status']??'')==='FAIL'))
];
}
}
}
// Detect potential conflicts: files modified by multiple recent commits
$conflictCmd = "cd $REPO && git log --since=\"$since\" --name-only --pretty=format:'' 2>&1 | grep -v '^$' | sort | uniq -c | sort -rn | head -10";
$conflictOut = @shell_exec($conflictCmd);
if ($conflictOut) {
foreach (explode("\n", trim($conflictOut)) as $line) {
$line = trim($line);
if (!$line) continue;
if (preg_match('/^(\d+)\s+(.+)$/', $line, $m)) {
$count = (int)$m[1];
$file = $m[2];
if ($count >= 2) {
$out['conflicts'][] = ['file' => $file, 'modification_count' => $count];
}
}
}
}
// Advice
if (count($out['other_opus_commits']) > 0) {
$out['advice'][] = count($out['other_opus_commits']) . " other Opus commit(s) in last {$WINDOW_MIN}min - pull before new work";
}
if (count($out['conflicts']) > 0) {
$out['advice'][] = "Files modified by multiple commits: review to avoid doublons";
}
$pending_stubs = @glob('/var/www/html/api/wired-pending/intent-opus4-*.php');
$out['pending_stubs_count'] = count($pending_stubs ?: []);
if (count($pending_stubs ?: []) > 120) {
$out['advice'][] = "Pending stubs = " . count($pending_stubs) . " (hig) - consider approving or purging";
}
if (empty($out['advice'])) {
$out['advice'][] = "No conflicts detected - safe to commit";
}
echo json_encode($out, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);