import { demoNew, demoSpawnVehicle, demoStep, maAutoStep, maNew } from "../evgrid/api"; import type { StationNode } from "../evgrid/api"; import { MapView } from "../map/MapView"; type Args = { baselineMountId: string; oracleMountId: string; btnNew: HTMLButtonElement; btnStep: HTMLButtonElement; btnRun: HTMLButtonElement; btnSpawn: HTMLButtonElement; btnDemo: HTMLButtonElement; btnJudge: HTMLButtonElement; btnExport: HTMLButtonElement; scenarioEl: HTMLSelectElement; seedEl: HTMLInputElement; tickEl: HTMLInputElement; tickLabelEl: HTMLSpanElement; btnPlay: HTMLButtonElement; followEl: HTMLInputElement; loraEl: HTMLInputElement; fleetEl?: HTMLSelectElement; baselineBadge: HTMLDivElement; oracleBadge: HTMLDivElement; kpiWait: HTMLDivElement; kpiPeak: HTMLDivElement; kpiStress: HTMLDivElement; kpiRen: HTMLDivElement; kpiDream: HTMLDivElement; dreamEl: HTMLPreElement; oracleEl: HTMLPreElement; diffEl: HTMLPreElement; eventsEl: HTMLPreElement; negoEl: HTMLPreElement; }; type TurnFrame = { tick: number; action: any; event: any; anti_cheat_flags?: string[]; anti_cheat_details?: Record; scenario_events_at_tick?: any[]; }; function fmtDelta(v: number, goodWhenNegative = true) { const cls = v === 0 ? "" : goodWhenNegative ? (v < 0 ? "deltaPos" : "deltaNeg") : v > 0 ? "deltaPos" : "deltaNeg"; const sign = v > 0 ? "+" : ""; return { text: `${sign}${v.toFixed(2)}`, cls }; } function pill(el: HTMLElement, kind: "good" | "warn" | "bad", text: string) { el.className = `pill ${kind}`; el.textContent = text; } function bump(el: HTMLElement | null, cls: "pulse" | "shake") { if (!el) return; el.classList.remove(cls); // Force reflow so the animation retriggers even with same class. void el.offsetWidth; el.classList.add(cls); } function setText(id: string, v: string) { const el = document.getElementById(id); if (!el) return; el.textContent = v; } function setVerdict(kind: "ready" | "win" | "risk", text: string) { const el = document.getElementById("heroVerdict"); if (!el) return; el.className = `heroVerdict ${kind}`; el.textContent = text; } function setBar(id: string, pct: number, good: boolean) { const el = document.getElementById(id) as HTMLDivElement | null; if (!el) return; const p = Math.max(0, Math.min(100, pct)); el.style.width = `${p.toFixed(0)}%`; el.style.background = good ? "linear-gradient(90deg, rgba(71,255,154,0.90), rgba(35,231,255,0.70))" : "linear-gradient(90deg, rgba(255,90,138,0.92), rgba(255,191,60,0.62))"; } async function withDeadline(p: Promise, ms: number, label: string): Promise { let timeoutId: number | null = null; try { return await Promise.race([ p, new Promise((_, reject) => { timeoutId = window.setTimeout(() => reject(new Error(`${label} timed out after ${ms / 1000}s`)), ms); }), ]); } finally { if (timeoutId != null) window.clearTimeout(timeoutId); } } export function startCommandCenter(args: Args) { const mountBaseline = document.getElementById(args.baselineMountId); const mountOracle = document.getElementById(args.oracleMountId); if (!mountBaseline || !mountOracle) { pill(args.baselineBadge, "bad", "UI ERROR"); pill(args.oracleBadge, "bad", "UI ERROR"); args.eventsEl.textContent = "ERROR: mount nodes missing.\n\n" + `baselineMountId=${args.baselineMountId} oracleMountId=${args.oracleMountId}\n` + "This is a frontend wiring issue (DOM ids)."; return; } // Surface unexpected runtime errors in the UI (HF Spaces users often don't open DevTools). const reportFatal = (label: string, detail: unknown) => { pill(args.baselineBadge, "bad", label); pill(args.oracleBadge, "bad", label); const msg = detail instanceof Error ? `${detail.name}: ${detail.message}` : String(detail); args.eventsEl.textContent = `${label}\n${msg}`; args.oracleEl.textContent = `${label}\n${msg}`; args.dreamEl.textContent = `${label}\n${msg}\n\n` + "Tip: hard refresh (Ctrl+F5) to clear cached JS after a Space rebuild."; }; window.addEventListener("error", (ev) => reportFatal("RUNTIME ERROR", (ev as ErrorEvent).error || (ev as ErrorEvent).message)); window.addEventListener("unhandledrejection", (ev) => reportFatal("PROMISE REJECTION", (ev as PromiseRejectionEvent).reason)); const mkMap = (mount: HTMLElement) => { const view = new MapView(mount); const ready = Promise.resolve(view); return { view, ready }; }; const baseline = mkMap(mountBaseline); const oracle = mkMap(mountOracle); void baseline.ready.then((s) => s.setSide("baseline")).catch((e) => reportFatal("MAP ERROR", e)); void oracle.ready.then((s) => s.setSide("oracle")).catch((e) => reportFatal("MAP ERROR", e)); let baselineSid: string | null = null; let oracleSid: string | null = null; let judgeMode = false; const baselineFrames: TurnFrame[] = []; const oracleFrames: TurnFrame[] = []; let isReplaying = false; let replayBusy = false; let playTimer: number | null = null; let playing = false; let demoBusy = false; let tourBusy = false; let lastBaselineState: any | null = null; let lastOracleState: any | null = null; let lastOracleRb: Record | null = null; const episodeLog: { tick: number; baseline: TurnFrame; oracle: TurnFrame }[] = []; const seedRand = () => Math.floor(Math.random() * 10_000); const sleep = async (ms: number) => { await new Promise((r) => window.setTimeout(r, ms)); }; const appendEvent = (line: string) => { const prev = args.eventsEl.textContent || ""; args.eventsEl.textContent = prev ? `${prev}\n${line}` : line; }; const applyUrlParams = () => { const p = new URLSearchParams(window.location.search || ""); const seedQ = p.get("seed"); const scenarioQ = p.get("scenario"); const followQ = p.get("follow"); const loraQ = p.get("lora"); const fleetQ = p.get("fleet"); const judgeQ = p.get("judge"); if (scenarioQ) args.scenarioEl.value = scenarioQ; if (seedQ && !Number.isNaN(Number(seedQ))) args.seedEl.value = String(Number(seedQ)); if (followQ != null) args.followEl.checked = followQ === "1" || followQ.toLowerCase() === "true"; if (loraQ) args.loraEl.value = loraQ; if (args.fleetEl && fleetQ) args.fleetEl.value = fleetQ; if (judgeQ === "1" || judgeQ?.toLowerCase() === "true") judgeMode = true; }; const updateShareLink = () => { const seed = Number(args.seedEl.value || "0") || 0; const scenario = args.scenarioEl.value || "baseline"; const fleet = args.fleetEl ? args.fleetEl.value : "mixed"; const params = new URLSearchParams(); if (seed) params.set("seed", String(seed)); if (scenario) params.set("scenario", scenario); if (fleet) params.set("fleet", fleet); if (args.followEl.checked) params.set("follow", "1"); if (judgeMode) params.set("judge", "1"); const lora = args.loraEl.value || ""; if (lora) params.set("lora", lora); const url = `${window.location.pathname}?${params.toString()}`; appendEvent(`share: ${url}`); }; const summarizeDiff = (prev: any | null, next: any | null) => { if (!next) return "(no state)"; const pv = prev || {}; const nv = next || {}; const d = (a: any, b: any) => (Number(b ?? 0) - Number(a ?? 0)); const pct = (x: any) => `${(Number(x ?? 0) * 100).toFixed(1)}%`; const num = (x: any) => Number(x ?? 0); const prevStations = Array.isArray(pv.stations) ? pv.stations : []; const nextStations = Array.isArray(nv.stations) ? nv.stations : []; const meanWait = (arr: any[]) => arr.reduce((a, s) => a + Number(s?.avg_wait_minutes ?? 0), 0) / Math.max(1, arr.length); const stressCount = (arr: any[]) => arr.filter((s) => Number(s?.occupied_slots ?? 0) / Math.max(1, Number(s?.total_slots ?? 1)) > 0.85).length; const lines: string[] = []; lines.push(`grid_load: ${pct(pv.grid_load_pct)} → ${pct(nv.grid_load_pct)} (Δ ${(d(pv.grid_load_pct, nv.grid_load_pct) * 100).toFixed(1)}pp)`); lines.push(`renewable: ${pct(pv.renewable_pct)} → ${pct(nv.renewable_pct)} (Δ ${(d(pv.renewable_pct, nv.renewable_pct) * 100).toFixed(1)}pp)`); lines.push(`avg_wait: ${meanWait(prevStations).toFixed(2)} → ${meanWait(nextStations).toFixed(2)} (Δ ${d(meanWait(prevStations), meanWait(nextStations)).toFixed(2)} min)`); lines.push(`stress_stations: ${stressCount(prevStations)} → ${stressCount(nextStations)} (Δ ${d(stressCount(prevStations), stressCount(nextStations)).toFixed(0)})`); lines.push(`peak_risk: ${String(pv.peak_risk || "—")} → ${String(nv.peak_risk || "—")}`); const pPend = Array.isArray(pv.pending_evs) ? pv.pending_evs.length : 0; const nPend = Array.isArray(nv.pending_evs) ? nv.pending_evs.length : 0; lines.push(`pending_evs: ${pPend} → ${nPend} (Δ ${nPend - pPend})`); lines.push(`tick_dt_s: ${num(nv.tick_dt_s).toFixed(1)}`); return lines.join("\n"); }; const summarizeRewardDelta = (prev: Record | null, next: Record | null) => { if (!next) return "(no reward)"; const p = prev || {}; const keys = Array.from(new Set([...Object.keys(p), ...Object.keys(next)])).filter((k) => k !== "total"); const diffs = keys .map((k) => [k, Number(next[k] ?? 0) - Number(p[k] ?? 0)] as const) .sort((a, b) => Math.abs(b[1]) - Math.abs(a[1])) .slice(0, 6) .map(([k, dv]) => `${k}: ${dv >= 0 ? "+" : ""}${dv.toFixed(3)}`); const total = Number(next.total ?? 0); return `reward_total: ${total.toFixed(3)}\nΔ reward terms:\n${diffs.join("\n") || "(none)"}`; }; const setReplayUi = () => { const n = Math.max(0, baselineFrames.length - 1); args.tickEl.min = "0"; args.tickEl.max = String(n); args.tickEl.disabled = baselineFrames.length === 0; args.btnPlay.disabled = baselineFrames.length === 0; const t = Math.min(Number(args.tickEl.value || "0"), n); args.tickEl.value = String(t); args.tickLabelEl.textContent = String(t); }; const stopPlay = () => { playing = false; args.btnPlay.textContent = "Play"; if (playTimer != null) { window.clearInterval(playTimer); playTimer = null; } }; const applyKpis = (b: any, o: any, dreamScore: number | null) => { const bw = Number(b?.baseline?.avg_wait_minutes ?? 0); const ow = Number(o?.oracle?.avg_wait_minutes ?? 0); const wait = fmtDelta(ow - bw, true); args.kpiWait.textContent = wait.text; args.kpiWait.className = `kpiVal ${wait.cls}`; setText("heroMain", wait.text); setText("heroMainUnit", "avg wait (min)"); setBar("kpiWaitBar", (Math.min(30, Math.abs(ow - bw)) / 30) * 100, ow - bw <= 0); const bp = Number(b?.baseline?.peak_violations ?? 0); const op = Number(o?.oracle?.peak_violations ?? 0); const peak = fmtDelta(op - bp, true); args.kpiPeak.textContent = peak.text; args.kpiPeak.className = `kpiVal ${peak.cls}`; setText("heroPeak", peak.text); setBar("kpiPeakBar", (Math.min(8, Math.abs(op - bp)) / 8) * 100, op - bp <= 0); const bs = Number(b?.baseline?.grid_stress_events ?? 0); const os = Number(o?.oracle?.grid_stress_events ?? 0); const stress = fmtDelta(os - bs, true); args.kpiStress.textContent = stress.text; args.kpiStress.className = `kpiVal ${stress.cls}`; setText("heroStress", stress.text); setBar("kpiStressBar", (Math.min(12, Math.abs(os - bs)) / 12) * 100, os - bs <= 0); const br = Number(b?.baseline?.renewable_mean ?? 0); const or = Number(o?.oracle?.renewable_mean ?? 0); const ren = fmtDelta(or - br, false); args.kpiRen.textContent = ren.text; args.kpiRen.className = `kpiVal ${ren.cls}`; setText("heroRen", ren.text); setBar("kpiRenBar", (Math.min(0.55, Math.abs(or - br)) / 0.55) * 100, or - br >= 0); args.kpiDream.textContent = dreamScore == null ? "—" : `${(dreamScore * 100).toFixed(1)}%`; args.kpiDream.className = "kpiVal"; setText("heroDream", dreamScore == null ? "—" : `${(dreamScore * 100).toFixed(1)}%`); setBar("kpiDreamBar", dreamScore == null ? 0 : dreamScore * 100, (dreamScore ?? 0) >= 0.6); const wins = (ow - bw <= 0 ? 1 : 0) + (op - bp <= 0 ? 1 : 0) + (os - bs <= 0 ? 1 : 0) + (or - br >= 0 ? 1 : 0); if (wins >= 3) { setVerdict("win", `WIN ${wins}/4`); setText("heroSub", "Oracle is outperforming baseline under current conditions."); bump(document.getElementById("oraclePanel"), "pulse"); } else if (wins <= 1) { setVerdict("risk", `RISK ${wins}/4`); setText("heroSub", "Baseline is holding up — try a stress scenario, then Run 60."); bump(document.getElementById("baselinePanel"), "shake"); } else { setVerdict("ready", `LIVE ${wins}/4`); setText("heroSub", "Close race — keep stepping and watch the deltas stabilize."); bump(document.getElementById("heroStrip"), "pulse"); } }; const initSessions = async () => { stopPlay(); baselineFrames.length = 0; oracleFrames.length = 0; episodeLog.length = 0; const seed = Number(args.seedEl.value || "0") || seedRand(); const scenario = args.scenarioEl.value || "baseline"; const fleet = args.fleetEl ? args.fleetEl.value : "mixed"; pill(args.baselineBadge, "warn", "waking server…"); pill(args.oracleBadge, "warn", "waking server…"); args.eventsEl.textContent = "(creating sessions — HF Space cold-start may take ~10–30s)"; try { const [b, o] = await withDeadline( Promise.all([ judgeMode ? maNew(seed, scenario, fleet) : demoNew(seed, scenario, fleet), judgeMode ? maNew(seed, scenario, fleet) : demoNew(seed, scenario, fleet), ]), 75_000, judgeMode ? "maNew" : "demoNew" ); baselineSid = b.session_id; oracleSid = o.session_id; const [bView, oView] = await withDeadline(Promise.all([baseline.ready, oracle.ready]), 10_000, "mapReady"); await withDeadline( Promise.all([ bView.bindSession(b.session_id, b.station_nodes as StationNode[]), oView.bindSession(o.session_id, o.station_nodes as StationNode[]), ]), 25_000, "bindSession" ); pill(args.baselineBadge, "warn", "heuristic"); pill(args.oracleBadge, "good", judgeMode ? "ready (MA)" : "ready"); setVerdict("ready", judgeMode ? "READY (MA)" : "READY"); setText("heroSub", "Take 1–2 steps to reveal the delta. Then hit Run 60."); args.eventsEl.textContent = `seed=${seed}\nscenario=${scenario}\nbaseline=${baselineSid}\noracle=${oracleSid}`; args.dreamEl.textContent = "Sessions ready. Click STEP (first oracle step may download Qwen+LoRA on CPU — can take minutes; Space uses a server timeout fallback).\n\nTip: LoRA id must match Hub exactly, e.g. NITISHRG15102007/ev-oracle-lora"; args.oracleEl.textContent = "(click STEP — no auto-run avoids blocking on model load)"; appendEvent("(ready — click STEP or RUN 60)"); if (judgeMode) args.negoEl.textContent = "Judge Mode enabled. STEP runs multi-agent auto policies (grid+fleet)."; setReplayUi(); } catch (e: any) { pill(args.oracleBadge, "bad", "API ERROR"); pill(args.baselineBadge, "bad", "API ERROR"); const msg = String(e?.message || e); args.dreamEl.textContent = "ERROR: failed to create sessions.\n\n" + "- If this is a fresh Space cold-start, wait ~30s and refresh.\n" + "- Check `/health` loads.\n" + "- If roads are missing, the client should still render stations; this error is likely API reachability."; args.oracleEl.textContent = `ERROR: ${msg}`; args.eventsEl.textContent = `ERROR creating sessions:\n${msg}`; setVerdict("risk", "API ERROR"); } }; const stepOne = async () => { if (!baselineSid || !oracleSid) { appendEvent("(auto: creating sessions)"); await initSessions(); } if (!baselineSid || !oracleSid) throw new Error("Sessions not ready. Click New and wait for the Space to warm up."); const oracleRepo = args.loraEl.value || ""; if (judgeMode) { const bRes = await maAutoStep({ session_id: baselineSid, fleet_policy: "baseline", oracle_lora_repo: "" }); const oRes = await maAutoStep({ session_id: oracleSid, fleet_policy: "oracle", oracle_lora_repo: oracleRepo }); pill(args.baselineBadge, "warn", "heuristic"); pill(args.oracleBadge, "good", "MA ACTIVE"); // No Phaser event animation in MA v0 (server doesn't emit polylines yet). const rb = (oRes.obs?.reward_breakdown || {}) as Record; const top = Object.entries(rb) .filter(([k]) => k !== "total") .sort((a, b) => Math.abs(b[1]) - Math.abs(a[1])) .slice(0, 8) .map(([k, v]) => `${k}=${v.toFixed(3)}`) .join(" | "); const st = oRes.obs?.state; args.oracleEl.textContent = `ACTION: ${String(oRes.resolved_action?.action_type || "")} station=${String(oRes.resolved_action?.station_id || "NONE")}\n` + `GRID: load=${((st?.grid_load_pct ?? 0) * 100).toFixed(1)}% renew=${((st?.renewable_pct ?? 0) * 100).toFixed( 1 )}% peak=${String(st?.peak_risk || "")}\n` + `REWARD: total=${Number(rb.total ?? 0).toFixed(3)}\n` + `BREAKDOWN: ${top || "(empty)"}`; args.eventsEl.textContent = JSON.stringify( { baseline: { tick: bRes.tick, violations: bRes.violations, role_rewards: bRes.role_rewards }, oracle: { tick: oRes.tick, violations: oRes.violations, role_rewards: oRes.role_rewards }, }, null, 2 ); const msgs = (oRes.messages || []).slice(-6); args.negoEl.textContent = msgs.map((m: any) => `[${m.role}] ${m.text}`).join("\n") || "(no messages)"; // KPI delta: lightweight approximations from obs const bKpi = { baseline: { avg_wait_minutes: Number(bRes.obs?.state?.stations?.reduce((a: number, s: any) => a + s.avg_wait_minutes, 0) ?? 0) / Math.max(1, bRes.obs?.state?.stations?.length ?? 1), peak_violations: Number(bRes.obs?.state?.grid_load_pct ?? 0) > 0.8 ? 1 : 0, grid_stress_events: Number( (bRes.obs?.state?.stations ?? []).filter((s: any) => s.occupied_slots / Math.max(1, s.total_slots) > 0.85).length ), renewable_mean: Number(bRes.obs?.state?.renewable_pct ?? 0), }, }; const oKpi = { oracle: { avg_wait_minutes: Number(oRes.obs?.state?.stations?.reduce((a: number, s: any) => a + s.avg_wait_minutes, 0) ?? 0) / Math.max(1, oRes.obs?.state?.stations?.length ?? 1), peak_violations: Number(oRes.obs?.state?.grid_load_pct ?? 0) > 0.8 ? 1 : 0, grid_stress_events: Number( (oRes.obs?.state?.stations ?? []).filter((s: any) => s.occupied_slots / Math.max(1, s.total_slots) > 0.85).length ), renewable_mean: Number(oRes.obs?.state?.renewable_pct ?? 0), }, }; applyKpis(bKpi, oKpi, null); return; } const bRes = await demoStep({ session_id: baselineSid, mode: "baseline", oracle_lora_repo: "" }); const oRes = await demoStep({ session_id: oracleSid, mode: "oracle", oracle_lora_repo: oracleRepo }); if (!isReplaying) { baselineFrames.push({ tick: Number(bRes.tick ?? baselineFrames.length), action: bRes.action, event: bRes.event, anti_cheat_flags: bRes.anti_cheat_flags, anti_cheat_details: bRes.anti_cheat_details, scenario_events_at_tick: bRes.scenario_events_at_tick, }); oracleFrames.push({ tick: Number(oRes.tick ?? oracleFrames.length), action: oRes.action, event: oRes.event, anti_cheat_flags: oRes.anti_cheat_flags, anti_cheat_details: oRes.anti_cheat_details, scenario_events_at_tick: oRes.scenario_events_at_tick, }); const bi = baselineFrames.length - 1; const oi = oracleFrames.length - 1; if (bi >= 0 && oi >= 0) { episodeLog.push({ tick: Number(bRes.tick ?? bi), baseline: { ...baselineFrames[bi] }, oracle: { ...oracleFrames[oi] }, }); } setReplayUi(); } // animate const [bView, oView] = await withDeadline(Promise.all([baseline.ready, oracle.ready]), 10_000, "mapReady"); bView.setFollowVehicle(args.followEl.checked); oView.setFollowVehicle(args.followEl.checked); // Enrich route events with persona so MapView can pick car vs bike cleanly. const bEvt = { ...(bRes.event || {}), persona: String(bRes.obs?.state?.pending_evs?.[0]?.persona || "") }; const oEvt = { ...(oRes.event || {}), persona: String(oRes.obs?.state?.pending_evs?.[0]?.persona || "") }; await bView.playExternalEvent(bEvt); await oView.playExternalEvent(oEvt); // badges pill(args.baselineBadge, "warn", "heuristic"); if (!judgeMode && (oRes as any).oracle_timed_out) { pill(args.oracleBadge, "bad", "TIMEOUT→baseline"); } else if (!judgeMode && (oRes as any).oracle_skipped_env) { pill(args.oracleBadge, "warn", "SKIP LLM env"); } else { pill( args.oracleBadge, judgeMode ? "good" : (oRes as any).oracle_llm_active ? "good" : "warn", judgeMode ? "MA ACTIVE" : (oRes as any).oracle_llm_active ? "LLM ACTIVE" : "FALLBACK" ); } // right rail: dream panel + oracle panel const dreamScore = typeof (oRes as any).dream_score === "number" ? (oRes as any).dream_score : null; const dreamBreak = (oRes as any).dream_breakdown || {}; const dreamPred = (oRes as any).dream_pred || null; const dreamTrue = (oRes as any).dream_true || null; args.dreamEl.textContent = dreamScore == null ? "Dream score: N/A (no from Oracle yet)\n\nTip: run Oracle with LoRA trained on dream reward." : `DREAM SCORE: ${(dreamScore * 100).toFixed(1)}%\n\nPRED:\n${JSON.stringify(dreamPred, null, 2)}\n\nTRUE:\n${JSON.stringify(dreamTrue, null, 2)}\n\nBREAKDOWN:\n${JSON.stringify(dreamBreak, null, 2)}`; const rb = (oRes.obs?.reward_breakdown || {}) as Record; const top = Object.entries(rb) .filter(([k]) => k !== "total") .sort((a, b) => Math.abs(b[1]) - Math.abs(a[1])) .slice(0, 8) .map(([k, v]) => `${k}=${v.toFixed(3)}`) .join(" | "); const st = oRes.obs?.state; args.oracleEl.textContent = `ACTION: ${String(oRes.action?.action_type || "")} station=${String(oRes.action?.station_id || "NONE")}\n` + `GRID: load=${((st?.grid_load_pct ?? 0) * 100).toFixed(1)}% renew=${((st?.renewable_pct ?? 0) * 100).toFixed( 1 )}% peak=${String(st?.peak_risk || "")}\n` + `REWARD: total=${Number(rb.total ?? 0).toFixed(3)}\n` + `BREAKDOWN: ${top || "(empty)"}`; // diff panel: state + reward deltas (readable, judge-friendly) const bState = bRes.obs?.state || null; const oState = oRes.obs?.state || null; const oRb = (oRes.obs?.reward_breakdown || {}) as Record; args.diffEl.textContent = `BASELINE\n${summarizeDiff(lastBaselineState, bState)}\n\nORACLE\n${summarizeDiff(lastOracleState, oState)}\n\nORACLE REWARD\n${summarizeRewardDelta(lastOracleRb, oRb)}`; lastBaselineState = bState; lastOracleState = oState; lastOracleRb = oRb; // event stream + negotiation if (!judgeMode) { args.eventsEl.textContent = JSON.stringify( { baseline: { tick: (bRes as any).tick, event: (bRes as any).event, action: (bRes as any).action, anti: (bRes as any).anti_cheat_flags }, oracle: { tick: (oRes as any).tick, event: (oRes as any).event, action: (oRes as any).action, anti: (oRes as any).anti_cheat_flags }, }, null, 2 ); } else { args.eventsEl.textContent = JSON.stringify( { baseline: { tick: (bRes as any).tick, violations: (bRes as any).violations, role_rewards: (bRes as any).role_rewards }, oracle: { tick: (oRes as any).tick, violations: (oRes as any).violations, role_rewards: (oRes as any).role_rewards }, }, null, 2 ); const msgs = ((oRes as any).messages || []).slice(-6); args.negoEl.textContent = msgs.map((m: any) => `[${m.role}] ${m.text}`).join("\n") || "(no messages)"; } // KPI delta: use evaluate-style summary approximations from obs (lightweight) const bKpi = { baseline: { avg_wait_minutes: Number(bRes.obs?.state?.stations?.reduce((a: number, s: any) => a + s.avg_wait_minutes, 0) ?? 0) / Math.max(1, bRes.obs?.state?.stations?.length ?? 1), peak_violations: Number(bRes.obs?.state?.grid_load_pct ?? 0) > 0.8 ? 1 : 0, grid_stress_events: Number( (bRes.obs?.state?.stations ?? []).filter( (s: any) => s.occupied_slots / Math.max(1, s.total_slots) > 0.85 ).length ), renewable_mean: Number(bRes.obs?.state?.renewable_pct ?? 0), }, }; const oKpi = { oracle: { avg_wait_minutes: Number(oRes.obs?.state?.stations?.reduce((a: number, s: any) => a + s.avg_wait_minutes, 0) ?? 0) / Math.max(1, oRes.obs?.state?.stations?.length ?? 1), peak_violations: Number(oRes.obs?.state?.grid_load_pct ?? 0) > 0.8 ? 1 : 0, grid_stress_events: Number( (oRes.obs?.state?.stations ?? []).filter( (s: any) => s.occupied_slots / Math.max(1, s.total_slots) > 0.85 ).length ), renewable_mean: Number(oRes.obs?.state?.renewable_pct ?? 0), }, }; applyKpis(bKpi, oKpi, dreamScore); }; const runJudgeTour = async () => { if (tourBusy) return; tourBusy = true; const prevScenario = args.scenarioEl.value; const prevSeed = args.seedEl.value; const prevJudge = judgeMode; try { args.followEl.checked = true; judgeMode = false; // tour focuses on crisp route visuals + KPI deltas args.scenarioEl.value = args.scenarioEl.value || "festival_surge"; args.seedEl.value = String(Number(args.seedEl.value || "0") || seedRand()); setVerdict("ready", "TOUR"); setText("heroSub", "Judge tour: short scripted sequence (watch neon route + KPI deltas)."); args.btnDemo.disabled = true; args.btnRun.disabled = true; args.btnStep.disabled = true; args.btnNew.disabled = true; args.btnJudge.disabled = true; args.btnExport.disabled = true; await initSessions(); updateShareLink(); await sleep(450); const captions: string[] = [ "Step 1: route appears under current traffic.", "Step 2: congestion pressure builds — oracle should adapt.", "Step 3: KPI deltas begin separating (avg wait / stress / peak).", "Step 4: follow stays tight — no messy whole-city view.", "Step 5: 'wow' moment — smooth motion + crisp polyline.", "Step 6: wrap-up — hit Run 60 for long-horizon evidence.", ]; for (let i = 0; i < captions.length; i++) { setText("heroSub", captions[i]); // eslint-disable-next-line no-await-in-loop await stepOne(); // eslint-disable-next-line no-await-in-loop await sleep(420); } setVerdict("win", "TOUR DONE"); setText("heroSub", "Tour complete. Copy the share link in the log, or press Run 60 for full proof."); } catch (e) { reportFatal("TOUR ERROR", e); } finally { args.btnDemo.disabled = false; args.btnRun.disabled = false; args.btnStep.disabled = false; args.btnNew.disabled = false; args.btnJudge.disabled = false; args.btnExport.disabled = false; args.scenarioEl.value = prevScenario; args.seedEl.value = prevSeed; judgeMode = prevJudge; tourBusy = false; } }; const replayToTick = async (frameIdx: number) => { if (replayBusy) return; replayBusy = true; isReplaying = true; try { if (!baselineSid || !oracleSid) return; const seed = Number(args.seedEl.value || "0") || 123; const scenario = args.scenarioEl.value || "baseline"; const fleet = args.fleetEl ? args.fleetEl.value : "mixed"; stopPlay(); const [b, o] = await Promise.all([demoNew(seed, scenario, fleet), demoNew(seed, scenario, fleet)]); baselineSid = b.session_id; oracleSid = o.session_id; const [bView, oView] = await withDeadline(Promise.all([baseline.ready, oracle.ready]), 10_000, "mapReady"); await bView.bindSession(b.session_id, b.station_nodes as StationNode[]); await oView.bindSession(o.session_id, o.station_nodes as StationNode[]); const oracleRepo = args.loraEl.value || ""; const f = Math.max(0, Math.min(frameIdx, baselineFrames.length - 1, oracleFrames.length - 1)); let bLast: any = null; let oLast: any = null; for (let i = 0; i <= f; i++) { const bf = baselineFrames[i]; const of = oracleFrames[i]; // eslint-disable-next-line no-await-in-loop bLast = await demoStep({ session_id: baselineSid, mode: "baseline", oracle_lora_repo: "", forced_action: bf.action, }); // eslint-disable-next-line no-await-in-loop oLast = await demoStep({ session_id: oracleSid, mode: "oracle", oracle_lora_repo: oracleRepo, forced_action: of.action, }); } if (bLast && oLast) { const [bView2, oView2] = await withDeadline(Promise.all([baseline.ready, oracle.ready]), 10_000, "mapReady"); await bView2.playExternalEvent(bLast.event); await oView2.playExternalEvent(oLast.event); } } finally { isReplaying = false; replayBusy = false; } }; args.btnNew.onclick = async () => { await initSessions(); updateShareLink(); }; args.btnSpawn.onclick = async () => { try { args.btnSpawn.disabled = true; args.btnStep.disabled = true; args.btnRun.disabled = true; args.btnNew.disabled = true; args.btnExport.disabled = true; args.btnSpawn.textContent = "Spawning…"; if (!baselineSid || !oracleSid) await initSessions(); if (!baselineSid || !oracleSid) throw new Error("Sessions not ready."); const [bRes, oRes] = await Promise.all([ demoSpawnVehicle({ session_id: baselineSid, min_station_dist_m: 250, battery_threshold_pct: 30 }), demoSpawnVehicle({ session_id: oracleSid, min_station_dist_m: 250, battery_threshold_pct: 30 }), ]); const [bView, oView] = await withDeadline(Promise.all([baseline.ready, oracle.ready]), 10_000, "mapReady"); bView.setFollowVehicle(true); oView.setFollowVehicle(true); if (bRes?.event) await bView.playExternalEvent({ ...(bRes.event || {}), persona: String(bRes?.spawned_ev?.persona || "") }); if (oRes?.event) await oView.playExternalEvent({ ...(oRes.event || {}), persona: String(oRes?.spawned_ev?.persona || "") }); appendEvent(`spawned: ${String(oRes?.spawned_ev?.ev_id || bRes?.spawned_ev?.ev_id || "")}`); updateShareLink(); } catch (e) { reportFatal("SPAWN ERROR", e); } finally { args.btnSpawn.disabled = false; args.btnStep.disabled = false; args.btnRun.disabled = false; args.btnNew.disabled = false; args.btnExport.disabled = false; args.btnSpawn.textContent = "New Vehicle"; } }; args.btnStep.onclick = async () => { try { args.btnStep.disabled = true; args.btnRun.disabled = true; args.btnNew.disabled = true; args.btnSpawn.disabled = true; args.btnStep.textContent = "Stepping…"; // Default to follow mode so the judge can track the route/vehicle instantly. args.followEl.checked = true; await stepOne(); updateShareLink(); } catch (e) { reportFatal("STEP ERROR", e); } finally { args.btnStep.disabled = false; args.btnRun.disabled = false; args.btnNew.disabled = false; args.btnSpawn.disabled = false; args.btnStep.textContent = "Step"; } }; args.btnRun.onclick = async () => { try { args.btnStep.disabled = true; args.btnRun.disabled = true; args.btnNew.disabled = true; args.btnSpawn.disabled = true; args.btnRun.textContent = "Running…"; for (let i = 0; i < 60; i++) { // eslint-disable-next-line no-await-in-loop await stepOne(); // eslint-disable-next-line no-await-in-loop await new Promise((r) => setTimeout(r, 90)); } updateShareLink(); } catch (e) { reportFatal("RUN ERROR", e); } finally { args.btnStep.disabled = false; args.btnRun.disabled = false; args.btnNew.disabled = false; args.btnSpawn.disabled = false; args.btnRun.textContent = "Run 60"; } }; args.btnDemo.onclick = async () => { if (demoBusy) return; demoBusy = true; const prevScenario = args.scenarioEl.value; const prevSeed = args.seedEl.value; try { args.followEl.checked = true; args.scenarioEl.value = "festival_surge"; args.seedEl.value = String(seedRand()); setText("heroSub", "Guided demo: chaos spike → Oracle reroutes → KPI win banner. Watch the neon path + smooth car motion."); setVerdict("risk", "DEMO"); args.btnDemo.disabled = true; args.btnRun.disabled = true; args.btnStep.disabled = true; args.btnNew.disabled = true; args.btnExport.disabled = true; // New session await initSessions(); updateShareLink(); await sleep(450); // Cinematic: 14 ticks at readable pacing for (let i = 0; i < 14; i++) { await stepOne(); if (i === 2) setText("heroSub", "Congestion builds. Baseline keeps pushing straight into it."); if (i === 5) setText("heroSub", "Oracle uses road-level routing — follow mode stays glued to the moving EV."); if (i === 9) setText("heroSub", "Delta stabilizes. This is your “wow” moment on a projector."); await sleep(320); } setVerdict("win", "WIN"); setText("heroSub", "Guided demo complete. Now hit Run 60 for the longer replay proof, or scrub the timeline."); } catch (e) { reportFatal("DEMO ERROR", e); } finally { args.btnDemo.disabled = false; args.btnRun.disabled = false; args.btnStep.disabled = false; args.btnNew.disabled = false; args.btnExport.disabled = false; args.scenarioEl.value = prevScenario; args.seedEl.value = prevSeed; demoBusy = false; } }; args.tickEl.addEventListener("input", async () => { const t = Number(args.tickEl.value || "0"); args.tickLabelEl.textContent = String(t); if (baselineFrames.length === 0) return; await replayToTick(t); }); args.btnPlay.onclick = async () => { if (baselineFrames.length === 0) return; if (playing) { stopPlay(); return; } playing = true; args.btnPlay.textContent = "Pause"; let idx = Number(args.tickEl.value || "0"); playTimer = window.setInterval(() => { void (async () => { idx = Math.min(idx + 1, baselineFrames.length - 1); args.tickEl.value = String(idx); args.tickLabelEl.textContent = String(idx); try { await replayToTick(idx); } catch { stopPlay(); } if (idx >= baselineFrames.length - 1) stopPlay(); })(); }, 320); }; // initial badges pill(args.baselineBadge, "warn", "heuristic"); pill(args.oracleBadge, "warn", "ready"); // Auto-start for Spaces (no need to click New) window.setTimeout(() => { applyUrlParams(); void initSessions(); const p = new URLSearchParams(window.location.search || ""); if (p.get("tour") === "1" || p.get("tour")?.toLowerCase() === "true") { window.setTimeout(() => void runJudgeTour(), 650); } }, 200); args.btnJudge.onclick = async () => { judgeMode = true; args.eventsEl.textContent = "(Judge Mode enabled — multi-agent protocol)"; await initSessions(); updateShareLink(); }; args.btnExport.onclick = () => { const seed = Number(args.seedEl.value || "0") || 0; const scenario = args.scenarioEl.value || "baseline"; const fleet = args.fleetEl ? args.fleetEl.value : "mixed"; const payload = { exported_at: new Date().toISOString(), seed, scenario, fleet, judge_mode: judgeMode, frames: episodeLog, }; const blob = new Blob([JSON.stringify(payload, null, 2)], { type: "application/json" }); const a = document.createElement("a"); a.href = URL.createObjectURL(blob); a.download = `ev-grid-oracle-episode-${scenario}-${seed}-${Date.now()}.json`; a.click(); URL.revokeObjectURL(a.href); appendEvent("(exported episode JSON — use OS screenshot for map stills)"); }; // Power-user keyboard shortcut: Shift+T runs the judge tour. window.addEventListener("keydown", (ev) => { if (ev.key.toLowerCase() === "t" && ev.shiftKey) void runJudgeTour(); }); }