Spaces:
Running
Running
deploy(hf): sync szl-holdings/a11oy@main derived COPY set
Browse filesReusable Dockerfile-COPY-derived deploy from szl-holdings/a11oy main.
Files: 1043 Pruned: 0
Derived from Dockerfile COPY sources (NO hand-maintained allowlist).
Signed-off-by: SZL Holdings <noreply@szlholdings.ai>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- pages/sovereign.html +58 -11
pages/sovereign.html
CHANGED
|
@@ -93,6 +93,17 @@
|
|
| 93 |
@keyframes sway{0%,100%{transform:translateX(-3px) rotate(-.5deg)}50%{transform:translateX(3px) rotate(.5deg)}}
|
| 94 |
@media (max-width:760px){.strip,.lamps{grid-template-columns:repeat(2,1fr)}.brand h1{font-size:22px;letter-spacing:.3em}}
|
| 95 |
@media (prefers-reduced-motion:reduce){*{animation:none!important}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
</style>
|
| 97 |
</head>
|
| 98 |
<body>
|
|
@@ -105,8 +116,15 @@
|
|
| 105 |
<div class="clock"><span><span class="dot"></span><span id="live">live</span></span><br/><span id="ts">—</span></div>
|
| 106 |
</header>
|
| 107 |
|
|
|
|
| 108 |
<section class="strip" id="strip"></section>
|
| 109 |
<section class="lamps" id="lamps"></section>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
|
| 111 |
<section class="khipu"><div id="khipu"></div></section>
|
| 112 |
<div class="lgd">
|
|
@@ -129,6 +147,7 @@
|
|
| 129 |
var $=function(id){return document.getElementById(id)};
|
| 130 |
function esc(s){return String(s==null?"":s).replace(/[&<>"]/g,function(c){return {"&":"&","<":"<",">":">",'"':"""}[c]})}
|
| 131 |
function money(x){ if(x==null||isNaN(x)) return null; return "$"+Number(x).toLocaleString(undefined,{minimumFractionDigits:2,maximumFractionDigits:2}); }
|
|
|
|
| 132 |
function fetchJSON(url){
|
| 133 |
return fetch(url,{headers:{accept:"application/json"},cache:"no-store"})
|
| 134 |
.then(function(r){ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
|
@@ -178,6 +197,30 @@
|
|
| 178 |
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>';
|
| 179 |
}
|
| 180 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
// ---------- the khipu (organs + spend sources + estate) ----------
|
| 182 |
var VW=1200, VH=460, TOP=78, BASE=430;
|
| 183 |
function pendant(x, len, knots, cls, label, swayCls){
|
|
@@ -202,7 +245,7 @@
|
|
| 202 |
}
|
| 203 |
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; }
|
| 204 |
|
| 205 |
-
function renderKhipu(eng, sp, con){
|
| 206 |
var svg='<svg viewBox="0 0 '+VW+' '+VH+'" preserveAspectRatio="xMidYMid meet" role="img" aria-label="Sovereign khipu">';
|
| 207 |
svg += '<line x1="48" y1="'+TOP+'" x2="'+(VW-48)+'" y2="'+TOP+'" stroke="#173049" stroke-width="3" stroke-linecap="round"/>';
|
| 208 |
// section 1: VITALS (organs)
|
|
@@ -217,19 +260,21 @@
|
|
| 217 |
if(!names.length) svg += emptyCord(250,"no organs reported","sway0");
|
| 218 |
} else svg += emptyCord(250, eng?"no organ data":"engine unreachable","sway0");
|
| 219 |
|
| 220 |
-
// section 2: SPEND (ledger
|
| 221 |
svg += sectionLabel(600,"SPEND");
|
| 222 |
-
|
| 223 |
-
|
|
|
|
| 224 |
if(tail.length){
|
| 225 |
var total=tail.reduce(function(a,e){return a+(+e.amount_usd||0)},0)||1;
|
| 226 |
var xs2=spread(480,720,tail.length);
|
| 227 |
for(var j=0;j<tail.length;j++){
|
| 228 |
var amt=+tail[j].amount_usd||0; var kk=Math.max(1,Math.min(9,Math.round(1+8*(amt/total))));
|
| 229 |
-
svg += pendantAmber(xs2[j], BASE-((j%2)*30), kk, (tail[j].source||"?").slice(0,8),
|
| 230 |
}
|
| 231 |
} else {
|
| 232 |
-
|
|
|
|
| 233 |
}
|
| 234 |
} else svg += emptyCord(600,"spend unreachable","sway1");
|
| 235 |
|
|
@@ -271,13 +316,15 @@
|
|
| 271 |
Promise.all([
|
| 272 |
fetchJSON("/api/a11oy/v1/engine/status"),
|
| 273 |
fetchJSON("/api/a11oy/v1/spend/state"),
|
| 274 |
-
fetchJSON("/api/a11oy/v1/constellation")
|
|
|
|
| 275 |
]).then(function(res){
|
| 276 |
-
var eng=res[0], sp=res[1], con=res[2];
|
| 277 |
renderSpend(sp);
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
live.
|
|
|
|
| 281 |
$("ts").textContent = new Date().toISOString().replace("T"," ").replace(/\..+/,"Z");
|
| 282 |
});
|
| 283 |
}
|
|
|
|
| 93 |
@keyframes sway{0%,100%{transform:translateX(-3px) rotate(-.5deg)}50%{transform:translateX(3px) rotate(.5deg)}}
|
| 94 |
@media (max-width:760px){.strip,.lamps{grid-template-columns:repeat(2,1fr)}.brand h1{font-size:22px;letter-spacing:.3em}}
|
| 95 |
@media (prefers-reduced-motion:reduce){*{animation:none!important}}
|
| 96 |
+
/* federated (authoritative box) spend panel */
|
| 97 |
+
.localttl{font-family:var(--mono);font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--mute);margin:2px 2px 8px}
|
| 98 |
+
.fedwrap{margin:6px 0 18px;padding:14px 15px 15px;border:1px solid var(--teal-dim);border-radius:14px;
|
| 99 |
+
background:linear-gradient(180deg,rgba(58,244,200,.05),rgba(8,12,20,.5))}
|
| 100 |
+
.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}
|
| 101 |
+
.fedttl .badge{font-size:9.5px;letter-spacing:.16em;background:var(--teal);color:#04241d;padding:3px 8px;border-radius:20px;font-weight:700}
|
| 102 |
+
.fedttl .fedsrc{color:var(--mute);font-size:10.5px;letter-spacing:.02em}
|
| 103 |
+
.fednote{color:var(--mute);font-size:10.5px;margin:0 0 12px;line-height:1.5}
|
| 104 |
+
.fedwrap .strip{margin-bottom:12px}
|
| 105 |
+
.fedwrap .lamps{margin-bottom:0}
|
| 106 |
+
|
| 107 |
</style>
|
| 108 |
</head>
|
| 109 |
<body>
|
|
|
|
| 116 |
<div class="clock"><span><span class="dot"></span><span id="live">live</span></span><br/><span id="ts">—</span></div>
|
| 117 |
</header>
|
| 118 |
|
| 119 |
+
<div class="localttl">a11oy module ledger — local / advisory (in-container)</div>
|
| 120 |
<section class="strip" id="strip"></section>
|
| 121 |
<section class="lamps" id="lamps"></section>
|
| 122 |
+
<section class="fedwrap">
|
| 123 |
+
<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>
|
| 124 |
+
<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>
|
| 125 |
+
<div class="strip" id="fedstrip"></div>
|
| 126 |
+
<div class="lamps" id="fedlamps"></div>
|
| 127 |
+
</section>
|
| 128 |
|
| 129 |
<section class="khipu"><div id="khipu"></div></section>
|
| 130 |
<div class="lgd">
|
|
|
|
| 147 |
var $=function(id){return document.getElementById(id)};
|
| 148 |
function esc(s){return String(s==null?"":s).replace(/[&<>"]/g,function(c){return {"&":"&","<":"<",">":">",'"':"""}[c]})}
|
| 149 |
function money(x){ if(x==null||isNaN(x)) return null; return "$"+Number(x).toLocaleString(undefined,{minimumFractionDigits:2,maximumFractionDigits:2}); }
|
| 150 |
+
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}); }
|
| 151 |
function fetchJSON(url){
|
| 152 |
return fetch(url,{headers:{accept:"application/json"},cache:"no-store"})
|
| 153 |
.then(function(r){ if(!r.ok) throw new Error("HTTP "+r.status); return r.json(); })
|
|
|
|
| 197 |
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>';
|
| 198 |
}
|
| 199 |
|
| 200 |
+
// ---------- federated (authoritative box-router) spend panel ----------
|
| 201 |
+
function renderFed(fs){
|
| 202 |
+
var strip=$("fedstrip"), lamps=$("fedlamps"), src=$("fedsrc");
|
| 203 |
+
if(!strip) return;
|
| 204 |
+
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=""; }
|
| 205 |
+
if(!fs){ down("unreachable","the federation feed did not answer","red"); return; }
|
| 206 |
+
if(fs.state==="not_configured"){ down("not configured","set SZL_ROUTER_SPEND_URL to federate the box ledger",""); return; }
|
| 207 |
+
if(fs.state!=="live" || fs.reachable!==true){ down("unreachable","box router did not answer (http "+(fs.http_status!=null?fs.http_status:"?")+")","red"); return; }
|
| 208 |
+
var cap=fs.cap_usd, spent=fs.spent_usd, rem=fs.remaining_usd, pct=fs.pct_used;
|
| 209 |
+
var overspend=(rem!=null && rem<=0);
|
| 210 |
+
strip.innerHTML =
|
| 211 |
+
card("Hard cap", money6(cap), "ceiling", "") +
|
| 212 |
+
card("Spent (real, paid)", money6(spent)||"—", (fs.entries!=null?fs.entries+" ledger entries":""), "amber") +
|
| 213 |
+
card("Remaining", money6(rem)||"—", "", overspend?"red":"") +
|
| 214 |
+
card("Utilisation", (pct!=null? pct+"% ":"—"), bar(pct), pct!=null&&pct>=90?"red":(pct!=null&&pct>=60?"amber":""));
|
| 215 |
+
lamps.innerHTML =
|
| 216 |
+
lamp("Spend cap", fs.armed===true?"ARMED":"\u2014", fs.armed===true?"ok":"na") +
|
| 217 |
+
lamp("Status", fs.tripped===true?"TRIPPED":(fs.tripped===false?"CLEAR":"\u2014"), fs.tripped===true?"bad":(fs.tripped===false?"ok":"na")) +
|
| 218 |
+
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")) +
|
| 219 |
+
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"));
|
| 220 |
+
var when = fs.upstream_generated || fs.checked_at || "";
|
| 221 |
+
src.textContent = (when? "\u00b7 as of "+when : "") + (fs.cache? " ("+fs.cache+")":"");
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
// ---------- the khipu (organs + spend sources + estate) ----------
|
| 225 |
var VW=1200, VH=460, TOP=78, BASE=430;
|
| 226 |
function pendant(x, len, knots, cls, label, swayCls){
|
|
|
|
| 245 |
}
|
| 246 |
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; }
|
| 247 |
|
| 248 |
+
function renderKhipu(eng, sp, con, fed){
|
| 249 |
var svg='<svg viewBox="0 0 '+VW+' '+VH+'" preserveAspectRatio="xMidYMid meet" role="img" aria-label="Sovereign khipu">';
|
| 250 |
svg += '<line x1="48" y1="'+TOP+'" x2="'+(VW-48)+'" y2="'+TOP+'" stroke="#173049" stroke-width="3" stroke-linecap="round"/>';
|
| 251 |
// section 1: VITALS (organs)
|
|
|
|
| 260 |
if(!names.length) svg += emptyCord(250,"no organs reported","sway0");
|
| 261 |
} else svg += emptyCord(250, eng?"no organ data":"engine unreachable","sway0");
|
| 262 |
|
| 263 |
+
// section 2: SPEND (real box-router ledger; falls back to local advisory)
|
| 264 |
svg += sectionLabel(600,"SPEND");
|
| 265 |
+
var spendSrc = (fed && fed.state==="live" && fed.reachable===true) ? fed : sp;
|
| 266 |
+
if(spendSrc){
|
| 267 |
+
var tail=(spendSrc.tail&&spendSrc.tail.length)?spendSrc.tail.slice(-6):[];
|
| 268 |
if(tail.length){
|
| 269 |
var total=tail.reduce(function(a,e){return a+(+e.amount_usd||0)},0)||1;
|
| 270 |
var xs2=spread(480,720,tail.length);
|
| 271 |
for(var j=0;j<tail.length;j++){
|
| 272 |
var amt=+tail[j].amount_usd||0; var kk=Math.max(1,Math.min(9,Math.round(1+8*(amt/total))));
|
| 273 |
+
svg += pendantAmber(xs2[j], BASE-((j%2)*30), kk, (tail[j].source||"?").slice(0,8), money6(amt)||"", "sway1");
|
| 274 |
}
|
| 275 |
} else {
|
| 276 |
+
var sv=(spendSrc.spent_usd!=null?spendSrc.spent_usd:null);
|
| 277 |
+
svg += emptyCord(600, (sv? money6(sv):"$0.00")+" spent","sway1");
|
| 278 |
}
|
| 279 |
} else svg += emptyCord(600,"spend unreachable","sway1");
|
| 280 |
|
|
|
|
| 316 |
Promise.all([
|
| 317 |
fetchJSON("/api/a11oy/v1/engine/status"),
|
| 318 |
fetchJSON("/api/a11oy/v1/spend/state"),
|
| 319 |
+
fetchJSON("/api/a11oy/v1/constellation"),
|
| 320 |
+
fetchJSON("/api/a11oy/v1/spend/federated")
|
| 321 |
]).then(function(res){
|
| 322 |
+
var eng=res[0], sp=res[1], con=res[2], fed=res[3];
|
| 323 |
renderSpend(sp);
|
| 324 |
+
renderFed(fed);
|
| 325 |
+
renderKhipu(eng, sp, con, fed);
|
| 326 |
+
var live=$("live"); live.textContent = (fed||sp)?"live":"degraded";
|
| 327 |
+
live.style.color = (fed||sp)?"#3af4c8":"#ff5470";
|
| 328 |
$("ts").textContent = new Date().toISOString().replace("T"," ").replace(/\..+/,"Z");
|
| 329 |
});
|
| 330 |
}
|