Skip to content

Commit 941c6b4

Browse files
committed
Implement Step Through and Auto Play modes in ENKI Debate Arena
- Step Through: click Next Step to advance pipeline agent-by-agent - Auto Play: timed 800ms delays between steps, Pause button to switch to step mode - Debate mode unchanged: runs all steps with 150ms delays - All three modes share the same pipeline execution logic - Buttons update contextually based on current mode - 93/93 tests passing, server running on port 3848
1 parent f4d949a commit 941c6b4

1 file changed

Lines changed: 205 additions & 79 deletions

File tree

docs/debate.html

Lines changed: 205 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ <h1>ENKI Debate Arena</h1>
164164
const STOP_WORDS=new Set(['a','an','the','in','on','of','to','is','it','or','and','was','who','how','do','does','what']);
165165
function searchCorpus(kw,corpus){const m=kw.filter(k=>k.length>=3&&!STOP_WORDS.has(k));if(!m.length)return[];return corpus.filter(e=>e.k.some(k=>m.some(q=>q===k||(q.length>=4&&k.length>=4&&(k.includes(q)||q.includes(k)))))).map(e=>({source:e.s,text:e.t,location:e.l}));}
166166
function dedupe(c){const s=new Set();return c.filter(e=>{const k=e.source+':'+e.location;if(s.has(k))return false;s.add(k);return true;});}
167-
function pickRandom(arr){return arr[Math.floor(Math.random()*arr.length)];}
168167
let wormSeq=0,wormChain=[];
169168
async function sha256(s){const b=new TextEncoder().encode(s);const h=await crypto.subtle.digest('SHA-256',b);return Array.from(new Uint8Array(h)).map(b=>b.toString(16).padStart(2,'0')).join('');}
170169
async function sealWorm(eid,ag,act,v,cit){wormSeq++;const prev=wormChain.length===0?'GENESIS':wormChain[wormChain.length-1].hash;const ts=new Date().toISOString();const hash=await sha256(`${wormSeq}|${prev}|${eid}|${ag}|${act}|${v}|${ts}`);const e={seq:wormChain.length+1,prev_hash:prev,hash,timestamp:ts,event_id:eid,agent:ag,action:act,verdict:v,citations:cit};wormChain.push(e);return{sequence:e.seq,hash:e.hash,sealed:true};}
@@ -261,83 +260,182 @@ <h1>ENKI Debate Arena</h1>
261260
document.getElementById('rounds').appendChild(el);
262261
}
263262

