betterwithage commited on
Commit
e7c7693
·
verified ·
1 Parent(s): 53a82fc

chore(sync): mirror front-door files to Space (hf-sync)

Browse files

Automated front-door sync from szl-holdings/a11oy main via hf-sync.
Added/updated: cathedral.html, cathedral_genius.html, console/docs.html, console/index.html, console/pricing.html, console/throne-room.html, console/throne-room.js, live_wires.html, pages/api-keys.html, pages/audit.html, pages/ayni.html, pages/brain-dual.html, pages/brain-jack.html, pages/brain.html, pages/chaski.html, pages/codex-kernel.html, pages/company.html, pages/compliance.html, pages/console.html, pages/counter-uas.html, pages/cued-engagement.html, pages/docs.html, pages/energy-ops.html, pages/evidence.html, pages/fabric.html, pages/gap-report.html, pages/harvest.html, pages/hatun-mcp.html, pages/hub.html, pages/integrations.html, pages/landing.html, pages/mesh.html, pages/observability.html, pages/operator_organ.html, pages/pinn.html, pages/pnt.html, pages/pricing.html, pages/run-all.html, pages/sdk.html, pages/security.html, pages/status.html, pages/substrate.html, pages/superpowers.html, pages/throne-room.html, pages/throne-room.js, pages/uds.html, pages/upgrades.html, pages/wallpa.html, pages/warhacker.html, pages/wasi-rikuq.html, pages/wires.html, static/a11oy_cathedral.js, static/cathedral_app.js, static/shared/szl_codename_sanitizer.js, static/shared/szl_holo3d.js, static/shared/szl_label_engine.js, static/shared/szl_receipt_cosign.js, web/agent-loop.html, web/agentic-gpu.html, web/autoreview.html, web/console.html, web/console_index.html, web/constitution.html, web/defense-readiness.html, web/dns.html, web/elite_console.html, web/energy-holographic.html, web/energy.html, web/estate-hologram.html, web/fleet-c2.html, web/formulas.html, web/governance.html, web/holo.html, web/hologram.html, web/immune.html, web/index.html, web/living-anatomy.html, web/materials.html, web/nemo.html, web/operator.html, web/quant.html, web/restraint-bench.html, web/restraint.html, web/sda.html, web/signature-is-not-proof.html, web/v4_fleet_panel.html
Deleted (gone from GitHub main): (none)

