Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"/> | |
| <!-- | |
| KHIPU — Sovereign Ledger. A single screen fusing the whole SZL organism's | |
| HEALTH and SPEND into one living knotted-cord record (khipu: the Andean | |
| tactile ledger — a one-of-one metaphor for a hash-linked spend chain). | |
| Doctrine: 0 runtime CDN, 0 build step, pure inline CSS/JS. Honest by | |
| construction — every figure renders only if its own feed answered; nulls show | |
| "—", a dead feed shows "unreachable", nothing is ever fabricated. Frugal by | |
| construction — the SVG is rebuilt only on the 15s refresh; motion is CSS-only | |
| (GPU-composited), no requestAnimationFrame loop burns CPU. | |
| Feeds (all same-origin, all free): | |
| GET /api/a11oy/v1/engine/status (szl.engine_status/v1) — organs, mind, energy | |
| GET /api/a11oy/v1/spend/state (szl_spend_cap) — cap, spent, kill, chain | |
| GET /api/a11oy/v1/constellation (szl.constellation_status/v1) — estate surfaces | |
| --> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"/> | |
| <title>KHIPU · Sovereign Ledger</title> | |
| <style> | |
| :root{ | |
| --void:#080c14; --void2:#0b1220; --panel:#0d1524; --line:#173049; | |
| --teal:#3af4c8; --teal-dim:#1c8f78; --amber:#f5a623; --amber-dim:#7a5410; | |
| --red:#ff5470; --ink:#e8f6f1; --mute:#6f8c9c; | |
| --mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace; | |
| --sans:"Inter",system-ui,-apple-system,Segoe UI,Roboto,sans-serif; | |
| } | |
| *{box-sizing:border-box} | |
| html,body{margin:0;height:100%} | |
| body{ | |
| background: | |
| radial-gradient(1200px 700px at 78% -10%, rgba(58,244,200,.08), transparent 60%), | |
| radial-gradient(900px 600px at 8% 110%, rgba(245,166,35,.06), transparent 60%), | |
| var(--void); | |
| color:var(--ink); font-family:var(--sans); -webkit-font-smoothing:antialiased; | |
| display:flex; flex-direction:column; min-height:100%; | |
| } | |
| a{color:inherit;text-decoration:none} | |
| .wrap{max-width:1280px;width:100%;margin:0 auto;padding:22px 22px 40px;flex:1;display:flex;flex-direction:column} | |
| /* header */ | |
| header{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;flex-wrap:wrap;margin-bottom:18px} | |
| .brand{display:flex;align-items:baseline;gap:14px} | |
| .brand h1{font-family:var(--mono);font-size:30px;letter-spacing:.42em;margin:0;font-weight:600; | |
| background:linear-gradient(90deg,var(--teal),#bfeee2);-webkit-background-clip:text;background-clip:text;color:transparent} | |
| .brand .tag{color:var(--mute);font-size:12.5px;letter-spacing:.02em} | |
| .brand .tag b{color:var(--teal-dim);font-weight:600} | |
| .clock{font-family:var(--mono);font-size:11.5px;color:var(--mute);text-align:right;line-height:1.7} | |
| .clock .dot{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--teal);margin-right:6px; | |
| box-shadow:0 0 8px var(--teal);animation:beat 2.4s ease-in-out infinite} | |
| /* stat strip */ | |
| .strip{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:14px} | |
| .lamps{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:20px} | |
| .card{background:linear-gradient(180deg,var(--panel),var(--void2));border:1px solid var(--line); | |
| border-radius:14px;padding:15px 17px;position:relative;overflow:hidden} | |
| .card::before{content:"";position:absolute;inset:0 auto 0 0;width:3px;background:var(--teal-dim);opacity:.6} | |
| .card.amber::before{background:var(--amber)} | |
| .card.red::before{background:var(--red)} | |
| .card .k{font-size:10.5px;letter-spacing:.18em;text-transform:uppercase;color:var(--mute)} | |
| .card .v{font-family:var(--mono);font-size:29px;margin-top:7px;line-height:1;letter-spacing:-.01em} | |
| .card .v small{font-size:14px;color:var(--mute)} | |
| .card.amber .v{color:var(--amber)} | |
| .card .sub{font-size:11px;color:var(--mute);margin-top:7px;font-family:var(--mono)} | |
| /* lamps */ | |
| .lamp{display:flex;align-items:center;gap:11px;background:var(--void2);border:1px solid var(--line); | |
| border-radius:12px;padding:13px 15px} | |
| .lamp .bulb{width:12px;height:12px;border-radius:50%;flex:none;background:var(--mute);box-shadow:0 0 0 rgba(0,0,0,0)} | |
| .lamp.ok .bulb{background:var(--teal);box-shadow:0 0 12px var(--teal);animation:beat 2.6s ease-in-out infinite} | |
| .lamp.warn .bulb{background:var(--amber);box-shadow:0 0 12px var(--amber)} | |
| .lamp.bad .bulb{background:var(--red);box-shadow:0 0 14px var(--red);animation:beat 1s ease-in-out infinite} | |
| .lamp .lt{display:flex;flex-direction:column;gap:2px;min-width:0} | |
| .lamp .lt .n{font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--mute)} | |
| .lamp .lt .s{font-family:var(--mono);font-size:15px;letter-spacing:.02em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} | |
| .lamp.ok .s{color:var(--teal)} .lamp.warn .s{color:var(--amber)} .lamp.bad .s{color:var(--red)} | |
| /* khipu */ | |
| .khipu{background:linear-gradient(180deg,rgba(13,21,36,.7),rgba(8,12,20,.7)); | |
| border:1px solid var(--line);border-radius:16px;padding:8px 6px 4px;flex:1;min-height:360px;position:relative} | |
| .khipu svg{display:block;width:100%;height:100%} | |
| .cordwrap{transform-box:fill-box;transform-origin:top center} | |
| .sway0{animation:sway 7s ease-in-out infinite} | |
| .sway1{animation:sway 8.5s ease-in-out infinite;animation-delay:-2s} | |
| .sway2{animation:sway 6.2s ease-in-out infinite;animation-delay:-4s} | |
| .knot{transform-box:fill-box;transform-origin:center} | |
| .knot.live{animation:pulse 2.8s ease-in-out infinite} | |
| .lgd{display:flex;gap:18px;flex-wrap:wrap;justify-content:center;margin-top:6px;color:var(--mute);font-size:11px} | |
| .lgd i{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:6px;vertical-align:middle} | |
| footer{margin-top:16px;color:var(--mute);font-size:11.5px;text-align:center;line-height:1.7} | |
| footer b{color:var(--teal-dim)} | |
| @keyframes beat{0%,100%{opacity:1}50%{opacity:.35}} | |
| @keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(1.55)}} | |
| @keyframes sway{0%,100%{transform:translateX(-3px) rotate(-.5deg)}50%{transform:translateX(3px) rotate(.5deg)}} | |
| @media (max-width:760px){.strip,.lamps{grid-template-columns:repeat(2,1fr)}.brand h1{font-size:22px;letter-spacing:.3em}} | |
| @media (prefers-reduced-motion:reduce){*{animation:none}} | |
| /* federated (authoritative box) spend panel */ | |
| .localttl{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--mute);margin:2px 2px 8px} | |
| .fedwrap{margin:6px 0 18px;padding:14px 15px 15px;border:1px solid var(--teal-dim);border-radius:14px; | |
| background:linear-gradient(180deg,rgba(58,244,200,.05),rgba(8,12,20,.5))} | |
| .fedttl{font-family:var(--mono);font-size:12.5px;letter-spacing:.06em;color:var(--ink);margin-bottom:6px;display:flex;align-items:center;gap:10px;flex-wrap:wrap} | |
| .fedttl .badge{font-size:9.5px;letter-spacing:.16em;background:var(--teal);color:#04241d;padding:3px 8px;border-radius:20px;font-weight:700} | |
| .fedttl .fedsrc{color:var(--mute);font-size:10.5px;letter-spacing:.02em} | |
| .fednote{color:var(--mute);font-size:10.5px;margin:0 0 12px;line-height:1.5} | |
| .fedwrap .strip{margin-bottom:12px} | |
| .fedwrap .lamps{margin-bottom:0} | |
| /* governed frontier console */ | |
| .frin,.frta{width:100%;background:rgba(8,12,20,.7);border:1px solid var(--line);color:var(--ink); | |
| font-family:var(--mono);font-size:12px;border-radius:9px;padding:9px 10px;outline:none;box-sizing:border-box} | |
| .frin:focus,.frta:focus{border-color:var(--teal-dim)} | |
| .frta{resize:vertical;min-height:40px;line-height:1.5} | |
| .frrow{display:flex;gap:8px;align-items:flex-start;margin:8px 0} | |
| .frbtn{white-space:nowrap;background:var(--teal);color:#04241d;border:none;font-weight:700; | |
| font-family:var(--mono);font-size:11.5px;letter-spacing:.04em;padding:9px 14px;border-radius:9px;cursor:pointer} | |
| .frbtn.ghost{background:transparent;color:var(--teal-dim);border:1px solid var(--teal-dim);font-weight:600} | |
| .frbtn:disabled{opacity:.45;cursor:default} | |
| .frout{margin-top:6px} | |
| .frchips{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0} | |
| .chip{font-family:var(--mono);font-size:10px;letter-spacing:.04em;padding:3px 8px;border-radius:20px; | |
| border:1px solid var(--line);color:var(--mute);background:rgba(8,12,20,.5)} | |
| .chip.ok{border-color:var(--teal-dim);color:var(--teal);background:rgba(58,244,200,.08)} | |
| .chip.bad{border-color:#ff5470;color:#ff5470;background:rgba(255,84,112,.08)} | |
| .chip.amber{border-color:#f5a623;color:#f5a623;background:rgba(245,166,35,.08)} | |
| .franswer{white-space:pre-wrap;font-size:13px;line-height:1.55;color:var(--ink);background:rgba(8,12,20,.5); | |
| border:1px solid var(--line);border-radius:10px;padding:11px 12px;margin:6px 0} | |
| .frraw{margin-top:6px} | |
| .frraw summary{cursor:pointer;color:var(--mute);font-family:var(--mono);font-size:10.5px;letter-spacing:.04em} | |
| .frraw pre{white-space:pre-wrap;word-break:break-all;font-family:var(--mono);font-size:10px;color:var(--mute); | |
| background:rgba(8,12,20,.6);border:1px solid var(--line);border-radius:8px;padding:10px;margin:6px 0 0;max-height:220px;overflow:auto} | |
| </style> | |
| </head> | |
| <body> | |
| <div class="wrap"> | |
| <header> | |
| <div class="brand"> | |
| <h1>KHIPU</h1> | |
| <div class="tag">Sovereign Ledger — the whole organism's <b>health</b> & <b>spend</b>, one screen · honest by construction</div> | |
| </div> | |
| <div class="clock"><span><span class="dot"></span><span id="live">live</span></span><br/><span id="ts">—</span></div> | |
| </header> | |
| <div class="localttl">a11oy module ledger — local / advisory (in-container)</div> | |
| <section class="strip" id="strip"></section> | |
| <section class="lamps" id="lamps"></section> | |
| <section class="fedwrap"> | |
| <div class="fedttl"><span class="badge">AUTHORITATIVE</span> Live Sovereign Router — real paid spend on the box ledger <span class="fedsrc" id="fedsrc">—</span></div> | |
| <div class="fednote">read live from the box router at request time · chain state as reported by the source · never summed with the local advisory ledger above</div> | |
| <div class="strip" id="fedstrip"></div> | |
| <div class="lamps" id="fedlamps"></div> | |
| </section> | |
| <section class="fedwrap frontier"> | |
| <div class="fedttl"><span class="badge">GOVERNED</span> Frontier Console — one capped call, receipt verified locally <span class="fedsrc" id="frstate">—</span></div> | |
| <div class="fednote">operator-gated · model pinned · max 256 tokens · 8s cooldown · 50/day · the box router meters & kill-switches every call. a11oy verifies the DSSE / ECDSA-P256 receipt against a <b>pinned</b> key — the router is never trusted, the math is checked here.</div> | |
| <div class="frrow"> | |
| <input id="frop" class="frin" type="password" autocomplete="off" spellcheck="false" placeholder="operator token (kept only in this browser)"/> | |
| <button id="frsave" class="frbtn ghost" type="button">remember</button> | |
| </div> | |
| <div class="frrow"> | |
| <textarea id="frprompt" class="frta" rows="2" maxlength="600" placeholder="Ask the sovereign router something… (governed, capped, receipted · ⌘/Ctrl+Enter)"></textarea> | |
| <button id="frask" class="frbtn" type="button">Ask →</button> | |
| </div> | |
| <div id="frout" class="frout"></div> | |
| </section> | |
| <section class="khipu"><div id="khipu"></div></section> | |
| <div class="lgd"> | |
| <span><i style="background:#3af4c8"></i>live / intact</span> | |
| <span><i style="background:#f5a623"></i>spend</span> | |
| <span><i style="background:#ff5470"></i>down / tripped</span> | |
| <span><i style="background:#6f8c9c"></i>unknown / —</span> | |
| </div> | |
| <footer> | |
| Every value comes from a live feed; a silent source renders <b>—</b> or <b>unreachable</b>, never fake-green (Doctrine v11). | |
| · Free-first: sovereign compute + free grid; paid inference is capped and kill-switched, never quiet. | |
| · refresh 15s | |
| </footer> | |
| </div> | |
| <script> | |
| (function(){ | |
| "use strict"; | |
| var $=function(id){return document.getElementById(id)}; | |
| function esc(s){return String(s==null?"":s).replace(/[&<>"]/g,function(c){return {"&":"&","<":"<",">":">",'"':"""}[c]})} | |
| function money(x){ if(x==null||isNaN(x)) return null; return "$"+Number(x).toLocaleString(undefined,{minimumFractionDigits:2,maximumFractionDigits:2}); } | |
| function money6(x){ if(x==null||isNaN(x)) return null; var n=Number(x); if(n===0) return "$0.00"; if(Math.abs(n)<0.01) return "$"+n.toFixed(6); return "$"+n.toLocaleString(undefined,{minimumFractionDigits:2,maximumFractionDigits:2}); } | |
| function fetchJSON(url){ | |
| return fetch(url,{headers:{accept:"application/json"},cache:"no-store"}) | |
| .then(function(r){ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); }) | |
| .catch(function(){ return null; }); | |
| } | |
| // reachability, tolerant of several honest shapes | |
| function reach(o){ | |
| if(!o||typeof o!=="object") return null; | |
| var v = (o.reachable!=null?o.reachable : (o.ok!=null?o.ok : (o.up!=null?o.up : (o.alive!=null?o.alive : null)))); | |
| if(v==null && typeof o.status==="string") v = /^(up|live|ok|ready|running|healthy)$/i.test(o.status); | |
| return v; | |
| } | |
| function stateClass(v){ return v===true?"live":(v===false?"down":"na"); } | |
| function colorOf(v){ return v===true?"#3af4c8":(v===false?"#ff5470":"#6f8c9c"); } | |
| // ---------- cockpit strip + lamps (from spend/state) ---------- | |
| function renderSpend(sp){ | |
| var strip=$("strip"), lamps=$("lamps"); | |
| if(!sp){ | |
| strip.innerHTML = '<div class="card red"><div class="k">Spend ledger</div><div class="v">unreachable</div><div class="sub">the spend feed did not answer</div></div>'; | |
| lamps.innerHTML=""; return; | |
| } | |
| var cap=sp.cap_usd, spent=sp.spent_usd, rem=sp.remaining_usd, pct=sp.pct_used; | |
| var overspend = (rem!=null && rem<=0); | |
| strip.innerHTML = | |
| card("Hard cap", money(cap), "ceiling · $"+ (cap!=null?cap:"—"), "") + | |
| card("Spent", money(spent)||"—", (sp.entries!=null?sp.entries+" ledger entries":""), "amber") + | |
| card("Remaining", money(rem)||"—", "", overspend?"red":"") + | |
| card("Utilisation", (pct!=null? pct+"% ":"—"), bar(pct), pct!=null&&pct>=90?"red":(pct!=null&&pct>=60?"amber":"")); | |
| lamps.innerHTML = | |
| lamp("Spend cap", sp.armed===true?"ARMED":"—", sp.armed===true?"ok":"na") + | |
| lamp("Status", sp.tripped===true?"TRIPPED":(sp.tripped===false?"CLEAR":"—"), sp.tripped===true?"bad":(sp.tripped===false?"ok":"na")) + | |
| lamp("Kill-switch", sp.kill_file_engaged===true?"ENGAGED":(sp.kill_file_engaged===false?"ready":"—"), sp.kill_file_engaged===true?"bad":(sp.kill_file_engaged===false?"ok":"na")) + | |
| lamp("Ledger chain", (sp.chain&&sp.chain.intact===true)?"INTACT":((sp.chain&&sp.chain.intact===false)?"BROKEN":"—"), (sp.chain&&sp.chain.intact===true)?"ok":((sp.chain&&sp.chain.intact===false)?"bad":"na")); | |
| } | |
| function card(k,v,sub,cls){ | |
| return '<div class="card '+(cls||"")+'"><div class="k">'+esc(k)+'</div><div class="v">'+(v==null?"—":v)+'</div>'+(sub?'<div class="sub">'+sub+'</div>':'')+'</div>'; | |
| } | |
| function bar(pct){ | |
| if(pct==null) return ""; | |
| var p=Math.max(0,Math.min(100,pct)); | |
| var col = p>=90?"#ff5470":(p>=60?"#f5a623":"#3af4c8"); | |
| return '<div style="height:5px;border-radius:3px;background:#122;overflow:hidden;margin-top:8px"><div style="height:100%;width:'+p+'%;background:'+col+'"></div></div>'; | |
| } | |
| function lamp(n,s,cls){ | |
| return '<div class="lamp '+cls+'"><span class="bulb"></span><span class="lt"><span class="n">'+esc(n)+'</span><span class="s">'+esc(s)+'</span></span></div>'; | |
| } | |
| // ---------- federated (authoritative box-router) spend panel ---------- | |
| function renderFed(fs){ | |
| var strip=$("fedstrip"), lamps=$("fedlamps"), src=$("fedsrc"); | |
| if(!strip) return; | |
| function down(msg,sub,cls){ strip.innerHTML='<div class="card '+(cls||"")+'"><div class="k">Router spend</div><div class="v">'+esc(msg)+'</div>'+(sub?'<div class="sub">'+esc(sub)+'</div>':'')+'</div>'; lamps.innerHTML=""; src.textContent=""; } | |
| if(!fs){ down("unreachable","the federation feed did not answer","red"); return; } | |
| if(fs.state==="not_configured"){ down("not configured","set SZL_ROUTER_SPEND_URL to federate the box ledger",""); return; } | |
| if(fs.state!=="live" || fs.reachable!==true){ down("unreachable","box router did not answer (http "+(fs.http_status!=null?fs.http_status:"?")+")","red"); return; } | |
| var cap=fs.cap_usd, spent=fs.spent_usd, rem=fs.remaining_usd, pct=fs.pct_used; | |
| var overspend=(rem!=null && rem<=0); | |
| strip.innerHTML = | |
| card("Hard cap", money6(cap), "ceiling", "") + | |
| card("Spent (real, paid)", money6(spent)||"—", (fs.entries!=null?fs.entries+" ledger entries":""), "amber") + | |
| card("Remaining", money6(rem)||"—", "", overspend?"red":"") + | |
| card("Utilisation", (pct!=null? pct+"% ":"—"), bar(pct), pct!=null&&pct>=90?"red":(pct!=null&&pct>=60?"amber":"")); | |
| lamps.innerHTML = | |
| lamp("Spend cap", fs.armed===true?"ARMED":"\u2014", fs.armed===true?"ok":"na") + | |
| lamp("Status", fs.tripped===true?"TRIPPED":(fs.tripped===false?"CLEAR":"\u2014"), fs.tripped===true?"bad":(fs.tripped===false?"ok":"na")) + | |
| lamp("Kill-switch", fs.kill_file_engaged===true?"ENGAGED":(fs.kill_file_engaged===false?"ready":"\u2014"), fs.kill_file_engaged===true?"bad":(fs.kill_file_engaged===false?"ok":"na")) + | |
| lamp("Ledger chain", fs.chain_intact===true?"INTACT":(fs.chain_intact===false?"BROKEN":"\u2014"), fs.chain_intact===true?"ok":(fs.chain_intact===false?"bad":"na")); | |
| var when = fs.upstream_generated || fs.checked_at || ""; | |
| src.textContent = (when? "\u00b7 as of "+when : "") + (fs.cache? " ("+fs.cache+")":""); | |
| } | |
| // ---------- the khipu (organs + spend sources + estate) ---------- | |
| var VW=1200, VH=460, TOP=78, BASE=430; | |
| function pendant(x, len, knots, cls, label, swayCls){ | |
| var bx = x + (Math.sin(x)*8); // gentle static bow, deterministic | |
| var path = 'M '+x+' '+TOP+' Q '+((x+bx)/2)+' '+((TOP+len)/2)+' '+bx+' '+len; | |
| var s = '<g class="cordwrap '+swayCls+'">'; | |
| s += '<path d="'+path+'" fill="none" stroke="'+colorOf(cls==="live"?true:(cls==="down"?false:null))+'" stroke-width="1.6" opacity="'+(cls==="na"?.4:.75)+'"/>'; | |
| var n = Math.max(1, knots|0); | |
| for(var i=0;i<n;i++){ | |
| var t=(i+1)/(n+1); | |
| var kx = x + (bx-x)*t, ky = TOP + (len-TOP)*t; | |
| var kn = (cls==="live"?"knot live":"knot"); | |
| s += '<circle class="'+kn+'" cx="'+kx.toFixed(1)+'" cy="'+ky.toFixed(1)+'" r="'+(cls==="down"?4.6:4)+'" fill="'+colorOf(cls==="live"?true:(cls==="down"?false:null))+'" opacity="'+(cls==="na"?.5:.95)+'" style="animation-delay:'+(i*0.3).toFixed(1)+'s"/>'; | |
| } | |
| s += '<circle cx="'+x+'" cy="'+TOP+'" r="2.6" fill="#bfeee2"/>'; | |
| s += '<text x="'+bx.toFixed(1)+'" y="'+(len+16)+'" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#6f8c9c">'+esc(label)+'</text>'; | |
| s += '</g>'; | |
| return s; | |
| } | |
| function sectionLabel(cx, text){ | |
| return '<text x="'+cx+'" y="44" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="11" letter-spacing="3" fill="#3af4c8" opacity=".8">'+esc(text)+'</text>'; | |
| } | |
| function spread(x0,x1,n){ var a=[]; if(n<=0) return a; if(n===1){a.push((x0+x1)/2);return a;} for(var i=0;i<n;i++)a.push(x0+(x1-x0)*i/(n-1)); return a; } | |
| function renderKhipu(eng, sp, con, fed){ | |
| var svg='<svg viewBox="0 0 '+VW+' '+VH+'" preserveAspectRatio="xMidYMid meet" role="img" aria-label="Sovereign khipu">'; | |
| svg += '<line x1="48" y1="'+TOP+'" x2="'+(VW-48)+'" y2="'+TOP+'" stroke="#173049" stroke-width="3" stroke-linecap="round"/>'; | |
| // section 1: VITALS (organs) | |
| var organs = (eng&&eng.organs&&typeof eng.organs==="object")?eng.organs:null; | |
| svg += sectionLabel(250,"VITALS"); | |
| if(organs){ | |
| var names=Object.keys(organs); var xs=spread(90,430,Math.max(1,names.length)); | |
| for(var i=0;i<names.length;i++){ | |
| var v=reach(organs[names[i]]); var len=BASE-((i%3)*26); | |
| svg += pendant(xs[i], len, 3, stateClass(v), names[i].slice(0,7), "sway0"); | |
| } | |
| if(!names.length) svg += emptyCord(250,"no organs reported","sway0"); | |
| } else svg += emptyCord(250, eng?"no organ data":"engine unreachable","sway0"); | |
| // section 2: SPEND (real box-router ledger; falls back to local advisory) | |
| svg += sectionLabel(600,"SPEND"); | |
| var spendSrc = (fed && fed.state==="live" && fed.reachable===true) ? fed : sp; | |
| if(spendSrc){ | |
| var tail=(spendSrc.tail&&spendSrc.tail.length)?spendSrc.tail.slice(-6):[]; | |
| if(tail.length){ | |
| var total=tail.reduce(function(a,e){return a+(+e.amount_usd||0)},0)||1; | |
| var xs2=spread(480,720,tail.length); | |
| for(var j=0;j<tail.length;j++){ | |
| var amt=+tail[j].amount_usd||0; var kk=Math.max(1,Math.min(9,Math.round(1+8*(amt/total)))); | |
| svg += pendantAmber(xs2[j], BASE-((j%2)*30), kk, (tail[j].source||"?").slice(0,8), money6(amt)||"", "sway1"); | |
| } | |
| } else { | |
| var sv=(spendSrc.spent_usd!=null?spendSrc.spent_usd:null); | |
| svg += emptyCord(600, (sv? money6(sv):"$0.00")+" spent","sway1"); | |
| } | |
| } else svg += emptyCord(600,"spend unreachable","sway1"); | |
| // section 3: ESTATE (constellation surfaces) | |
| svg += sectionLabel(955,"ESTATE"); | |
| var surfaces = con && (Array.isArray(con.surfaces)?con.surfaces:(Array.isArray(con)?con:null)); | |
| if(surfaces){ | |
| var ss=surfaces.slice(0,9); var xs3=spread(772,1140,Math.max(1,ss.length)); | |
| for(var k=0;k<ss.length;k++){ | |
| var s=ss[k]; var v3=reach(s); var nm=(s.name||s.id||s.slug||"?"); | |
| svg += pendant(xs3[k], BASE-((k%3)*24), 2, stateClass(v3), String(nm).slice(0,9), "sway2"); | |
| } | |
| if(!ss.length) svg += emptyCord(955,"no surfaces reported","sway2"); | |
| } else svg += emptyCord(955, con?"no estate data":"constellation unreachable","sway2"); | |
| svg += '</svg>'; | |
| $("khipu").innerHTML = svg; | |
| } | |
| function pendantAmber(x,len,knots,label,val,swayCls){ | |
| var bx=x+(Math.sin(x)*8); | |
| var path='M '+x+' '+TOP+' Q '+((x+bx)/2)+' '+((TOP+len)/2)+' '+bx+' '+len; | |
| var s='<g class="cordwrap '+swayCls+'"><path d="'+path+'" fill="none" stroke="#f5a623" stroke-width="1.6" opacity=".8"/>'; | |
| var n=Math.max(1,knots|0); | |
| for(var i=0;i<n;i++){var t=(i+1)/(n+1);var kx=x+(bx-x)*t,ky=TOP+(len-TOP)*t; | |
| s+='<circle cx="'+kx.toFixed(1)+'" cy="'+ky.toFixed(1)+'" r="3.7" fill="#f5a623" opacity=".95"/>';} | |
| s+='<circle cx="'+x+'" cy="'+TOP+'" r="2.6" fill="#f5d18a"/>'; | |
| s+='<text x="'+bx.toFixed(1)+'" y="'+(len+16)+'" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10" fill="#a9803a">'+esc(label)+'</text>'; | |
| s+='<text x="'+bx.toFixed(1)+'" y="'+(len+28)+'" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="9" fill="#6f8c9c">'+esc(val)+'</text></g>'; | |
| return s; | |
| } | |
| function emptyCord(cx,text,swayCls){ | |
| return '<g class="cordwrap '+swayCls+'"><line x1="'+cx+'" y1="'+TOP+'" x2="'+cx+'" y2="'+(TOP+120)+'" stroke="#173049" stroke-width="1.4" stroke-dasharray="3 5"/>'+ | |
| '<circle cx="'+cx+'" cy="'+TOP+'" r="2.6" fill="#3a5568"/>'+ | |
| '<text x="'+cx+'" y="'+(TOP+140)+'" text-anchor="middle" font-family="ui-monospace,Menlo,monospace" font-size="10.5" fill="#6f8c9c">'+esc(text)+'</text></g>'; | |
| } | |
| // ---------- governed frontier console ---------- | |
| var FR_KEY="szl_frontier_op"; | |
| function frToken(){ try{return localStorage.getItem(FR_KEY)||"";}catch(e){return "";} } | |
| function frChip(label,cls){ return '<span class="chip '+(cls||"")+'">'+esc(label)+'</span>'; } | |
| function frRender(d){ | |
| var out=$("frout"), st=$("frstate"); | |
| if(!d){ out.innerHTML='<div class="franswer">the console could not reach a11oy (network).</div>'; st.textContent="\u2014"; return; } | |
| var s=d.state||"?"; | |
| var label={verified:"RECEIPT VERIFIED",verify_failed:"VERIFY FAILED",receipt_unsigned:"UNSIGNED",receipt_missing:"NO RECEIPT",receipt_unparseable:"BAD RECEIPT",not_configured:"NOT CONFIGURED",unauthorized:"UNAUTHORIZED",bad_request:"BAD REQUEST",unreachable:"ROUTER UNREACHABLE",cooldown:"COOLDOWN",daily_cap:"DAILY CAP",busy:"BUSY"}[s]||String(s).toUpperCase(); | |
| var cls=(s==="verified")?"ok":((s==="verify_failed"||s==="unauthorized"||s==="unreachable")?"bad":"amber"); | |
| st.innerHTML=frChip(label,cls); | |
| if(s==="not_configured"){ out.innerHTML='<div class="franswer">Frontier edge/operator not provisioned yet.</div>'; return; } | |
| if(s==="unauthorized"){ out.innerHTML='<div class="franswer">Operator token rejected. Paste your token above and try again.</div>'; return; } | |
| if(s==="cooldown"){ out.innerHTML='<div class="franswer">Cooling down — retry in '+esc(d.retry_after_s)+'s (governance).</div>'; return; } | |
| if(s==="daily_cap"){ out.innerHTML='<div class="franswer">Daily governed-call cap reached ('+esc(d.daily_cap)+').</div>'; return; } | |
| if(s==="busy"){ out.innerHTML='<div class="franswer">A governed call is already in flight — one at a time.</div>'; return; } | |
| if(s==="unreachable"){ out.innerHTML='<div class="franswer">Box router did not answer (http '+esc(d.http_status)+').</div>'; return; } | |
| if(s==="bad_request"){ out.innerHTML='<div class="franswer">'+esc(d.detail||"bad request")+'</div>'; return; } | |
| var html=""; | |
| if(d.answer){ html+='<div class="franswer">'+esc(d.answer)+'</div>'; } | |
| var r=d.receipt||{}, p=d.provenance||{}, u=d.usage||{}; | |
| var chips=""; | |
| chips+=frChip((r.verified?"\u2713 ":"\u2717 ")+"DSSE "+(r.verified?"verified":(r.reason||"unverified")), r.verified?"ok":"bad"); | |
| if(p.tier) chips+=frChip("tier "+p.tier,""); | |
| if(p.served_by) chips+=frChip("via "+p.served_by,""); | |
| if(p.upstream_model||p.model) chips+=frChip("model "+(p.upstream_model||p.model),""); | |
| if(p.amount_usd!=null) chips+=frChip((p.estimated?"~":"")+(money6(p.amount_usd)||"$0.00")+" this call","amber"); | |
| if(u.total_tokens!=null) chips+=frChip(u.total_tokens+" tok",""); | |
| if(r.keyid) chips+=frChip("keyid "+String(r.keyid).slice(0,12),""); | |
| if(r.organ) chips+=frChip("organ "+r.organ,""); | |
| if(p.request_digest) chips+=frChip("req "+String(p.request_digest).slice(0,10),""); | |
| html+='<div class="frchips">'+chips+'</div>'; | |
| if(d.envelope){ html+='<details class="frraw"><summary>raw DSSE receipt — verify it yourself</summary><pre>'+esc(JSON.stringify(d.envelope,null,2))+'</pre></details>'; } | |
| out.innerHTML=html; | |
| } | |
| function frAsk(){ | |
| var tok=(($("frop").value||"")||frToken()).trim(); | |
| var prompt=($("frprompt").value||"").trim(); | |
| var btn=$("frask"); | |
| if(!prompt){ $("frprompt").focus(); return; } | |
| btn.disabled=true; $("frstate").innerHTML='<span class="chip amber">calling\u2026</span>'; | |
| $("frout").innerHTML='<div class="franswer">routing one governed call\u2026</div>'; | |
| fetch("/api/a11oy/v1/frontier/ask",{method:"POST",cache:"no-store", | |
| headers:{"content-type":"application/json","accept":"application/json","x-szl-operator":tok}, | |
| body:JSON.stringify({prompt:prompt})}) | |
| .then(function(r){ return r.json().catch(function(){return null;}); }) | |
| .then(function(d){ frRender(d); }) | |
| .catch(function(){ frRender(null); }) | |
| .then(function(){ btn.disabled=false; }); | |
| } | |
| (function frInit(){ | |
| var op=$("frop"); if(op){ var t=frToken(); if(t) op.value=t; } | |
| var save=$("frsave"); if(save) save.addEventListener("click",function(){ try{ localStorage.setItem(FR_KEY,($("frop").value||"").trim()); save.textContent="saved"; setTimeout(function(){save.textContent="remember";},1200);}catch(e){} }); | |
| var ask=$("frask"); if(ask) ask.addEventListener("click",frAsk); | |
| var pr=$("frprompt"); if(pr) pr.addEventListener("keydown",function(e){ if((e.metaKey||e.ctrlKey)&&e.key==="Enter"){ e.preventDefault(); frAsk(); } }); | |
| })(); | |
| // ---------- tick ---------- | |
| function tick(){ | |
| Promise.all([ | |
| fetchJSON("/api/a11oy/v1/engine/status"), | |
| fetchJSON("/api/a11oy/v1/spend/state"), | |
| fetchJSON("/api/a11oy/v1/constellation"), | |
| fetchJSON("/api/a11oy/v1/spend/federated") | |
| ]).then(function(res){ | |
| var eng=res[0], sp=res[1], con=res[2], fed=res[3]; | |
| renderSpend(sp); | |
| renderFed(fed); | |
| renderKhipu(eng, sp, con, fed); | |
| var live=$("live"); live.textContent = (fed||sp)?"live":"degraded"; | |
| live.style.color = (fed||sp)?"#3af4c8":"#ff5470"; | |
| $("ts").textContent = new Date().toISOString().replace("T"," ").replace(/\..+/,"Z"); | |
| }); | |
| } | |
| tick(); | |
| setInterval(tick, 15000); | |
| })(); | |
| </script> | |
| </body> | |
| </html> | |