Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
Couverture dock nav: - Tour 29: 10 pages - Tour 30 batch 2: +12 (22 total) - Tour 31 batch 3: +24 (46 total) Pages injectees batch 3 (+92 bytes chacune, additif idempotent): * Dashboards: api-key-hub, tasks-live, nonreg, monitoring, trust-center * Pages hub: methodologie, playbook-3-phases, integrations-marketplace, automation-hub * Navigation: pages-index, weval-sitemap * Business: candidates-pool, contacts-segmentation-dashboard, kaouther-compose * Landings: landing-industrie, landing-ocp, landing-banque, landing-retail, ecosysteme-ia-maroc * Controls: linkedin-control-v98, blade-control, world-map-live, vsm-15depts-NEW, nl-autowire-status SKIP: vsm-pipelines.html (chattr+i) GOLD: /opt/wevads/vault/gold_*_t31_*.html Doctrine: ERP Global single source nav · Zero ecrasement · Zero regression · Idempotent
329 lines
14 KiB
HTML
329 lines
14 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="fr"><head>
|
||
<meta charset="UTF-8"><title>Automation Hub · Doctrine 64 ZERO-MANUAL-TASK</title>
|
||
<style>
|
||
body{font-family:-apple-system,BlinkMacSystemFont,sans-serif;background:#0a0e27;color:#e4e8f7;margin:0;padding:0;line-height:1.5}
|
||
.container{max-width:1400px;margin:0 auto;padding:24px}
|
||
h1{color:#6ba3ff;border-bottom:2px solid #1e3a8a;padding-bottom:8px;margin-top:0}
|
||
h2{color:#c084fc;margin-top:24px}
|
||
.card{background:#141933;border:1px solid #263161;border-radius:8px;padding:16px;margin:12px 0}
|
||
.flex{display:flex;gap:16px;flex-wrap:wrap}
|
||
.flex > div{flex:1;min-width:250px}
|
||
.badge{padding:3px 10px;border-radius:4px;font-size:11px;font-weight:bold;display:inline-block}
|
||
.ok{background:#10b981;color:#fff}.warn{background:#f59e0b;color:#111}.ko{background:#ef4444;color:#fff}.info{background:#3b82f6;color:#fff}.auto{background:#8b5cf6;color:#fff}
|
||
table{width:100%;border-collapse:collapse}th,td{padding:10px;border-bottom:1px solid #263161;text-align:left;font-size:13px;vertical-align:top}
|
||
th{background:#1e2549;color:#9ca8d3;font-size:11px;text-transform:uppercase}
|
||
button{background:#1e3a8a;color:#fff;border:0;padding:8px 14px;border-radius:4px;cursor:pointer;font-size:12px;margin:2px}
|
||
button:hover{background:#2950a7}button.primary{background:#10b981}
|
||
a{color:#6ba3ff}
|
||
code{background:#0f1529;padding:2px 6px;border-radius:3px;color:#fbbf24;font-family:Monaco,monospace;font-size:12px}
|
||
.step{background:#0f1529;padding:12px;border-radius:4px;margin-bottom:8px;border-left:3px solid #6ba3ff}
|
||
</style></head>
|
||
<body>
|
||
<div class="container">
|
||
|
||
<h1>🤖 Automation Hub · Doctrine 64 ZERO-MANUAL-TASK</h1>
|
||
<p>Plus aucune action humaine. Toutes les tâches sont automatisées via WEVIA + Selenium/Playwright + Blade IA.</p>
|
||
|
||
<h2>📊 État automations</h2>
|
||
<div id="status" class="card">Chargement…</div>
|
||
|
||
<h2>🔧 Automations wired</h2>
|
||
<div class="card">
|
||
<table>
|
||
<tr><th>Task</th><th>Script</th><th>Cron</th><th>Trigger WEVIA</th><th>Statut</th></tr>
|
||
|
||
<tr>
|
||
<td><strong>CRM pipeline sync</strong></td>
|
||
<td><code>/usr/local/bin/deliverads-guard.sh</code> (S95)</td>
|
||
<td>every 30min + 1h + 4×/jour</td>
|
||
<td><code>observe crm</code> / <code>run crm</code></td>
|
||
<td><span class="badge ok">ACTIVE</span></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td><strong>CRM observation daily</strong></td>
|
||
<td><code>/opt/weval-l99/crm-observation.py</code> (Playwright)</td>
|
||
<td>daily 9am</td>
|
||
<td><code>observe crm pipeline</code></td>
|
||
<td><span class="badge ok">ACTIVE</span></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td><strong>Blade self-heal</strong></td>
|
||
<td><code>/opt/weval-l99/blade-selfheal.py</code></td>
|
||
<td>every 5min</td>
|
||
<td><code>blade health</code></td>
|
||
<td><span class="badge ok">ACTIVE</span></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td><strong>OVH S151 cancel</strong></td>
|
||
<td><code>/opt/weval-l99/ovh-s151-cancel.py</code> (Selenium)</td>
|
||
<td>daily 10am (check+queue)</td>
|
||
<td><code>cancel ovh</code></td>
|
||
<td><span class="badge warn">PENDING creds</span></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td><strong>Azure AD rotation</strong></td>
|
||
<td><code>/api/azure-reregister-api.php</code></td>
|
||
<td>on-demand</td>
|
||
<td><code>rotate azure</code> / page UI</td>
|
||
<td><span class="badge ok">DONE (3 tenants rotated)</span></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td><strong>Blade task observer</strong></td>
|
||
<td>Task queue + Chrome headless Windows</td>
|
||
<td>daily (via Blade agent)</td>
|
||
<td>queue WEVIA</td>
|
||
<td><span class="badge ok">ACTIVE</span></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td><strong>NonReg guard</strong></td>
|
||
<td><code>/opt/weval-l99/wevia-nonreg-agent.php</code></td>
|
||
<td>every 15min</td>
|
||
<td><code>nonreg</code></td>
|
||
<td><span class="badge ok">153/153</span></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td><strong>L99 auto-update</strong></td>
|
||
<td><code>/opt/weval-l99/l99-state-updater.py</code></td>
|
||
<td>continuous</td>
|
||
<td><code>l99</code></td>
|
||
<td><span class="badge ok">100%</span></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td><strong>Ethica enrich boost</strong></td>
|
||
<td><code>/opt/ethica-*-boost.sh</code></td>
|
||
<td>4×/jour</td>
|
||
<td><code>ethica stats</code></td>
|
||
<td><span class="badge ok">+2,933/jour</span></td>
|
||
</tr>
|
||
|
||
</table>
|
||
</div>
|
||
|
||
<h2>🚨 Automations en attente de credentials</h2>
|
||
<div class="card" id="pending-list">Chargement…</div>
|
||
|
||
<h2>🎯 Exceptions doctrine 64 (légitimes)</h2>
|
||
<div class="card">
|
||
<p>Doctrine 64 tolère certaines exceptions :</p>
|
||
<ol>
|
||
<li><strong>Décision stratégique pure</strong> : ex. "option A vs B vs C" — Yacine doit vraiment trancher</li>
|
||
<li><strong>Authentification physique</strong> : biométrie, hardware key, SMS OTP setup initial</li>
|
||
<li><strong>Envoi email commercial au client</strong> (ordre GODMODE spécifique "SAUF SEND MAIL REEL AUTO") — drafts prêts, trigger manuel</li>
|
||
</ol>
|
||
</div>
|
||
|
||
<h2>📋 Tâches restantes (avec automation prévue)</h2>
|
||
<div class="card">
|
||
|
||
<div class="step">
|
||
<strong>1. Envoyer 3 emails Kaouther</strong> (<span class="badge warn">exception GODMODE</span>)
|
||
<br>→ Drafts prêts dans <a href="/kaouther-compose.html">/kaouther-compose.html</a>
|
||
<br>→ Clic "Ouvrir dans mail client" → Outlook/Gmail → Send
|
||
<br><em>Doctrine 64 exception #3 : envoi commercial réel requiert validation humaine</em>
|
||
</div>
|
||
|
||
<div class="step">
|
||
<strong>2. OVH S151 cancel</strong> (<span class="badge auto">AUTOMATED si creds fournies</span>)
|
||
<br>→ Script Selenium prêt <code>ovh-s151-cancel.py</code>
|
||
<br>→ Ajouter <code>OVH_EMAIL</code> + <code>OVH_PASSWORD</code> dans <code>/etc/weval/secrets.env</code>
|
||
<br>→ Cron 10h daily fera le reste
|
||
<br><em>Alternative : intent WEVIA <code>setup ovh creds email=X password=Y</code></em>
|
||
</div>
|
||
|
||
<div class="step">
|
||
<strong>3. OVH SMS provider</strong> (<span class="badge auto">AUTOMATABLE</span>)
|
||
<br>→ Décision stratégique Yacine : A(OVH) / B(Twilio) / C(Infobip recommandé) / D(pas SMS)
|
||
<br>→ Après décision : API signup auto via provider
|
||
<br><em>Recommandation : Infobip ~€0.04/SMS (MA/DZ/TN)</em>
|
||
</div>
|
||
|
||
<div class="step">
|
||
<strong>4. Blade wake</strong> (<span class="badge ok">AUTO DONE</span>)
|
||
<br>→ Blade déjà online (heartbeat 1s)
|
||
<br>→ Self-heal cron actif : auto-wake si offline > 10min
|
||
<br><em>Plus besoin d'action humaine</em>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<h2>🔗 Liens</h2>
|
||
<div class="card">
|
||
<ul>
|
||
<li><a href="/api/automation-status-live.php" target="_blank">API status JSON</a></li>
|
||
<li><a href="/wiki/DOCTRINE-64-ZERO-MANUAL-TASK.md" target="_blank">Doctrine 64</a></li>
|
||
<li><a href="/crm-pipeline-live.html">CRM pipeline</a></li>
|
||
<li><a href="/blade-control.html">Blade control</a></li>
|
||
<li><a href="/azure-reregister.html">Azure AD re-register</a></li>
|
||
<li><a href="/kaouther-compose.html">Kaouther compose</a></li>
|
||
<li><a href="/tasks-live.html">Tasks & logs live</a></li>
|
||
<li><a href="/wevia-master.html">WEVIA Master (chat)</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
async function load() {
|
||
try {
|
||
const r = await fetch('/api/automation-status-live.php');
|
||
const d = await r.json();
|
||
const sc = document.getElementById('status');
|
||
const auto_count = Object.keys(d.automations || {}).length;
|
||
const active = Object.values(d.automations || {}).filter(a => a.status === 'active').length;
|
||
sc.innerHTML = `
|
||
<div class="flex">
|
||
<div><strong>${active}/${auto_count}</strong> automations actives</div>
|
||
<div>Crons installés: <strong>${d.crons_count || 0}</strong></div>
|
||
<div>Scripts: <strong>${d.scripts_count || 0}</strong></div>
|
||
<div>Pending creds: <strong>${(d.pending || []).length}</strong></div>
|
||
</div>`;
|
||
|
||
const pl = document.getElementById('pending-list');
|
||
if (d.pending && d.pending.length) {
|
||
pl.innerHTML = d.pending.map(p => `
|
||
<div class="step">
|
||
<strong>${p.task}</strong>
|
||
<span class="badge warn">${p.status}</span>
|
||
<br><em>${p.reason}</em>
|
||
<br><small style="color:#9ca8d3">Depuis ${p.ts}</small>
|
||
</div>
|
||
`).join('');
|
||
} else {
|
||
pl.innerHTML = '<p style="color:#10b981">✅ Aucune automation bloquée</p>';
|
||
}
|
||
} catch(e) {
|
||
document.getElementById('status').innerHTML = 'Erreur: ' + e.message;
|
||
}
|
||
}
|
||
load();
|
||
setInterval(load, 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) {
|
||
// Clone card content + show close btn + increase font-size
|
||
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 a more-specific drill is already active (e.g. pp-card custom), let it handle
|
||
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);} });
|
||
}
|
||
}
|
||
|
||
// Initial + mutation observer
|
||
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 t31b3) --><script src="/wtp-unified-dock.js" defer></script>
|
||
</body></html>
|