Keeps the served front-door (pages/*.html, console/*.html) identical
to GitHub main so an HF factory rebuild never drops a GitHub edit or
keeps serving a page that was deleted on GitHub.

Files changed (1) hide show
  1. pages/warhacker.html +216 -5
pages/warhacker.html CHANGED
@@ -253,6 +253,45 @@
253
  .proof-card .pc-d{font-size:12.5px;line-height:1.6;color:var(--paragraph);margin:0;}
254
  .proof-card .pc-d code{color:var(--gold);font-family:var(--mono);font-size:11px;}
255
  .proof-card .pc-r{display:flex;gap:.6rem;flex-wrap:wrap;}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  </style>
257
  </head>
258
  <body>
@@ -276,16 +315,19 @@
276
  <section class="hero">
277
  <div class="grid-bg"></div>
278
  <div class="hero-inner">
279
- <span class="eyebrow"><span class="eyebrow-dot"></span><span class="eyebrow-text">WarHacker · governed mission compute · live on this Space</span></span>
280
  <h1 class="headline">Code is action.<br/><span class="accent">Govern it, or it governs you.</span></h1>
281
  <p class="support">a11oy is the <b style="color:var(--cream)">governed substrate</b> beneath the mission:
282
  every autonomous decision is checked against authorized limits, <span style="color:var(--live)">ALLOWED</span>
283
  or <span style="color:var(--err)">BLOCKED</span> at the exact line it crosses, and sealed into a signed,
284
- tamper-evident receipt you can re-verify on screen. Army counter-UAS, Navy maritime, multi-domain joint
285
- compute &mdash; one governed core, every domain.</p>
 
 
286
  <button class="runall" id="runAll">▶ Run all five mission surfaces</button>
287
  <div class="stats">
288
  <div class="stat"><div class="k">Surfaces live</div><div class="v" id="stLive">0 / 5</div></div>
 
289
  <div class="stat"><div class="k">Records signed</div><div class="v teal" id="stSigned">0</div></div>
290
  <div class="stat"><div class="k">Re-verified</div><div class="v" id="stVerified">—</div></div>
291
  <div class="stat"><div class="k">Registry</div><div class="v teal" id="stReg">—</div></div>
@@ -505,6 +547,32 @@ SAT-B 35786 3.07 0.0'></textarea>
505
 
506
  </div>
507
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
508
  <div class="honest">
509
  <div class="honest-box" id="honestBox">
510
  <b>What is real here (doctrine v11 · honest labels only).</b> Every surface above runs live in this container.
@@ -518,7 +586,12 @@ SAT-B 35786 3.07 0.0'></textarea>
518
  conjecture, not a pass/fail oracle. Locked-proven invariants = 8. Deploy posture is read live from the public
519
  registry. Attestation is honest SLSA L1; the L2 build-provenance .att is emitted (not independently verified here);
520
  L3 is roadmap &mdash; not the bundle, not an ATO. Mission Health and Trajectory Picture use clearly-labelled sample
521
- inputs over real logic; plug a real feed into the same shape and they are live.
 
 
 
 
 
522
  </div>
523
  </div>
524
 
@@ -580,11 +653,13 @@ SAT-B 35786 3.07 0.0'></textarea>
580
  });
581
 
582
  // ---------- shared run-state for the hero stats ----------
583
- var state = {live:{}, signed:0, verified:null};
584
  function refreshStats(){
585
  var n = Object.keys(state.live).filter(function(k){return state.live[k];}).length;
586
  $("stLive").textContent = n + " / 5";
587
  $("stSigned").textContent = state.signed;
 
 
588
  if(state.verified !== null){ $("stVerified").textContent = state.verified ? "PASS" : "FAIL"; $("stVerified").className = "v " + (state.verified?"teal":""); }
589
  }
590
  function markLive(tab, ok){ state.live[tab]= ok; setDot("dot-"+tab, ok?"ok":"err"); refreshStats(); }
@@ -924,6 +999,142 @@ SAT-B 35786 3.07 0.0'></textarea>
924
  }
925
  loadRibbon();
926
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
927
  drawTraj();
928
  })();
929
  </script>
 
253
  .proof-card .pc-d{font-size:12.5px;line-height:1.6;color:var(--paragraph);margin:0;}
254
  .proof-card .pc-d code{color:var(--gold);font-family:var(--mono);font-size:11px;}
255
  .proof-card .pc-r{display:flex;gap:.6rem;flex-wrap:wrap;}
256
+
257
+ /* --- 25-DEMO DEPTH SECTION (5 problems x 5 demos) --- */
258
+ .depth{max-width:64rem;margin:2.75rem auto 1rem;padding:0 1.25rem;}
259
+ .depth-head{text-align:center;margin-bottom:1.5rem;}
260
+ .depth-eyebrow{font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--teal);margin-bottom:.5rem;}
261
+ .depth-h{font-size:clamp(1.4rem,3.2vw,2rem);font-weight:300;letter-spacing:-.02em;margin:0 0 .5rem;color:var(--cream);}
262
+ .depth-h b{font-weight:600;color:var(--gold);}
263
+ .depth-sub{font-size:13px;line-height:1.6;color:var(--paragraph);max-width:46rem;margin:0 auto;}
264
+ .prob{border:1px solid var(--gold-line);border-radius:12px;background:var(--panel);margin-bottom:1rem;overflow:hidden;}
265
+ .prob-head{display:flex;align-items:center;gap:.7rem;flex-wrap:wrap;padding:1rem 1.2rem;cursor:pointer;
266
+ background:transparent;border:0;width:100%;text-align:left;color:inherit;transition:background .18s ease;}
267
+ .prob-head:hover{background:var(--gold-soft);}
268
+ .prob-head .chev{font-family:var(--mono);font-size:13px;color:var(--gold);transition:transform .2s ease;flex:0 0 auto;}
269
+ .prob.open .prob-head .chev{transform:rotate(90deg);}
270
+ .prob-id{font-family:var(--mono);font-size:11px;color:var(--teal);border:1px solid var(--teal-line);border-radius:5px;padding:.1rem .45rem;background:var(--teal-soft);flex:0 0 auto;}
271
+ .prob-title{font-size:1.05rem;font-weight:500;color:var(--cream);flex:1 1 auto;letter-spacing:-.01em;}
272
+ .lbl{font-family:var(--mono);font-size:9px;letter-spacing:.1em;padding:.12rem .45rem;border-radius:4px;text-transform:uppercase;flex:0 0 auto;white-space:nowrap;}
273
+ .lbl.real{color:var(--live);border:1px solid rgba(90,138,110,.45);background:rgba(90,138,110,.1);}
274
+ .lbl.roadmap{color:var(--gold);border:1px solid var(--gold-line);background:var(--gold-soft);}
275
+ .lbl.exp{color:var(--teal);border:1px solid var(--teal-line);background:var(--teal-soft);}
276
+ .prob-count{font-family:var(--mono);font-size:10px;color:var(--muted);flex:0 0 auto;}
277
+ .prob-summary{padding:0 1.2rem 0 2.7rem;font-size:12px;color:var(--paragraph);line-height:1.55;margin:-.3rem 0 .4rem;display:none;}
278
+ .prob.open .prob-summary{display:block;}
279
+ .demos{display:none;padding:.4rem 1.2rem 1.2rem;}
280
+ .prob.open .demos{display:block;}
281
+ .demo{border:1px solid var(--gold-soft);border-radius:9px;background:var(--panel2);padding:.85rem 1rem;margin-top:.7rem;}
282
+ .demo-top{display:flex;align-items:center;gap:.55rem;flex-wrap:wrap;}
283
+ .demo-id{font-family:var(--mono);font-size:10px;color:var(--gold);border:1px solid var(--gold-line);border-radius:4px;padding:.08rem .4rem;flex:0 0 auto;}
284
+ .demo-title{font-size:13px;color:var(--cream);font-weight:500;flex:1 1 auto;}
285
+ .demo-ctrls{display:flex;gap:.4rem;flex-wrap:wrap;margin:.6rem 0 .2rem;}
286
+ .demo-verdict{font-family:var(--mono);font-size:11px;margin:.5rem 0 .2rem;display:none;}
287
+ .demo-verdict.show{display:block;}
288
+ .demo-verdict .ok{color:var(--live);} .demo-verdict .err{color:var(--err);} .demo-verdict .warn{color:var(--gold);}
289
+ .demo-receipt{font-family:var(--mono);font-size:10px;color:var(--teal);margin:.3rem 0 0;word-break:break-all;display:none;}
290
+ .demo-receipt.show{display:block;}
291
+ .demo-out{font-family:var(--mono);font-size:9.5px;line-height:1.5;color:var(--paragraph);white-space:pre-wrap;word-break:break-word;
292
+ max-height:220px;overflow-y:auto;margin:.5rem 0 0;padding:.6rem;background:#050505;border:1px solid var(--gold-soft);border-radius:6px;display:none;
293
+ scrollbar-width:thin;scrollbar-color:var(--dim) transparent;}
294
+ .demo-out.show{display:block;}
295
  </style>
