Spaces:
Running
Running
feat(frontier): NEW neuromorphic/spiking organ (LIF, MODELED) + honesty/sunset-domain fixes
Browse filesAdds /api/a11oy/v1/neuromorphic/spikes + neuromorphic 3D surface; repoints 6 user-facing a11oy.net refs to a-11-oy.com; ecosystem label LIVE->LIVE-STATIC.
spaces/sda/assets/sda-fabric.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* ============================================================================
|
| 2 |
+
* SZL SDA — sda-fabric.js
|
| 3 |
+
* Honest, vendored, 0-CDN runtime wiring:
|
| 4 |
+
* 1. Live read of a11oy /v1/compute-pool with captured SNAPSHOT fallback.
|
| 5 |
+
* 2. Optional live read of killinchu /mosaic feed -> COP score panel (LIVE label).
|
| 6 |
+
* 3. Mount the "ask the fabric — verify a receipt" widget.
|
| 7 |
+
* 4. Poll for an SDA validation figure and swap it in when present.
|
| 8 |
+
* NEVER fabricates live status / numbers. Honest degradation per doctrine v11.
|
| 9 |
+
* ==========================================================================*/
|
| 10 |
+
(function () {
|
| 11 |
+
'use strict';
|
| 12 |
+
var A11OY = 'https://a-11-oy.com';
|
| 13 |
+
var POOL = '/api/a11oy/v1/compute-pool';
|
| 14 |
+
var KILLINCHU = 'https://szlholdings-killinchu.hf.space'; // estate killinchu surface (HF Space host)
|
| 15 |
+
var MOSAIC_COP = '/api/killinchu/v1/mosaic/cop'; // fused COP + anomaly scores (PR #118)
|
| 16 |
+
var TIMEOUT = 9000;
|
| 17 |
+
|
| 18 |
+
function esc(s){ return String(s==null?'':s).replace(/[&<>"]/g,function(c){
|
| 19 |
+
return {'&':'&','<':'<','>':'>','"':'"'}[c]; }); }
|
| 20 |
+
|
| 21 |
+
function pull(url, timeoutMs){
|
| 22 |
+
var ctl = (typeof AbortController!=='undefined') ? new AbortController() : null;
|
| 23 |
+
var to = ctl ? setTimeout(function(){ try{ctl.abort();}catch(e){} }, timeoutMs||TIMEOUT) : null;
|
| 24 |
+
return fetch(url, { signal: ctl ? ctl.signal : undefined, cache:'no-store' })
|
| 25 |
+
.then(function(r){ if(to)clearTimeout(to); if(!r.ok) throw new Error('http '+r.status); return r.json(); })
|
| 26 |
+
.catch(function(e){ if(to)clearTimeout(to); throw e; });
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
/* ---- compute-pool node list ---- */
|
| 30 |
+
function nodeRow(n){
|
| 31 |
+
var up = !!n.reachable;
|
| 32 |
+
var sov = !!n.sovereign;
|
| 33 |
+
var kindCls = sov ? 'sov' : (n.kind && n.kind.indexOf('hosted')===0 ? 'hosted' : '');
|
| 34 |
+
var kindLabel = sov ? 'sovereign' : (n.kind || 'node');
|
| 35 |
+
var meta = (n.endpoint ? esc(n.endpoint) : '') +
|
| 36 |
+
(sov ? '' : (n.kind && n.kind.indexOf('hosted')===0 ? ' · hosted fallback — not compute you own' : ''));
|
| 37 |
+
return '<li class="node">'+
|
| 38 |
+
'<span class="ndot '+(up?'up':'down')+'" title="'+(up?'reachable':'unreachable')+'"></span>'+
|
| 39 |
+
'<span class="ninfo"><span class="nname">'+esc(n.name||'node')+
|
| 40 |
+
(up?'':' · <span style="color:#FF6B7A">unreachable</span>')+'</span>'+
|
| 41 |
+
'<span class="nmeta">'+meta+'</span></span>'+
|
| 42 |
+
'<span class="nkind '+kindCls+'">'+esc(kindLabel)+'</span>'+
|
| 43 |
+
'</li>';
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
function renderPool(d, isLive){
|
| 47 |
+
var list = document.getElementById('node-list');
|
| 48 |
+
var srcBadge = document.getElementById('pool-src');
|
| 49 |
+
var connBadge = document.getElementById('conn-badge');
|
| 50 |
+
var connLabel = document.getElementById('conn-label');
|
| 51 |
+
if(!list) return;
|
| 52 |
+
|
| 53 |
+
var nodes = (d && d.nodes) || [];
|
| 54 |
+
list.innerHTML = nodes.map(nodeRow).join('') || '<li class="node"><span class="ninfo"><span class="nname">No nodes reported.</span></span></li>';
|
| 55 |
+
|
| 56 |
+
var c = (d && d.counts) || {};
|
| 57 |
+
var summary = document.createElement('li');
|
| 58 |
+
summary.className = 'node'; summary.style.background='transparent'; summary.style.border='none';
|
| 59 |
+
summary.innerHTML = '<span class="ninfo"><span class="nmeta tabular">'+
|
| 60 |
+
(c.nodes_reachable!=null?esc(c.nodes_reachable):'?')+'/'+(c.nodes_total!=null?esc(c.nodes_total):'?')+' reachable · '+
|
| 61 |
+
(c.gpu_nodes_reachable!=null?esc(c.gpu_nodes_reachable):'?')+' GPU node(s) · sovereign_gpu_live='+
|
| 62 |
+
esc(String((c.sovereign_gpu_live!=null)?c.sovereign_gpu_live:'?'))+'</span></span>';
|
| 63 |
+
list.appendChild(summary);
|
| 64 |
+
|
| 65 |
+
if(isLive){
|
| 66 |
+
if(srcBadge){ srcBadge.textContent='LIVE'; srcBadge.classList.add('live'); }
|
| 67 |
+
if(connBadge){ connBadge.classList.remove('snapshot'); }
|
| 68 |
+
if(connLabel){ connLabel.textContent='FABRIC: LIVE'; }
|
| 69 |
+
} else {
|
| 70 |
+
if(srcBadge){ srcBadge.textContent='SNAPSHOT'; srcBadge.classList.remove('live'); }
|
| 71 |
+
if(connBadge){ connBadge.classList.add('snapshot'); }
|
| 72 |
+
if(connLabel){ connLabel.textContent='FABRIC: SNAPSHOT'; }
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
function loadPool(){
|
| 77 |
+
pull(A11OY+POOL)
|
| 78 |
+
.then(function(d){ renderPool(d, true); })
|
| 79 |
+
.catch(function(){
|
| 80 |
+
pull('./assets/snapshot-compute-pool.json', 4000)
|
| 81 |
+
.then(function(d){ renderPool(d, false); })
|
| 82 |
+
.catch(function(){
|
| 83 |
+
var list = document.getElementById('node-list');
|
| 84 |
+
var connLabel = document.getElementById('conn-label');
|
| 85 |
+
if(list) list.innerHTML = '<li class="node"><span class="ninfo"><span class="nname">Fabric unreachable.</span>'+
|
| 86 |
+
'<span class="nmeta">Live read and snapshot both unavailable — status not shown rather than faked.</span></span></li>';
|
| 87 |
+
if(connLabel) connLabel.textContent='FABRIC: UNREACHABLE';
|
| 88 |
+
});
|
| 89 |
+
});
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
/* ---- killinchu /mosaic COP feed (LIVE upgrade of the demo COP) ----
|
| 93 |
+
* If killinchu's /mosaic/cop is reachable, push real anomaly scores into the
|
| 94 |
+
* COP panel and re-label the COP badges LIVE. Otherwise the demo stands,
|
| 95 |
+
* clearly labelled. NEVER fakes a live read. */
|
| 96 |
+
function loadMosaicCOP(){
|
| 97 |
+
pull(KILLINCHU+MOSAIC_COP)
|
| 98 |
+
.then(function(d){
|
| 99 |
+
var tracks = (d && (d.tracks || d.cop || d.fused)) || [];
|
| 100 |
+
var norm = tracks.map(function(t){
|
| 101 |
+
return { id: t.track_id || t.id || ('T-'+(t.fused_track_id||'?')),
|
| 102 |
+
score: (t.anomaly_score!=null?t.anomaly_score:(t.score!=null?t.score:0)) };
|
| 103 |
+
}).filter(function(t){ return t.id; });
|
| 104 |
+
if (norm.length && window.SDA_COP && window.SDA_COP.setTracks){
|
| 105 |
+
window.SDA_COP.setTracks(norm);
|
| 106 |
+
markCopLive();
|
| 107 |
+
}
|
| 108 |
+
})
|
| 109 |
+
.catch(function(){ /* keep honest DEMO label; no fabrication */ });
|
| 110 |
+
}
|
| 111 |
+
function markCopLive(){
|
| 112 |
+
['cop-src','cop-feed-src'].forEach(function(id){
|
| 113 |
+
var b=document.getElementById(id); if(b){ b.textContent='LIVE · killinchu /mosaic'; b.classList.add('live'); }
|
| 114 |
+
});
|
| 115 |
+
var note=document.getElementById('cop-demo-note');
|
| 116 |
+
if(note){ note.innerHTML='<strong>Live read.</strong> The COP panel is showing real anomaly scores from the killinchu <code>/api/killinchu/v1/mosaic/cop</code> endpoint. Track motion remains an illustrative rendering; the scores and verdicts are live.'; }
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
/* ---- SDA validation figure swap-in (silent HEAD probe; no 404 noise) ---- */
|
| 120 |
+
function tryFigure(){
|
| 121 |
+
var img = document.getElementById('sda-fig-img');
|
| 122 |
+
if(!img) return;
|
| 123 |
+
fetch('assets/sda_validation.png', { method:'HEAD', cache:'no-store' })
|
| 124 |
+
.then(function(r){ if(!r.ok) throw new Error('absent'); return r; })
|
| 125 |
+
.then(function(){
|
| 126 |
+
img.onload = function(){
|
| 127 |
+
img.style.display='block';
|
| 128 |
+
var stage=document.querySelector('.cop-stage');
|
| 129 |
+
var note=document.getElementById('cop-demo-note');
|
| 130 |
+
var src=document.getElementById('cop-src');
|
| 131 |
+
if(stage) stage.parentNode && stage.parentNode.insertBefore(img, stage);
|
| 132 |
+
if(note){ note.innerHTML='<strong>SZL SDA validation figure.</strong> Produced by the khipu-sda-core validation harness.'; }
|
| 133 |
+
if(src){ src.textContent='SZL SDA — VALIDATION'; src.classList.add('live'); }
|
| 134 |
+
};
|
| 135 |
+
img.src='assets/sda_validation.png';
|
| 136 |
+
})
|
| 137 |
+
.catch(function(){ /* keep honest labelled demo COP */ });
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
function boot(){
|
| 141 |
+
loadPool();
|
| 142 |
+
loadMosaicCOP();
|
| 143 |
+
tryFigure();
|
| 144 |
+
if (window.SZLVerify && typeof window.SZLVerify.mount === 'function') {
|
| 145 |
+
try { window.SZLVerify.mount('#verify-mount', { base: A11OY }); } catch(e){}
|
| 146 |
+
}
|
| 147 |
+
}
|
| 148 |
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);
|
| 149 |
+
else boot();
|
| 150 |
+
})();
|
spaces/sda/assets/szl_verify_widget.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* ============================================================================
|
| 2 |
+
* SZL "ask the fabric" — verify-a-claim widget (vendored, self-contained)
|
| 3 |
+
* ----------------------------------------------------------------------------
|
| 4 |
+
* 0 runtime CDN · system fonts only · AbortController · honest fallback.
|
| 5 |
+
* Calls the REAL a11oy verify endpoint and renders its REAL honest verdict.
|
| 6 |
+
* POST {base}/api/a11oy/v1/verify body = a receipt / DSSE envelope / in-toto stmt
|
| 7 |
+
* GET {base}/api/a11oy/v1/verify?url=<public receipt url>
|
| 8 |
+
*
|
| 9 |
+
* Doctrine v11: this widget NEVER fabricates a verdict. It shows exactly what
|
| 10 |
+
* the server returns (verdict: VERIFIED | STRUCTURAL-ONLY | FAILED | UNRECOGNISED).
|
| 11 |
+
* "STRUCTURAL-ONLY" is shown as advisory, NOT green. Network/timeout/429 degrade
|
| 12 |
+
* to an honest "unreachable / rate-limited" state — never to a false green.
|
| 13 |
+
*
|
| 14 |
+
* Attribution (clean-room rebuild of permissive ideas — see dev7 report):
|
| 15 |
+
* - Tool-call / receipt trace UI pattern inspired by smolagents (Apache-2.0,
|
| 16 |
+
* huggingface/smolagents) and assistant-ui (MIT). Rebuilt SZL-native; no code copied.
|
| 17 |
+
* - AbortController fetch contract reuses anatomy V8 (SZL own prior art).
|
| 18 |
+
* ==========================================================================*/
|
| 19 |
+
(function (global) {
|
| 20 |
+
'use strict';
|
| 21 |
+
|
| 22 |
+
var DEFAULT_BASE = 'https://a-11-oy.com'; // same fabric the estate already talks to
|
| 23 |
+
var TIMEOUT_MS = 12000;
|
| 24 |
+
var SAMPLE = {
|
| 25 |
+
_type: 'https://in-toto.io/Statement/v1',
|
| 26 |
+
subject: [{ name: 'szl-lake/homflyreceipt_gate',
|
| 27 |
+
digest: { sha256: '0a2d153d81c00688b576e5a012ae6117465639807456d1bb72eb590cac3b1e9d' } }],
|
| 28 |
+
predicateType: 'https://szlholdings.com/attestations/innovation/v1',
|
| 29 |
+
predicate: { note: 'paste your own receipt JSON here, or a public receipt URL' }
|
| 30 |
+
};
|
| 31 |
+
|
| 32 |
+
function esc(s){ return String(s==null?'':s).replace(/[&<>"]/g,function(c){
|
| 33 |
+
return {'&':'&','<':'<','>':'>','"':'"'}[c]; }); }
|
| 34 |
+
|
| 35 |
+
/* honest fetch contract: AbortController + try/catch. NEVER throws. ----- */
|
| 36 |
+
function pull(url, opts, timeoutMs){
|
| 37 |
+
var ctl = (typeof AbortController!=='undefined') ? new AbortController() : null;
|
| 38 |
+
var to = ctl ? setTimeout(function(){ try{ctl.abort();}catch(e){} }, timeoutMs||TIMEOUT_MS) : null;
|
| 39 |
+
opts = opts || {};
|
| 40 |
+
opts.signal = ctl ? ctl.signal : undefined;
|
| 41 |
+
opts.cache = 'no-store';
|
| 42 |
+
opts.mode = 'cors';
|
| 43 |
+
return fetch(url, opts).then(function(r){
|
| 44 |
+
if(to) clearTimeout(to);
|
| 45 |
+
var status = r.status;
|
| 46 |
+
return r.json().then(function(data){ return {ok:r.ok, status:status, data:data}; },
|
| 47 |
+
function(){ return {ok:false, status:status, data:null}; });
|
| 48 |
+
}).catch(function(e){
|
| 49 |
+
if(to) clearTimeout(to);
|
| 50 |
+
var aborted = e && (e.name==='AbortError');
|
| 51 |
+
return {ok:false, status:0, data:null, err:String(e&&e.message||e), aborted:aborted};
|
| 52 |
+
});
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
/* map an HONEST verdict string -> {label, cls, advisory} ---------------- */
|
| 56 |
+
function verdictView(v){
|
| 57 |
+
var s = String(v||'').toUpperCase();
|
| 58 |
+
if(s==='VERIFIED') return {label:'VERIFIED', cls:'ok', advisory:false};
|
| 59 |
+
if(s==='STRUCTURAL-ONLY') return {label:'STRUCTURAL-ONLY', cls:'warn', advisory:true};
|
| 60 |
+
if(s==='FAILED') return {label:'FAILED', cls:'fail', advisory:false};
|
| 61 |
+
if(s==='UNRECOGNISED') return {label:'UNRECOGNISED', cls:'muted',advisory:false};
|
| 62 |
+
return {label: s||'—', cls:'muted', advisory:false};
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
function renderChecks(checks){
|
| 66 |
+
if(!Array.isArray(checks) || !checks.length) return '';
|
| 67 |
+
var rows = checks.map(function(c){
|
| 68 |
+
var st = String(c.status||'').toLowerCase();
|
| 69 |
+
var cls = st==='pass' ? 'ok' : (st==='fail' ? 'fail' : 'muted');
|
| 70 |
+
return '<li class="szlv-chk"><span class="szlv-pill '+cls+'">'+esc(c.status||'?')+'</span>'+
|
| 71 |
+
'<code>'+esc(c.name||'check')+'</code>'+
|
| 72 |
+
(c.detail ? '<span class="szlv-det">'+esc(c.detail)+'</span>' : '')+'</li>';
|
| 73 |
+
}).join('');
|
| 74 |
+
return '<ul class="szlv-checks">'+rows+'</ul>';
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
function renderResult(res){
|
| 78 |
+
// res is the {ok,status,data,err,aborted} envelope from pull()
|
| 79 |
+
if(res.status===429){
|
| 80 |
+
return '<div class="szlv-state fail">rate-limited · the fabric caps at 60/min per IP. '+
|
| 81 |
+
'This is honest backpressure, not a failure of your receipt. Try again shortly.</div>';
|
| 82 |
+
}
|
| 83 |
+
if(!res.ok || !res.data){
|
| 84 |
+
var why = res.aborted ? 'timed out' : (res.status ? ('HTTP '+res.status) : 'unreachable');
|
| 85 |
+
return '<div class="szlv-state muted">offline · fabric '+esc(why)+
|
| 86 |
+
'. No verdict shown — the widget never invents a green. '+
|
| 87 |
+
'Re-run the checks yourself per docs/developers/VERIFY.md.</div>';
|
| 88 |
+
}
|
| 89 |
+
var d = res.data;
|
| 90 |
+
var vv = verdictView(d.verdict);
|
| 91 |
+
var head = '<div class="szlv-verdict '+vv.cls+'">'+
|
| 92 |
+
'<span class="szlv-dot"></span><b>'+esc(vv.label)+'</b>'+
|
| 93 |
+
(vv.advisory ? '<span class="szlv-adv">advisory · not a cryptographic green</span>' : '')+
|
| 94 |
+
'</div>';
|
| 95 |
+
var detail = d.detail ? '<p class="szlv-detail">'+esc(d.detail)+'</p>' : '';
|
| 96 |
+
var kinds = (Array.isArray(d.kinds)&&d.kinds.length)
|
| 97 |
+
? '<p class="szlv-kinds">recognised as: '+d.kinds.map(esc).join(', ')+'</p>' : '';
|
| 98 |
+
var checks = renderChecks(d.checks);
|
| 99 |
+
var foot = '<p class="szlv-foot">engine '+esc(d.engine_version||'?')+
|
| 100 |
+
' · doctrine '+esc((d.doctrine&&d.doctrine.version)||'v11')+
|
| 101 |
+
' · Λ='+esc((d.doctrine&&d.doctrine.lambda)||'Conjecture 1')+
|
| 102 |
+
(d.verified_at ? ' · '+esc(d.verified_at) : '')+
|
| 103 |
+
'<br><span class="szlv-trust">No trust in the server is required — re-verify with cosign / rekor-cli / lake build.</span></p>';
|
| 104 |
+
return head+detail+kinds+checks+foot;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
var CSS = [
|
| 108 |
+
'.szlv{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;',
|
| 109 |
+
'color:#cdccca;background:#1c1b19;border:1px solid #393836;border-radius:10px;padding:16px;max-width:640px}',
|
| 110 |
+
'.szlv h3{font-size:15px;margin:0 0 4px;font-weight:600;letter-spacing:.2px}',
|
| 111 |
+
'.szlv .szlv-sub{font-size:12px;color:#797876;margin:0 0 12px}',
|
| 112 |
+
'.szlv textarea{width:100%;min-height:120px;box-sizing:border-box;background:#171614;color:#cdccca;',
|
| 113 |
+
'border:1px solid #393836;border-radius:8px;padding:10px;font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;resize:vertical}',
|
| 114 |
+
'.szlv-row{display:flex;gap:8px;flex-wrap:wrap;margin:10px 0}',
|
| 115 |
+
'.szlv input[type=text]{flex:1;min-width:200px;background:#171614;color:#cdccca;border:1px solid #393836;border-radius:8px;padding:8px 10px;font-size:12px}',
|
| 116 |
+
'.szlv button{background:#01696f;color:#fff;border:0;border-radius:8px;padding:9px 16px;font-size:13px;font-weight:600;cursor:pointer}',
|
| 117 |
+
'.szlv button:hover{background:#0c4e54}.szlv button:disabled{opacity:.5;cursor:wait}',
|
| 118 |
+
'.szlv button.ghost{background:transparent;color:#4f98a3;border:1px solid #393836}',
|
| 119 |
+
'.szlv-out{margin-top:12px;font-size:13px;min-height:24px}',
|
| 120 |
+
'.szlv-load{color:#797876;font-size:12px}',
|
| 121 |
+
'.szlv-verdict{display:flex;align-items:center;gap:8px;font-size:15px;padding:8px 10px;border-radius:8px;border:1px solid #393836}',
|
| 122 |
+
'.szlv-verdict .szlv-dot{width:9px;height:9px;border-radius:50%}',
|
| 123 |
+
'.szlv-verdict.ok .szlv-dot{background:#6daa45}.szlv-verdict.ok{border-color:#3a5a26}',
|
| 124 |
+
'.szlv-verdict.warn .szlv-dot{background:#e8af34}.szlv-verdict.warn{border-color:#6b5418}',
|
| 125 |
+
'.szlv-verdict.fail .szlv-dot{background:#d163a7}.szlv-verdict.fail{border-color:#7a2c5a}',
|
| 126 |
+
'.szlv-verdict.muted .szlv-dot{background:#797876}',
|
| 127 |
+
'.szlv-adv{font-size:11px;color:#e8af34;font-weight:400;margin-left:auto}',
|
| 128 |
+
'.szlv-detail{font-size:12px;color:#a9a8a5;margin:8px 0}',
|
| 129 |
+
'.szlv-kinds{font-size:11px;color:#797876;margin:4px 0}',
|
| 130 |
+
'.szlv-checks{list-style:none;margin:8px 0 0;padding:0;display:flex;flex-direction:column;gap:4px}',
|
| 131 |
+
'.szlv-chk{display:flex;align-items:center;gap:8px;font-size:12px;flex-wrap:wrap}',
|
| 132 |
+
'.szlv-pill{font-size:10px;text-transform:uppercase;letter-spacing:.4px;padding:2px 6px;border-radius:4px;font-weight:700}',
|
| 133 |
+
'.szlv-pill.ok{background:rgba(109,170,69,.18);color:#6daa45}',
|
| 134 |
+
'.szlv-pill.fail{background:rgba(209,99,167,.18);color:#d163a7}',
|
| 135 |
+
'.szlv-pill.muted{background:#2a2927;color:#797876}',
|
| 136 |
+
'.szlv-chk code{color:#cdccca}.szlv-det{color:#797876;font-size:11px}',
|
| 137 |
+
'.szlv-foot{font-size:10px;color:#5a5957;margin:10px 0 0;line-height:1.5}',
|
| 138 |
+
'.szlv-trust{color:#797876}',
|
| 139 |
+
'.szlv-state{font-size:12px;padding:8px 10px;border-radius:8px}',
|
| 140 |
+
'.szlv-state.fail{background:rgba(209,99,167,.10);color:#d163a7}',
|
| 141 |
+
'.szlv-state.muted{background:#211f1d;color:#a9a8a5}',
|
| 142 |
+
/* DEV B mobile refinement: 12px type floor + 44px touch targets (additive, no logic change) */
|
| 143 |
+
'@media (max-width:768px){',
|
| 144 |
+
'.szlv-adv,.szlv-kinds,.szlv-chk .szlv-det,.szlv-foot,.szlv-pill{font-size:12px}',
|
| 145 |
+
'.szlv button{min-height:44px;padding:11px 18px;font-size:14px}',
|
| 146 |
+
'.szlv input[type=text]{min-height:44px;font-size:13px}',
|
| 147 |
+
'.szlv textarea{font-size:13px}',
|
| 148 |
+
'.szlv-sub,.szlv-load,.szlv-detail,.szlv-state{font-size:13px}',
|
| 149 |
+
'}'].join('');
|
| 150 |
+
|
| 151 |
+
function injectCSS(){
|
| 152 |
+
if(document.getElementById('szlv-css')) return;
|
| 153 |
+
var st = document.createElement('style'); st.id='szlv-css'; st.textContent = CSS;
|
| 154 |
+
document.head.appendChild(st);
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
/* Public mount: SZLVerify.mount('#id', {base}) ------------------------- */
|
| 158 |
+
function mount(target, opts){
|
| 159 |
+
opts = opts || {};
|
| 160 |
+
var base = (opts.base || DEFAULT_BASE).replace(/\/+$/,'');
|
| 161 |
+
var host = (typeof target==='string') ? document.querySelector(target) : target;
|
| 162 |
+
if(!host) return null;
|
| 163 |
+
injectCSS();
|
| 164 |
+
host.classList.add('szlv');
|
| 165 |
+
host.innerHTML =
|
| 166 |
+
'<h3>ask the fabric — verify a receipt</h3>'+
|
| 167 |
+
'<p class="szlv-sub">Paste a Khipu receipt / DSSE envelope / in-toto statement, '+
|
| 168 |
+
'or fetch a public receipt by URL. Verdicts are the fabric\u2019s real, honest output '+
|
| 169 |
+
'(unsigned \u2192 STRUCTURAL-ONLY, never a false green).</p>'+
|
| 170 |
+
'<textarea class="szlv-ta" spellcheck="false"></textarea>'+
|
| 171 |
+
'<div class="szlv-row">'+
|
| 172 |
+
'<input type="text" class="szlv-url" placeholder="\u2026or a public receipt URL (https://\u2026/receipt.json)">'+
|
| 173 |
+
'</div>'+
|
| 174 |
+
'<div class="szlv-row">'+
|
| 175 |
+
'<button class="szlv-go" type="button">Verify</button>'+
|
| 176 |
+
'<button class="szlv-sample ghost" type="button">Load sample receipt</button>'+
|
| 177 |
+
'</div>'+
|
| 178 |
+
'<div class="szlv-out" aria-live="polite"></div>';
|
| 179 |
+
|
| 180 |
+
var ta = host.querySelector('.szlv-ta');
|
| 181 |
+
var url = host.querySelector('.szlv-url');
|
| 182 |
+
var out = host.querySelector('.szlv-out');
|
| 183 |
+
var go = host.querySelector('.szlv-go');
|
| 184 |
+
var smp = host.querySelector('.szlv-sample');
|
| 185 |
+
|
| 186 |
+
smp.addEventListener('click', function(){ ta.value = JSON.stringify(SAMPLE, null, 2); url.value=''; });
|
| 187 |
+
|
| 188 |
+
go.addEventListener('click', function(){
|
| 189 |
+
go.disabled = true;
|
| 190 |
+
out.innerHTML = '<span class="szlv-load">calling <code>'+esc(base)+'/api/a11oy/v1/verify</code>\u2026</span>';
|
| 191 |
+
var p, u = url.value.trim(), body = ta.value.trim();
|
| 192 |
+
if(u){
|
| 193 |
+
p = pull(base+'/api/a11oy/v1/verify?url='+encodeURIComponent(u), {method:'GET'});
|
| 194 |
+
} else if(body){
|
| 195 |
+
var parsed = null;
|
| 196 |
+
try{ parsed = JSON.parse(body); }catch(e){
|
| 197 |
+
out.innerHTML = '<div class="szlv-state muted">input is not valid JSON — paste a receipt object or use a URL.</div>';
|
| 198 |
+
go.disabled = false; return;
|
| 199 |
+
}
|
| 200 |
+
p = pull(base+'/api/a11oy/v1/verify', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify(parsed)});
|
| 201 |
+
} else {
|
| 202 |
+
out.innerHTML = '<div class="szlv-state muted">paste a receipt JSON, or enter a public receipt URL.</div>';
|
| 203 |
+
go.disabled = false; return;
|
| 204 |
+
}
|
| 205 |
+
p.then(function(res){ out.innerHTML = renderResult(res); go.disabled = false; });
|
| 206 |
+
});
|
| 207 |
+
|
| 208 |
+
return { reload:function(){}, base:base };
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
var api = { mount: mount, pull: pull, _sample: SAMPLE, version: '1.0.0' };
|
| 212 |
+
if (typeof module!=='undefined' && module.exports) module.exports = api;
|
| 213 |
+
global.SZLVerify = api;
|
| 214 |
+
})(typeof window!=='undefined' ? window : this);
|