264-
async function runDebate(){
265-
const q=document.getElementById('question').value.trim();if(!q)return;
266-
const loading=document.getElementById('loading'),roundsEl=document.getElementById('rounds'),scoresEl=document.getElementById('scores'),verdictBar=document.getElementById('verdict-bar');
267-
roundsEl.innerHTML='';loading.classList.add('visible');scoresEl.style.display='none';verdictBar.style.display='none';
268-
document.querySelectorAll('.pipe-step').forEach(el=>el.className='pipe-step');
263+
// --- Pipeline state ---
264+
let debateMode='idle'; // idle|debate|step|auto
265+
let autoTimer=null;
266+
let currentQuestion='';
267+
let pipelineSteps=[];
268+
let stepIndex=0;
269+
let pipelineData={};
270+
271+
const STEP_DELAY={debate:150,auto:800};
272+
273+
function cancelPipeline(){
274+
debateMode='idle';
275+
if(autoTimer){clearTimeout(autoTimer);autoTimer=null;}
276+
document.getElementById('loading').classList.remove('visible');
277+
document.getElementById('debate-btn').textContent='Debate';
278+
document.getElementById('debate-btn').disabled=false;
279+
document.getElementById('step-btn').textContent='Step Through';
280+
document.getElementById('step-btn').disabled=false;
281+
document.getElementById('auto-btn').textContent='Auto Play';
282+
document.getElementById('auto-btn').disabled=false;
283+
}
284+
285+
function showStepButtons(mode){
286+
const d=document.getElementById('debate-btn');
287+
const s=document.getElementById('step-btn');
288+
const a=document.getElementById('auto-btn');
289+
if(mode==='step'){
290+
d.textContent='Debate';d.disabled=false;
291+
s.textContent='Next Step';s.disabled=false;a.disabled=true;a.textContent='Auto Play';
292+
}else if(mode==='auto'){
293+
d.textContent='Debate';d.disabled=false;
294+
s.textContent='Pause';s.disabled=false;a.textContent='Stop';a.disabled=false;
295+
}else{
296+
d.textContent='Debate';d.disabled=false;
297+
s.textContent='Step Through';s.disabled=false;
298+
a.textContent='Auto Play';a.disabled=false;
299+
}
300+
}
269301

302+
async function sleep(ms){return new Promise(r=>setTimeout(r,ms));}
303+
304+
async function advanceStep(){
305+
if(stepIndex>=pipelineSteps.length)return finishPipeline();
306+
const step=pipelineSteps[stepIndex];
307+
stepIndex++;
308+
await executeStep(step);
309+
if(debateMode==='auto'){
310+
if(stepIndex>=pipelineSteps.length)return finishPipeline();
311+
autoTimer=setTimeout(()=>advanceStep(),STEP_DELAY.auto);
312+
}else if(debateMode==='step'){
313+
if(stepIndex>=pipelineSteps.length)return finishPipeline();
314+
document.getElementById('step-btn').textContent=`Next Step (${stepIndex}/${pipelineSteps.length})`;
315+
}else{
316+
await sleep(STEP_DELAY.debate);
317+
advanceStep();
318+
}
319+
}
320+
321+
async function executeStep(step){
322+
const q=currentQuestion;
270323
const kw=q.toLowerCase().split(/\s+/);
271324
const meaningfulKw=kw.filter(k=>k.length>=3&&!STOP_WORDS.has(k));
272325

273-
// SCRIBE
274-
setStep('scribe','active');
275-
await new Promise(r=>setTimeout(r,200));
276-
const cites=dedupe([...searchCorpus(meaningfulKw,BIBLE),...searchCorpus(meaningfulKw,ENOCH),...searchCorpus(meaningfulKw,THEOLOGY)]);
277-
const scribeConf=cites.length>0?Math.min(0.4+cites.length*0.12,0.95):0.15;
278-
setStep('scribe','done');
279-
280-
// JUDGE
281-
setStep('judge','active');
282-
await new Promise(r=>setTimeout(r,200));
283-
const judgeVerdict=cites.length>0?'approve':'repent';
284-
setStep('judge','done');
285-
286-
// ENKI
287-
setStep('enki','active');
288-
await new Promise(r=>setTimeout(r,300));
289-
const enkiMatch=ENKI_DB.find(e=>q.toLowerCase().includes(e.topic))||{topic:q,tension:`The nature of "${q}" involves multiple domains.`,synthesis:`Understanding "${q}" requires cross-domain analysis.`,label:'hypothesis'};
290-
const enkiConf=Math.min(0.3+cites.length*0.1,0.7);
291-
setStep('enki','done');
292-
293-
// ADVERSARY
294-
setStep('adversary','active');
295-
await new Promise(r=>setTimeout(r,200));
296-
const advChallenges=[];
297-
if(enkiConf>0.6&&enkiMatch.label!=='fact')advChallenges.push({type:'overclaiming',description:'Confidence exceeds threshold for non-fact synthesis',severity:'high'});
298-
if(enkiMatch.label==='analogy')advChallenges.push({type:'weak_analogy',description:'Analogy may not be structurally sound',severity:'medium'});
299-
const advPassed=advChallenges.filter(c=>c.severity==='high').length<2;
300-
setStep('adversary',advPassed?'done':'attacked');
301-
302-
// MISCONCEPTION
303-
setStep('misconception','active');
304-
await new Promise(r=>setTimeout(r,200));
305-
const misconceptions=misconceptionCheck(enkiMatch.synthesis);
306-
setStep('misconception',misconceptions.length>0?'attacked':'done');
307-
308-
// NOISE
309-
setStep('noise','active');
310-
await new Promise(r=>setTimeout(r,200));
311-
const noise=noiseCheck(enkiMatch.synthesis);
312-
setStep('noise',noise.length>0?'attacked':'done');
313-
314-
// PROPHET
315-
setStep('prophet','active');
316-
await new Promise(r=>setTimeout(r,200));
317-
const risk=misconceptions.some(m=>m.severity==='high')||noise.some(n=>n.severity==='high')?'high':advChallenges.length>0?'medium':'none';
318-
setStep('prophet','done');
319-
320-
// SENTINEL
321-
setStep('sentinel','active');
322-
await new Promise(r=>setTimeout(r,200));
323-
const classification=classifyClaim(enkiMatch.label,advPassed,misconceptions,noise);
324-
const sentinelAllowed=classification!=='misconception'&&classification!=='noise'&&classification!=='blocked';
325-
setStep('sentinel',sentinelAllowed?'done':'blocked');
326-
327-
// LEDGE
328-
setStep('ledge','active');
329-
let ledgeResult=null;
330-
if(sentinelAllowed){await new Promise(r=>setTimeout(r,200));ledgeResult=await sealWorm(`debate_${Date.now().toString(36)}`,'ARENA',q,judgeVerdict,cites.map(c=>c.source));}
331-
setStep('ledge',ledgeResult?'done':'blocked');
332-
333-
const scores=computeScores(cites.length,{label:enkiMatch.label},{passed:advPassed},misconceptions,noise);
334-
const verdict=computeVerdict(scores,classification,advPassed);
335-
336-
const round={round:1,question:q,scribe:{citations:cites,confidence:scribeConf},enki:{claim:enkiMatch.topic,synthesis:enkiMatch.synthesis,synthesis_label:enkiMatch.label,confidence:enkiConf,tensionMap:null},adversary:{passed:advPassed,challenges:advChallenges,verdict:advPassed?'approve':'repent'},misconception:misconceptions,noise,judge:{verdict:judgeVerdict,violatedRules:[],leanCheck:cites.length>0},prophet:{riskLevel:risk,warnings:[],recommendation:risk==='high'?'reject':'proceed'},sentinel:{allowed:sentinelAllowed,reason:sentinelAllowed?'Passed':'Blocked',classification},ledge:ledgeResult,scores,verdict};
337-
338-
loading.classList.remove('visible');
326+
switch(step){
327+
case'scribe':{
328+
setStep('scribe','active');await sleep(debateMode==='debate'?STEP_DELAY.debate:100);
329+
const cites=dedupe([...searchCorpus(meaningfulKw,BIBLE),...searchCorpus(meaningfulKw,ENOCH),...searchCorpus(meaningfulKw,THEOLOGY)]);
330+
const scribeConf=cites.length>0?Math.min(0.4+cites.length*0.12,0.95):0.15;
331+
pipelineData.cites=cites;pipelineData.scribeConf=scribeConf;
332+
setStep('scribe','done');
333+
showAgentMsg('scribe','🔍📖','SCRIBE',`Found <strong>${cites.length}</strong> citation(s). Confidence: <strong>${scribeConf}</strong>`);
334+
break;}
335+
case'judge':{
336+
setStep('judge','active');await sleep(debateMode==='debate'?STEP_DELAY.debate:100);
337+
const judgeVerdict=pipelineData.cites.length>0?'approve':'repent';
338+
pipelineData.judgeVerdict=judgeVerdict;
339+
setStep('judge','done');
340+
showAgentMsg('judge','⚖️','JUDGE',`Verdict: <strong>${judgeVerdict}</strong>. Lean: ${pipelineData.cites.length>0?'✓':'✗'}`);
341+
break;}
342+
case'enki':{
343+
setStep('enki','active');await sleep(debateMode==='debate'?STEP_DELAY.debate:100);
344+
const enkiMatch=ENKI_DB.find(e=>q.toLowerCase().includes(e.topic))||{topic:q,tension:`The nature of "${q}" involves multiple domains.`,synthesis:`Understanding "${q}" requires cross-domain analysis.`,label:'hypothesis'};
345+
const enkiConf=Math.min(0.3+pipelineData.cites.length*0.1,0.7);
346+
pipelineData.enkiMatch=enkiMatch;pipelineData.enkiConf=enkiConf;
347+
setStep('enki','done');
348+
showAgentMsg('enki','🔮','ENKI',`<strong>${enkiMatch.topic}</strong><br>${enkiMatch.synthesis}<br><span class="claim-badge ${enkiMatch.label}">${enkiMatch.label}</span>`);
349+
break;}
350+
case'adversary':{
351+
setStep('adversary','active');await sleep(debateMode==='debate'?STEP_DELAY.debate:100);
352+
const advChallenges=[];
353+
if(pipelineData.enkiConf>0.6&&pipelineData.enkiMatch.label!=='fact')advChallenges.push({type:'overclaiming',description:'Confidence exceeds threshold for non-fact synthesis',severity:'high'});
354+
if(pipelineData.enkiMatch.label==='analogy')advChallenges.push({type:'weak_analogy',description:'Analogy may not be structurally sound',severity:'medium'});
355+
const advPassed=advChallenges.filter(c=>c.severity==='high').length<2;
356+
pipelineData.advChallenges=advChallenges;pipelineData.advPassed=advPassed;
357+
setStep('adversary',advPassed?'done':'attacked');
358+
if(advChallenges.length>0){
359+
let h='';advChallenges.forEach(c=>{h+=`<div class="challenge">[${c.type}] ${c.description}</div>`;});
360+
h+=`<div style="margin-top:6px">Passed: <strong>${advPassed}</strong></div>`;
361+
showAgentMsg('adversary','⚔️','ADVERSARY',h);
362+
}else{
363+
showAgentMsg('adversary','⚔️','ADVERSARY',`No challenges. Passed: <strong>true</strong>`);
364+
}
365+
break;}
366+
case'misconception':{
367+
setStep('misconception','active');await sleep(debateMode==='debate'?STEP_DELAY.debate:100);
368+
const misconceptions=misconceptionCheck(pipelineData.enkiMatch.synthesis);
369+
pipelineData.misconceptions=misconceptions;
370+
setStep('misconception',misconceptions.length>0?'attacked':'done');
371+
if(misconceptions.length>0){
372+
let h='';misconceptions.forEach(m=>{h+=`<div class="misconception-inject">[${m.classification}] ${m.reason}</div>`;});
373+
showAgentMsg('misconception','🎭','MISCONCEPTION',h);
374+
}else{
375+
showAgentMsg('misconception','🎭','MISCONCEPTION','No reasoning errors detected.');
376+
}
377+
break;}
378+
case'noise':{
379+
setStep('noise','active');await sleep(debateMode==='debate'?STEP_DELAY.debate:100);
380+
const noise=noiseCheck(pipelineData.enkiMatch.synthesis);
381+
pipelineData.noise=noise;
382+
setStep('noise',noise.length>0?'attacked':'done');
383+
if(noise.length>0){
384+
let h='';noise.forEach(n=>{h+=`<div class="noise-inject">[${n.type}] ${n.desc}</div>`;});
385+
showAgentMsg('noise','🦠','NOISE',h);
386+
}else{
387+
showAgentMsg('noise','🦠','NOISE','No noise detected.');
388+
}
389+
break;}
390+
case'prophet':{
391+
setStep('prophet','active');await sleep(debateMode==='debate'?STEP_DELAY.debate:100);
392+
const risk=pipelineData.misconceptions.some(m=>m.severity==='high')||pipelineData.noise.some(n=>n.severity==='high')?'high':pipelineData.advChallenges.length>0?'medium':'none';
393+
pipelineData.risk=risk;
394+
setStep('prophet','done');
395+
showAgentMsg('prophet','🔥','PROPHET',`Risk: <strong>${risk}</strong>. Recommendation: ${risk==='high'?'reject':'proceed'}`);
396+
break;}
397+
case'sentinel':{
398+
setStep('sentinel','active');await sleep(debateMode==='debate'?STEP_DELAY.debate:100);
399+
const classification=classifyClaim(pipelineData.enkiMatch.label,pipelineData.advPassed,pipelineData.misconceptions,pipelineData.noise);
400+
const sentinelAllowed=classification!=='misconception'&&classification!=='noise'&&classification!=='blocked';
401+
pipelineData.classification=classification;pipelineData.sentinelAllowed=sentinelAllowed;
402+
setStep('sentinel',sentinelAllowed?'done':'blocked');
403+
const el=document.createElement('div');
404+
el.className=`sentinel-class ${classification}`;
405+
el.textContent=`SENTINEL: ${classification.toUpperCase()}`;
406+
document.getElementById('rounds').appendChild(el);
407+
break;}
408+
case'ledge':{
409+
setStep('ledge','active');
410+
let ledgeResult=null;
411+
if(pipelineData.sentinelAllowed){
412+
await sleep(debateMode==='debate'?STEP_DELAY.debate:100);
413+
ledgeResult=await sealWorm(`debate_${Date.now().toString(36)}`,'ARENA',q,pipelineData.judgeVerdict,pipelineData.cites.map(c=>c.source));
414+
}
415+
pipelineData.ledgeResult=ledgeResult;
416+
setStep('ledge',ledgeResult?'done':'blocked');
417+
break;}
418+
}
419+
}
420+
421+
function showAgentMsg(agentId,emoji,name,html){
422+
const el=document.createElement('div');
423+
el.className='agent-msg';
424+
el.innerHTML=`<div class="agent-name"><span class="emoji">${emoji}</span> ${name}</div><div class="msg-text">${html}</div>`;
425+
document.getElementById('rounds').appendChild(el);
426+
}
427+
428+
function finishPipeline(){
429+
const d=pipelineData;
430+
const scores=computeScores(d.cites.length,{label:d.enkiMatch.label},{passed:d.advPassed},d.misconceptions,d.noise);
431+
const verdict=computeVerdict(scores,d.classification,d.advPassed);
432+
433+
const round={round:1,question:currentQuestion,scribe:{citations:d.cites,confidence:d.scribeConf},enki:{claim:d.enkiMatch.topic,synthesis:d.enkiMatch.synthesis,synthesis_label:d.enkiMatch.label,confidence:d.enkiConf,tensionMap:null},adversary:{passed:d.advPassed,challenges:d.advChallenges,verdict:d.advPassed?'approve':'repent'},misconception:d.misconceptions,noise:d.noise,judge:{verdict:d.judgeVerdict,violatedRules:[],leanCheck:d.cites.length>0},prophet:{riskLevel:d.risk,warnings:[],recommendation:d.risk==='high'?'reject':'proceed'},sentinel:{allowed:d.sentinelAllowed,reason:d.sentinelAllowed?'Passed':'Blocked',classification:d.classification},ledge:d.ledgeResult,scores,verdict};
434+
435+
document.getElementById('loading').classList.remove('visible');
436+
const scoresEl=document.getElementById('scores');
339437
scoresEl.style.display='flex';
340-
verdictBar.style.display='flex';
438+
document.getElementById('verdict-bar').style.display='flex';
341439

342440
document.getElementById('sc-ev').textContent=scores.evidence;document.getElementById('sc-ev').className='score-value '+scoreClass(scores.evidence);
343441
document.getElementById('sc-lg').textContent=scores.logic;document.getElementById('sc-lg').className='score-value '+scoreClass(scores.logic);
@@ -347,16 +445,44 @@ <h1>ENKI Debate Arena</h1>
347445

348446
document.getElementById('final-verdict').textContent=verdict.replace(/_/g,' ');
349447
document.getElementById('final-verdict').className='verdict-value '+verdict;
350-
document.getElementById('total-claims').textContent='1 claim · '+classification;
448+
document.getElementById('total-claims').textContent='1 claim · '+d.classification;
351449

352450
renderRound(round);
451+
debateMode='idle';
452+
showStepButtons('idle');
453+
}
454+
455+
async function startDebate(mode){
456+
const q=document.getElementById('question').value.trim();if(!q)return;
457+
if(debateMode!=='idle')cancelPipeline();
458+
currentQuestion=q;
459+
debateMode=mode;
460+
pipelineSteps=['scribe','judge','enki','adversary','misconception','noise','prophet','sentinel','ledge'];
461+
stepIndex=0;
462+
pipelineData={};
463+
464+
document.getElementById('rounds').innerHTML='';
465+
document.getElementById('loading').classList.add('visible');
466+
document.getElementById('scores').style.display='none';
467+
document.getElementById('verdict-bar').style.display='none';
468+
document.querySelectorAll('.pipe-step').forEach(el=>el.className='pipe-step');
469+
470+
showStepButtons(mode);
471+
await advanceStep();
353472
}
354473

355-
document.querySelectorAll('.example').forEach(el=>{el.addEventListener('click',()=>{document.getElementById('question').value=el.dataset.q;runDebate();});});
356-
document.getElementById('debate-btn').addEventListener('click',runDebate);
357-
document.getElementById('step-btn').addEventListener('click',runDebate);
358-
document.getElementById('auto-btn').addEventListener('click',runDebate);
359-
document.getElementById('question').addEventListener('keydown',e=>{if(e.key==='Enter')runDebate();});
474+
document.querySelectorAll('.example').forEach(el=>{el.addEventListener('click',()=>{document.getElementById('question').value=el.dataset.q;startDebate('debate');});});
475+
document.getElementById('debate-btn').addEventListener('click',()=>{if(debateMode==='idle')startDebate('debate');});
476+
document.getElementById('step-btn').addEventListener('click',()=>{
477+
if(debateMode==='idle')startDebate('step');
478+
else if(debateMode==='step'){advanceStep();}
479+
else if(debateMode==='auto'){cancelPipeline();startDebate('step');}
480+
});
481+
document.getElementById('auto-btn').addEventListener('click',()=>{
482+
if(debateMode==='idle')startDebate('auto');
483+
else if(debateMode==='step'||debateMode==='auto')cancelPipeline();
484+
});
485+
document.getElementById('question').addEventListener('keydown',e=>{if(e.key==='Enter'){if(debateMode==='idle')startDebate('debate');}});
360486
</script>
361487
</body>
362488
</html>

0 commit comments

Comments
 (0)