296
  </head>
297
  <body>
 
315
  <section class="hero">
316
  <div class="grid-bg"></div>
317
  <div class="hero-inner">
318
+ <span class="eyebrow"><span class="eyebrow-dot"></span><span class="eyebrow-text">WarHacker · 5 mission surfaces · 25 governed demos · live on this Space</span></span>
319
  <h1 class="headline">Code is action.<br/><span class="accent">Govern it, or it governs you.</span></h1>
320
  <p class="support">a11oy is the <b style="color:var(--cream)">governed substrate</b> beneath the mission:
321
  every autonomous decision is checked against authorized limits, <span style="color:var(--live)">ALLOWED</span>
322
  or <span style="color:var(--err)">BLOCKED</span> at the exact line it crosses, and sealed into a signed,
323
+ tamper-evident receipt you can re-verify on screen. <b style="color:var(--cream)">Five mission surfaces</b>
324
+ sit over a deeper catalog of <b style="color:var(--cream)">25 governed demos &mdash; 5 problems &times; 5 each</b>:
325
+ Cannonico (drone oversight) is <span style="color:var(--live)">REAL TODAY</span>; the other four are honest
326
+ <span style="color:var(--gold)">sample / roadmap</span> on the same proven substrate.</p>
327
  <button class="runall" id="runAll">▶ Run all five mission surfaces</button>
