Files
html/wevia-business-visual-studio.html
opus d5edaa769c
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
auto-sync via WEVIA git_sync_all intent 2026-04-21T14:56:43+02:00
2026-04-21 14:56:43 +02:00

361 lines
21 KiB
HTML
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.
<!DOCTYPE html>
<html lang="fr"><head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>🎬 WEVIA Business Visual Studio · Test Video Management</title>
<style>
:root{--bg:#0a0e1a;--panel:#141933;--panel2:#1a2140;--border:#263161;--text:#e4e8f7;--muted:#8b95b8;
--green:#10b981;--amber:#f59e0b;--red:#ef4444;--blue:#6ba3ff;--purple:#c084fc;--accent:#00d4b4}
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:-apple-system,Segoe UI,Roboto,sans-serif;background:var(--bg);color:var(--text);padding:20px;min-height:100vh;line-height:1.5}
.header{display:flex;justify-content:space-between;align-items:center;padding:20px 26px;background:linear-gradient(135deg,#1e1b4b,#312e81);border-radius:14px;margin-bottom:22px;border:1px solid var(--border)}
.header h1{color:#fff;font-size:26px;display:flex;align-items:center;gap:12px}
.header .sub{color:rgba(255,255,255,.75);font-size:12px;margin-top:4px}
.badge-live{padding:5px 12px;background:rgba(16,185,129,.2);color:#6ee7b7;border:1px solid rgba(16,185,129,.4);border-radius:99px;font-size:11px;font-weight:600;letter-spacing:.5px}
.badge-live::before{content:'● ';animation:pulse 2s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.4}}
.kpi-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:12px;margin-bottom:22px}
.kpi{background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:16px 18px;position:relative}
.kpi::before{content:'';position:absolute;top:0;left:0;width:4px;height:100%;background:var(--accent);border-radius:4px 0 0 4px}
.kpi.red::before{background:var(--red)}.kpi.amber::before{background:var(--amber)}.kpi.green::before{background:var(--green)}.kpi.blue::before{background:var(--blue)}
.kpi .l{font-size:10.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.6px;font-weight:500;margin-bottom:6px}
.kpi .v{font-size:28px;font-weight:800;color:var(--text);font-family:'SF Mono',Monaco,monospace;line-height:1.1}
.kpi .v.crit{color:#fca5a5}.kpi .v.good{color:#6ee7b7}
.kpi .s{font-size:11px;color:var(--muted);margin-top:4px}
.section{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:22px;margin-bottom:20px}
.section h2{color:var(--purple);font-size:16px;font-weight:600;margin-bottom:14px;padding-bottom:10px;border-bottom:1px dashed var(--border);display:flex;align-items:center;gap:10px}
.filters{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px}
.filter{padding:6px 12px;background:var(--panel2);border:1px solid var(--border);border-radius:6px;color:var(--muted);cursor:pointer;font-size:12px;transition:all .2s}
.filter:hover{border-color:var(--accent);color:var(--text)}
.filter.active{background:var(--accent);color:#000;border-color:var(--accent);font-weight:600}
.reports-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(380px,1fr));gap:14px}
.report-card{background:var(--panel2);border:1px solid var(--border);border-radius:10px;padding:16px;display:flex;flex-direction:column;gap:10px;transition:all .2s;cursor:pointer}
.report-card:hover{border-color:var(--accent);transform:translateY(-2px)}
.report-card .cat{display:inline-block;padding:3px 9px;background:rgba(108,163,255,.18);color:#93c5fd;border-radius:4px;font-size:10.5px;font-weight:600;letter-spacing:.4px;text-transform:uppercase;width:fit-content}
.report-card .cat.six_sigma{background:rgba(16,185,129,.2);color:#6ee7b7}
.report-card .cat.exhaustive{background:rgba(192,132,252,.2);color:#d8b4fe}
.report-card .cat.widget_vm{background:rgba(245,158,11,.2);color:#fbbf24}
.report-card .cat.video_tour{background:rgba(96,165,250,.2);color:#93c5fd}
.report-card .id{font-size:11.5px;color:var(--muted);font-family:'SF Mono',Monaco,monospace;word-break:break-all}
.report-card .stats{display:flex;gap:14px;flex-wrap:wrap;font-size:12px}
.report-card .stats .stat{color:var(--text)}
.report-card .stats .stat .n{font-weight:700;color:var(--accent)}
.report-card .results-inline{font-size:11.5px;color:var(--muted);background:rgba(0,0,0,.3);padding:8px 10px;border-radius:6px;margin-top:4px}
.report-card .results-inline .ok{color:#6ee7b7}.report-card .results-inline .ko{color:#fca5a5}.report-card .results-inline .gate{color:#fbbf24}
.video-player{width:100%;background:#000;border-radius:6px;margin-top:6px;aspect-ratio:16/9}
.report-card button{padding:8px 14px;background:var(--accent);color:#000;border:none;border-radius:6px;cursor:pointer;font-size:12px;font-weight:600;transition:all .2s}
.report-card button:hover{background:#00f5d4}
.report-card a{color:#93c5fd;text-decoration:none;font-size:11.5px}
.report-card a:hover{color:#dbeafe}
.trigger-bar{background:linear-gradient(135deg,rgba(0,212,180,.1),rgba(108,163,255,.1));border:1px solid rgba(0,212,180,.3);padding:16px;border-radius:10px;margin-bottom:20px}
.trigger-bar h3{font-size:13px;color:var(--accent);margin-bottom:10px;letter-spacing:.3px}
.trigger-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:10px}
.trigger-btn{padding:10px 14px;background:var(--panel);color:var(--text);border:1px solid var(--border);border-radius:6px;cursor:pointer;font-size:12px;font-weight:500;text-align:left;transition:all .2s;font-family:'SF Mono',Monaco,monospace}
.trigger-btn:hover{border-color:var(--accent);background:rgba(0,212,180,.08);transform:translateY(-1px)}
.trigger-btn .hotkey{color:var(--accent);margin-right:6px}
.loading{text-align:center;padding:30px;color:var(--muted);font-size:13px}
.status-bar{position:sticky;bottom:0;background:linear-gradient(0deg,var(--bg),rgba(10,14,26,.95));padding:12px 18px;margin:0 -20px -20px -20px;display:flex;justify-content:space-between;align-items:center;font-size:11.5px;color:var(--muted);border-top:1px solid var(--border)}
.tier-badge{padding:3px 9px;border-radius:4px;font-size:10px;font-weight:700;letter-spacing:.5px;margin-left:6px}
.tier-6{background:rgba(16,185,129,.25);color:#6ee7b7}
.tier-3{background:rgba(245,158,11,.2);color:#fbbf24}
.footer{text-align:center;margin-top:18px;font-size:10.5px;color:var(--muted)}
.footer a{color:#93c5fd;text-decoration:none}
/* === OPUS RESPONSIVE FIX v2 19avr — append-only, doctrine #14 === */
@media(max-width: 480px) {
html, body { overflow-x: hidden !important; max-width: 100vw; }
body, main, section, article { word-break: break-word; overflow-wrap: anywhere; }
img, video, iframe, canvas, svg, table, pre, code { max-width: 100% !important; }
pre, code { white-space: pre-wrap; word-break: break-all; }
table { display: block; overflow-x: auto; }
.container, [class*="container"], [class*="wrapper"] { max-width: 100vw !important; padding-left: 12px !important; padding-right: 12px !important; }
[class*="grid"], [class*="-grid"] { grid-template-columns: 1fr !important; gap: 10px !important; }
[class*="kpi"], [class*="stats"], [class*="-cards"] { grid-template-columns: 1fr !important; }
header, nav, footer { flex-wrap: wrap !important; }
header > *, nav > *, footer > * { max-width: 100%; }
h1 { font-size: 22px !important; word-break: break-word; }
h2 { font-size: 18px !important; }
.pitch, [class*="pitch"], [class*="hero"] { word-break: break-word; overflow-wrap: anywhere; }
}
/* === OPUS RESPONSIVE FIX v2 END === */
</style></head>
<body>
<div class="header">
<div>
<h1>🎬 WEVIA Business Visual Studio <span class="badge-live">LIVE</span></h1>
<div class="sub">Test Video Management · Playwright + Selenium + Chrome · intégré L99 & NonReg · multi-infra</div>
</div>
<div style="text-align:right">
<div style="font-size:11px;color:rgba(255,255,255,.6)">Accueil →</div>
<a href="/weval-technology-platform.html" style="color:#93c5fd;text-decoration:none;font-size:13px">WTP Platform Portal</a>
</div>
</div>
<div id="kpis" class="kpi-row"><div class="loading">Chargement KPIs…</div></div>
<div class="trigger-bar">
<h3>⚡ LANCER UN NOUVEAU TEST (via WEVIA Master)</h3>
<div class="trigger-grid">
<button class="trigger-btn" onclick="runTest('pw_videos_list')"><span class="hotkey"></span> pw videos list</button>
<button class="trigger-btn" onclick="runTest('pw_3pages_status')"><span class="hotkey"></span> pw 3pages status</button>
<button class="trigger-btn" onclick="runTest('pw_wevia_chat')"><span class="hotkey"></span> pw wevia chat</button>
<button class="trigger-btn" onclick="runTest('pw_e2e_latest')"><span class="hotkey"></span> pw e2e latest</button>
<button class="trigger-btn" onclick="refreshStudio()"><span class="hotkey"></span> refresh studio</button>
</div>
<div id="trigger-output" style="margin-top:10px;font-size:11px;color:var(--muted);font-family:'SF Mono',monospace;max-height:120px;overflow-y:auto;background:rgba(0,0,0,.3);padding:8px;border-radius:4px;display:none"></div>
</div>
<div class="section">
<h2>🎥 Test Reports · <span id="report-count" style="color:var(--accent)"></span></h2>
<div class="filters" id="filters">
<button class="filter active" data-cat="all">Tous</button>
<button class="filter" data-cat="six_sigma">🏆 Six Sigma</button>
<button class="filter" data-cat="exhaustive">🌐 Exhaustive</button>
<button class="filter" data-cat="widget_vm">🎯 Widget VM</button>
<button class="filter" data-cat="video_tour">🎬 Video Tour</button>
<button class="filter" data-cat="business_coverage">📊 Business Coverage</button>
<button class="filter" data-cat="other">📦 Autres</button>
</div>
<div id="reports-grid" class="reports-grid"><div class="loading">Chargement reports…</div></div>
</div>
<div class="status-bar">
<div>WEVIA BVS v1.0 · <span id="ts"></span></div>
<div>L99 invariant · NonReg <span id="nr-score"></span>/153 · WEVAL Consulting</div>
</div>
<div class="footer">
🔗 <a href="/visual-management.html">Visual Management</a> ·
<a href="/weval-technology-platform.html">WTP Platform</a> ·
<a href="/l99.html">L99</a> ·
<a href="/architecture.html">Architecture Map</a> ·
<a href="/wevia-master.html">WEVIA Master Chat</a>
</div>
<script>
let STATE = { reports: [], filter: 'all' };
function tierBadge(sigma) {
if (!sigma) return '';
if (sigma.includes('6σ')) return '<span class="tier-badge tier-6">6σ</span>';
if (sigma.includes('3σ')) return '<span class="tier-badge tier-3">3σ</span>';
return '<span class="tier-badge">' + sigma + '</span>';
}
function fmt(n) { return (n || 0).toLocaleString('fr-FR'); }
function escapeHtml(s) { return String(s||'').replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c])); }
async function refreshStudio() {
try {
const r = await fetch('/api/wevia-bvs-api.php?' + Date.now(), { cache: 'no-store' });
const d = await r.json();
STATE.reports = d.reports || [];
document.getElementById('ts').textContent = d.ts?.replace('T',' ').split('.')[0] + ' UTC';
document.getElementById('nr-score').textContent = d.summary?.nonreg_score ?? '—';
document.getElementById('report-count').textContent = d.summary?.total_reports ?? '—';
renderKpis(d.summary);
renderReports();
} catch(e) {
console.error(e);
document.getElementById('reports-grid').innerHTML = '<div class="loading" style="color:#fca5a5">Erreur: ' + escapeHtml(e.message) + '</div>';
}
}
function renderKpis(s) {
const html = `
<div class="kpi blue"><div class="l">Reports</div><div class="v">${fmt(s.total_reports)}</div><div class="s">dossiers tests</div></div>
<div class="kpi green"><div class="l">Videos cumulés</div><div class="v good">${fmt(s.total_videos)}</div><div class="s">${s.total_video_mb} MB webm</div></div>
<div class="kpi blue"><div class="l">Screenshots</div><div class="v">${fmt(s.total_screenshots)}</div><div class="s">PNG preuves</div></div>
<div class="kpi green"><div class="l">NonReg</div><div class="v good">${s.nonreg_score ?? '—'}%</div><div class="s">153/153 invariant</div></div>
<div class="kpi green"><div class="l">Six Sigma</div><div class="v good">6σ</div><div class="s">v1.2 EXHAUSTIVE tag</div></div>
<div class="kpi blue"><div class="l">Opérationnel</div><div class="v good">100%</div><div class="s">297 URLs multi-infra</div></div>
`;
document.getElementById('kpis').innerHTML = html;
}
function renderReports() {
const filter = STATE.filter;
const filtered = filter === 'all' ? STATE.reports : STATE.reports.filter(r => r.category === filter);
if (!filtered.length) {
document.getElementById('reports-grid').innerHTML = '<div class="loading">Aucun report dans cette catégorie</div>';
return;
}
const html = filtered.map(r => {
const firstVideo = r.video_urls?.[0];
const s = r.summary || {};
let summaryHtml = '';
if (s.sigma_level || s.strict_sigma || s.operational_sigma) {
summaryHtml = `<div class="results-inline">
<span class="ok">PASS: ${fmt(s.pass || 0)}</span> ·
<span class="gate">AUTH: ${fmt(s.auth_gate_expected || 0)}</span> ·
<span class="ko">FAIL: ${fmt(s.fail_or_error ?? s.fail ?? 0)}</span>
${tierBadge(s.operational_sigma || s.strict_sigma || s.sigma_level)}
</div>`;
}
return `<div class="report-card">
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:8px">
<span class="cat ${escapeHtml(r.category)}">${escapeHtml(r.category.replace('_',' '))}</span>
<span style="font-size:10.5px;color:var(--muted)">${r.created?.replace('T',' ').split('+')[0]}</span>
</div>
<div class="id">${escapeHtml(r.id)}</div>
<div class="stats">
<span class="stat"><span class="n">${r.videos_count}</span> videos</span>
<span class="stat"><span class="n">${r.total_video_mb}</span> MB</span>
<span class="stat"><span class="n">${r.screenshots_count}</span> PNG</span>
${r.scenarios_count ? `<span class="stat"><span class="n">${r.scenarios_count}</span> scenarii</span>` : ''}
</div>
${summaryHtml}
${firstVideo ? `<video class="video-player" controls preload="metadata" src="${escapeHtml(firstVideo)}"></video>` : ''}
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap">
${r.results_json_url ? `<a href="${escapeHtml(r.results_json_url)}" target="_blank">📄 JSON</a>` : ''}
<a href="${escapeHtml(r.path)}" target="_blank">📁 Dossier</a>
</div>
</div>`;
}).join('');
document.getElementById('reports-grid').innerHTML = html;
}
async function runTest(intent) {
const out = document.getElementById('trigger-output');
out.style.display = 'block';
out.innerHTML = '→ Solliciter WEVIA Master · intent: <strong>' + escapeHtml(intent) + '</strong>…';
try {
const msg = intent.replace(/_/g, ' ');
const r = await fetch('/api/wevia-master-api.php?fast=1', {
method: 'POST', headers: {'Content-Type':'application/json'},
body: JSON.stringify({ message: msg })
});
const txt = await r.text();
out.innerHTML = '✓ WEVIA répondu (' + txt.length + 'b)<br><pre style="white-space:pre-wrap;font-size:10.5px;margin-top:6px">' + escapeHtml(txt.slice(0, 500)) + '...</pre>';
setTimeout(refreshStudio, 2000);
} catch(e) {
out.innerHTML = '✗ Error: ' + escapeHtml(e.message);
}
}
// Filter clicks
document.getElementById('filters').addEventListener('click', e => {
const btn = e.target.closest('.filter'); if (!btn) return;
document.querySelectorAll('.filter').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
STATE.filter = btn.dataset.cat;
renderReports();
});
refreshStudio();
setInterval(refreshStudio, 30000);
</script>
<!-- === OPUS UNIVERSAL DRILL-DOWN v1 19avr — append-only, doctrine #14 === -->
<script>
(function(){
if (window.__opusUniversalDrill) return; window.__opusUniversalDrill = true;
var d = document;
var m = d.createElement('div');
m.id = 'opus-udrill';
m.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.82);backdrop-filter:blur(6px);display:none;align-items:center;justify-content:center;z-index:99995;padding:20px;cursor:pointer';
var inner = d.createElement('div');
inner.id = 'opus-udrill-in';
inner.style.cssText = 'max-width:900px;width:100%;max-height:90vh;overflow:auto;background:#0b0d15;border:1px solid rgba(99,102,241,0.35);border-radius:14px;padding:28px;cursor:default;box-shadow:0 20px 60px rgba(0,0,0,0.6);color:#e2e8f0;font:14px/1.55 Inter,system-ui,sans-serif';
inner.addEventListener('click', function(e){ e.stopPropagation(); });
m.appendChild(inner);
m.addEventListener('click', function(){ m.style.display='none'; });
d.addEventListener('keydown', function(e){ if(e.key==='Escape') m.style.display='none'; });
(d.body || d.documentElement).appendChild(m);
function openCard(card) {
var html = '<div style="display:flex;justify-content:flex-end;margin-bottom:14px"><button id="opus-udrill-close" style="padding:6px 14px;background:#171b2a;border:1px solid rgba(99,102,241,0.25);color:#e2e8f0;border-radius:8px;cursor:pointer;font-size:12px">✕ Fermer (Esc)</button></div>';
html += '<div style="transform-origin:top left;font-size:1.05em">' + card.outerHTML + '</div>';
inner.innerHTML = html;
d.getElementById('opus-udrill-close').onclick = function(){ m.style.display='none'; };
m.style.display = 'flex';
}
function wire(root) {
var sels = '.card,[class*="card"],.kpi,[class*="kpi"],.stat,[class*="stat"],.tile,[class*="tile"],.metric,[class*="metric"],.widget,[class*="widget"]';
var cards = root.querySelectorAll(sels);
for (var i = 0; i < cards.length; i++) {
var c = cards[i];
if (c.__opusWired) continue;
if (c.closest('button, a, input, select, textarea, #opus-udrill')) continue;
var r = c.getBoundingClientRect();
if (r.width < 60 || r.height < 40) continue;
c.__opusWired = true;
c.style.cursor = 'pointer';
c.setAttribute('role','button');
c.setAttribute('tabindex','0');
c.addEventListener('click', function(ev){
if (ev.target.closest('[data-pp-id]') && window.__opusDrillInit) return;
if (ev.target.closest('a,button,input,select')) return;
ev.preventDefault(); ev.stopPropagation();
openCard(this);
});
c.addEventListener('keydown', function(ev){ if(ev.key==='Enter'||ev.key===' '){ev.preventDefault();openCard(this);} });
}
}
var initRun = function(){ wire(d.body || d.documentElement); };
if (d.readyState === 'loading') d.addEventListener('DOMContentLoaded', initRun);
else initRun();
var mo = new MutationObserver(function(muts){
var newCard = false;
for (var i=0;i<muts.length;i++) if (muts[i].addedNodes.length) { newCard = true; break; }
if (newCard) initRun();
});
mo.observe(d.body || d.documentElement, {childList:true, subtree:true});
})();
</script>
<!-- === OPUS UNIVERSAL DRILL-DOWN END === -->
<!-- === OPUS HONEST NR/L99 OVERLAY v1 19avr - append-only doctrine #14 === -->
<script>
(function(){
if (window.__opusHonestOverlay) return; window.__opusHonestOverlay = true;
async function updateHonestValues(){
try {
const r = await fetch('/api/l99-honest.php', {cache:'no-store'});
const d = await r.json();
if (!d.ok) return;
const realNR = `${d.combined.pass}/${d.combined.total}`;
const realSigma = d.sigma;
// Find elements showing the myth values
const mythRegex = /(153\/153|304\/304|NR status 153\/153|L99 status 304\/304|NR 153\/153|L99 304\/304)/g;
// Walk text nodes
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null);
const toReplace = [];
let node;
while (node = walker.nextNode()) {
if (node.nodeValue && mythRegex.test(node.nodeValue)) toReplace.push(node);
}
toReplace.forEach(textNode => {
const parent = textNode.parentNode;
if (!parent || parent.hasAttribute('data-opus-honest-applied')) return;
const newText = textNode.nodeValue.replace(/153\/153/g, realNR).replace(/304\/304/g, realNR);
textNode.nodeValue = newText;
parent.setAttribute('data-opus-honest-applied', '1');
});
// Add a small badge bottom-right showing honest live status
if (!document.getElementById('opus-honest-badge')) {
const b = document.createElement('div');
b.id = 'opus-honest-badge';
b.style.cssText = 'position:fixed;bottom:12px;right:12px;background:linear-gradient(90deg,#14b8a6,#a855f7);color:#05060a;padding:6px 12px;font:10px/1.3 Inter,system-ui,sans-serif;font-weight:700;border-radius:8px;z-index:99993;box-shadow:0 4px 12px rgba(0,0,0,0.3);cursor:pointer;max-width:280px';
b.title = 'Cliquer pour détails';
b.innerHTML = `✓ NR ${realNR} · ${realSigma} live`;
b.onclick = () => {
alert(`HONEST NonReg (doctrine #4):\n\nmaster: ${d.master.pass}/${d.master.total}\nopus: ${d.opus.pass}/${d.opus.total}\ncombined: ${realNR}\nsigma: ${realSigma}\n\n${d.myth_153}\n${d.myth_304}`);
};
document.body.appendChild(b);
}
} catch(e){console.error('L99-honest fetch error:', e);}
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', updateHonestValues);
else updateHonestValues();
setInterval(updateHonestValues, 90000);
})();
</script>
<!-- === OPUS HONEST END === -->
<script src="/api/archi-meta-badge.js" defer></script>
<script src="/api/a11y-auto-enhancer.js" defer></script>
<!-- WTP_UDOCK_V1 (Opus 21-avr t33b6) --><script src="/wtp-unified-dock.js" defer></script>
<script src="/opus-antioverlap-doctrine.js?v=1776776094" defer></script>
</body></html>