328
  <div class="stats">
329
  <div class="stat"><div class="k">Surfaces live</div><div class="v" id="stLive">0 / 5</div></div>
330
+ <div class="stat"><div class="k">Governed demos ran</div><div class="v teal" id="stDemos">0 / 25</div></div>
331
  <div class="stat"><div class="k">Records signed</div><div class="v teal" id="stSigned">0</div></div>
332
  <div class="stat"><div class="k">Re-verified</div><div class="v" id="stVerified">—</div></div>
333
  <div class="stat"><div class="k">Registry</div><div class="v teal" id="stReg">—</div></div>
 
547
 
548
  </div>
549
 
550
+ <!-- ====================================================================
551
+ 25-DEMO DEPTH — the 5 mission surfaces above are the polished front
552
+ door; this section exposes the FULL governed catalog: 5 approved
553
+ problems x 5 demos = 25. Loaded live from /warhacker/index and run
554
+ live against /warhacker/run/{problem}/{demo}. Honest labels per the
555
+ operator's OWN real_or_roadmap field: CANNONICO = REAL TODAY; the
556
+ other four = ROADMAP (proven substrate, SAMPLE vertical). Every demo
557
+ emits a signed receipt and is re-verifiable in-browser; the tamper
558
+ button flips one byte and the same chain reports the break.
559
+ ==================================================================== -->
560
+ <section class="depth" id="depth">
561
+ <div class="depth-head">
562
+ <div class="depth-eyebrow">Mission depth · 5 problems × 5 demos</div>
563
+ <h2 class="depth-h">Five surfaces. <b>Twenty-five governed demos</b> underneath.</h2>
564
+ <p class="depth-sub">Each of the five approved problems carries five governed demos &mdash; <b style="color:var(--cream)">25 in total</b>,
565
+ loaded live from the platform and runnable right here. Each run computes a real mechanism in-image and seals a signed,
566
+ re-verifiable receipt; press <b style="color:var(--cream)">Tamper</b> and one flipped byte returns
567
+ <span class="mono" style="color:var(--err)">verified:false</span>. Labels are the operator's own:
568
+ <span class="lbl real" style="display:inline-block">real today</span> for Cannonico,
569
+ <span class="lbl roadmap" style="display:inline-block">roadmap</span> (proven substrate · sample vertical) for the rest. Nothing here claims more than it is.</p>
570
+ </div>
571
+ <div id="depthList">
572
+ <p class="mono" id="depthLoading" style="text-align:center;color:var(--dim);font-size:12px;">— loading the 25-demo catalog from the live platform —</p>
573
+ </div>
574
+ </section>
575
+
576
  <div class="honest">
577
  <div class="honest-box" id="honestBox">
578
  <b>What is real here (doctrine v11 · honest labels only).</b> Every surface above runs live in this container.
 
586
  conjecture, not a pass/fail oracle. Locked-proven invariants = 8. Deploy posture is read live from the public
587
  registry. Attestation is honest SLSA L1; the L2 build-provenance .att is emitted (not independently verified here);
588
  L3 is roadmap &mdash; not the bundle, not an ATO. Mission Health and Trajectory Picture use clearly-labelled sample
589
+ inputs over real logic; plug a real feed into the same shape and they are live. The <b>25-demo depth</b> below
590
+ (5 problems &times; 5 demos) is the full governed catalog: <b>CANNONICO is REAL TODAY</b>; the other four problems
591
+ (Tychee, Hangar2Apps, Cyber-RTS, Raven) are <b>ROADMAP</b> &mdash; the proven horizontal substrate (hash chain +
592
+ Merkle + DSSE + the computed formula) is real, while each vertical runs on clearly-labelled SAMPLE data pending the
593
+ operational stand-up (live feed / hardware / ATO). Every one of the 25 emits a real signed receipt and a 1-byte
594
+ tamper test that fails cryptographically. We never imply all 25 are fully real.
595
  </div>
596
  </div>
597
 
 
653
  });
654
 
655
  // ---------- shared run-state for the hero stats ----------
656
+ var state = {live:{}, signed:0, verified:null, demosRan:{}};
657
  function refreshStats(){
658
  var n = Object.keys(state.live).filter(function(k){return state.live[k];}).length;
659
  $("stLive").textContent = n + " / 5";
660
  $("stSigned").textContent = state.signed;
661
+ var dcount = Object.keys(state.demosRan).length;
662
+ var dEl = $("stDemos"); if(dEl) dEl.textContent = dcount + " / 25";
663
  if(state.verified !== null){ $("stVerified").textContent = state.verified ? "PASS" : "FAIL"; $("stVerified").className = "v " + (state.verified?"teal":""); }
664
  }
665
  function markLive(tab, ok){ state.live[tab]= ok; setDot("dot-"+tab, ok?"ok":"err"); refreshStats(); }
 
999
  }
1000
  loadRibbon();
1001
 
1002
+ // ========== 25-DEMO DEPTH (5 problems x 5 demos) ==========
1003
+ // Loads the live catalog from /warhacker/index and renders 5 collapsible
1004
+ // problem groups, each with its 5 demos. Each demo runs live against
1005
+ // /warhacker/run/{problem}/{demo}, shows the decision + signed receipt id,
1006
+ // and offers a tamper test (the API's own always-on 1-byte-flip negative
1007
+ // test). Honest labels come straight from the operator's real_or_roadmap.
1008
+ function esc(s){ return String(s==null?"":s).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;"); }
1009
+ function lblClass(rr){
1010
+ var s = String(rr||"").toUpperCase();
1011
+ if(s.indexOf("REAL")===0 || s.indexOf("REAL TODAY")>=0) return "real";
1012
+ if(s.indexOf("EXPERIMENTAL")>=0) return "exp";
1013
+ return "roadmap";
1014
+ }
1015
+ function lblText(rr){
1016
+ var s = String(rr||"").toUpperCase();
1017
+ if(s.indexOf("REAL")===0 || s.indexOf("REAL TODAY")>=0) return "REAL TODAY";
1018
+ if(s.indexOf("EXPERIMENTAL")>=0) return "EXPERIMENTAL";
1019
+ return "ROADMAP \u00b7 SAMPLE";
1020
+ }
1021
+ function shortRR(rr){
1022
+ // first sentence / clause, for the demo-level honesty line
1023
+ var s = String(rr||"");
1024
+ var cut = s.split(/[;\u2014]/)[0];
1025
+ return cut.length>140 ? cut.slice(0,138)+"\u2026" : cut;
1026
+ }
1027
+ function depthRunDemo(prob, demo, mode, els){
1028
+ els.verdict.className = "demo-verdict show";
1029
+ els.verdict.innerHTML = '<span class="warn">' + (mode==="tamper"?"tamper run\u2026":"running\u2026") + '</span>';
1030
+ els.runBtn.disabled = true; els.tamperBtn.disabled = true;
1031
+ return postJSON("/warhacker/run/"+prob+"/"+demo, {mode: mode}).then(function(r){
1032
+ var d = r.json || {};
1033
+ if(!d.ok){
1034
+ els.verdict.innerHTML = '<span class="err">error \u2014 ' + esc(d.error || ("HTTP "+r.status)) + '</span>';
1035
+ els.runBtn.disabled=false; els.tamperBtn.disabled=false; return;
1036
+ }
1037
+ // signed receipt id from the sealed DSSE envelope / chain
1038
+ var sealed = d.sealed || {};
1039
+ var chainHash = (sealed.chain_hash || "").slice(0,16);
1040
+ var merkle = (sealed.merkle_root || "").slice(0,16);
1041
+ var signed = !!(sealed.envelope && sealed.envelope.signed);
1042
+ var tt = d.tamper_test || {};
1043
+ var cs = d.chain_self || {};
1044
+ var decClass = d.authorized ? "ok" : "err";
1045
+ if(mode==="tamper"){
1046
+ // surface the API's negative test result: a 1-byte flip breaks the chain
1047
+ els.verdict.innerHTML = '<span class="err">TAMPER \u2014 verified:false \u00b7 chain break at seq ' +
1048
+ esc(tt.chain_break_at_seq) + ' (field: ' + esc(tt.tamper && tt.tamper.field) +
1049
+ ', bytes changed: ' + esc(tt.tamper && tt.tamper.bytes_changed) + '). One flipped byte is caught.</span>';
1050
+ state.verified = false;
1051
+ } else {
1052
+ els.verdict.innerHTML = '<span class="' + decClass + '">' + esc(d.decision || (d.authorized?"ALLOW":"BLOCK")) +
1053
+ '</span> \u2014 ' + esc(d.headline || "") +
1054
+ ' <span class="' + (cs.chain_intact?"ok":"err") + '">[re-verify: chain ' + (cs.chain_intact?"intact":"BROKEN") + ']</span>';
1055
+ if(state.verified===null) state.verified = !!cs.chain_intact;
1056
+ }
1057
+ els.receipt.className = "demo-receipt show";
1058
+ els.receipt.textContent = "signed receipt \u00b7 chain=" + chainHash + "\u2026 \u00b7 merkle=" + merkle + "\u2026 \u00b7 signed=" + signed + " \u00b7 mode=" + esc(d.mode);
1059
+ els.out.className = "demo-out show";
1060
+ els.out.textContent = pretty({problem:d.problem, demo:d.demo, mode:d.mode, decision:d.decision,
1061
+ authorized:d.authorized, real_or_roadmap:d.real_or_roadmap, headline:d.headline,
1062
+ sealed:{signed:signed, chain_hash:sealed.chain_hash, merkle_root:sealed.merkle_root, chain_seq:sealed.chain_seq},
1063
+ chain_self:cs, tamper_test:tt, honesty:d.honesty});
1064
+ // count the demo as run (once, by key) and tally signed receipts
1065
+ var key = prob+"/"+demo;
1066
+ if(!state.demosRan[key]){ state.demosRan[key]=true; }
1067
+ if(mode!=="tamper" && signed){ state.signed++; }
1068
+ refreshStats();
1069
+ els.runBtn.disabled=false; els.tamperBtn.disabled=false;
1070
+ }).catch(function(e){
1071
+ els.verdict.innerHTML = '<span class="err">error \u2014 ' + esc(String(e)) + '</span>';
1072
+ els.runBtn.disabled=false; els.tamperBtn.disabled=false;
1073
+ });
1074
+ }
1075
+ function renderDepth(idx){
1076
+ var problems = (idx && idx.problems) || [];
1077
+ var host = $("depthList");
1078
+ host.innerHTML = "";
1079
+ problems.forEach(function(p, pi){
1080
+ var probEl = document.createElement("div");
1081
+ probEl.className = "prob" + (pi===0 ? " open" : ""); // first (Cannonico) open by default
1082
+ var lc = lblClass(p.real_or_roadmap), lt = lblText(p.real_or_roadmap);
1083
+ var head = document.createElement("button");
1084
+ head.type = "button"; head.className = "prob-head";
1085
+ head.setAttribute("aria-expanded", pi===0 ? "true" : "false");
1086
+ head.innerHTML = '<span class="chev">\u25b6</span>' +
1087
+ '<span class="prob-id">' + esc(p.id) + '</span>' +
1088
+ '<span class="prob-title">' + esc(p.title) + '</span>' +
1089
+ '<span class="lbl ' + lc + '">' + lt + '</span>' +
1090
+ '<span class="prob-count">' + esc(p.demo_count) + ' demos</span>';
1091
+ head.addEventListener("click", function(){
1092
+ var open = probEl.classList.toggle("open");
1093
+ head.setAttribute("aria-expanded", open ? "true" : "false");
1094
+ });
1095
+ probEl.appendChild(head);
1096
+ var summary = document.createElement("div");
1097
+ summary.className = "prob-summary";
1098
+ summary.textContent = p.summary || "";
1099
+ probEl.appendChild(summary);
1100
+ var demosWrap = document.createElement("div");
1101
+ demosWrap.className = "demos";
1102
+ (p.demos||[]).forEach(function(dm){
1103
+ var demoEl = document.createElement("div");
1104
+ demoEl.className = "demo";
1105
+ var top = document.createElement("div"); top.className = "demo-top";
1106
+ top.innerHTML = '<span class="demo-id">' + esc(dm.id) + '</span>' +
1107
+ '<span class="demo-title">' + esc(dm.title) + '</span>' +
1108
+ '<span class="lbl ' + lc + '">' + lt + '</span>';
1109
+ var ctrls = document.createElement("div"); ctrls.className = "demo-ctrls";
1110
+ var runBtn = document.createElement("button"); runBtn.className="r-btn r-btn-primary"; runBtn.textContent="\u25b6 Run";
1111
+ var tamperBtn = document.createElement("button"); tamperBtn.className="r-btn"; tamperBtn.textContent="\u26a0 Tamper";
1112
+ ctrls.appendChild(runBtn); ctrls.appendChild(tamperBtn);
1113
+ var verdict = document.createElement("div"); verdict.className="demo-verdict";
1114
+ var receipt = document.createElement("div"); receipt.className="demo-receipt";
1115
+ var out = document.createElement("pre"); out.className="demo-out";
1116
+ var els = {runBtn:runBtn, tamperBtn:tamperBtn, verdict:verdict, receipt:receipt, out:out};
1117
+ runBtn.addEventListener("click", function(){ depthRunDemo(p.key, dm.id, "nominal", els); });
1118
+ tamperBtn.addEventListener("click", function(){ depthRunDemo(p.key, dm.id, "tamper", els); });
1119
+ demoEl.appendChild(top); demoEl.appendChild(ctrls);
1120
+ demoEl.appendChild(verdict); demoEl.appendChild(receipt); demoEl.appendChild(out);
1121
+ demosWrap.appendChild(demoEl);
1122
+ });
1123
+ probEl.appendChild(demosWrap);
1124
+ host.appendChild(probEl);
1125
+ });
1126
+ }
1127
+ getJSON("/warhacker/index").then(function(r){
1128
+ var idx = r.json;
1129
+ if(idx && idx.ok && idx.problems && idx.problems.length){
1130
+ renderDepth(idx);
1131
+ } else {
1132
+ var ld = $("depthLoading"); if(ld) ld.textContent = "\u2014 25-demo catalog endpoint reachable but returned no problems \u2014";
1133
+ }
1134
+ }).catch(function(){
1135
+ var ld = $("depthLoading"); if(ld){ ld.style.color="var(--err)"; ld.textContent = "\u2014 NO-LIVE-DATA: 25-demo catalog endpoint unreachable \u2014"; }
1136
+ });
1137
+
1138
  drawTraj();
1139
  })();
1140
  </script>