betterwithage commited on
Commit
5ea238f
·
verified ·
1 Parent(s): 5e09637

feat(restraint): R2 front-end - 'Restraint applied' indicator on /nemo (rung+lines-saved+ceilings+signed receipt) and restraint verdict column on /agent-loop trace. Ponytail MIT, governed. Byte-identical to GitHub 3a8305e. Additive; PENDING until R1 live.

Browse files
Files changed (2) hide show
  1. web/agent-loop.html +21 -3
  2. web/nemo.html +75 -0
web/agent-loop.html CHANGED
@@ -70,7 +70,7 @@
70
  <section class="view active" id="v-loop">
71
  <div class="card">
72
  <div class="row">
73
- <input id="goal" type="text" placeholder="goal, e.g. compute 18*23 please" value="compute 18*23 please"/>
74
  <label class="sub">max_steps <input id="maxsteps" type="number" value="4" style="width:64px"/></label>
75
  <label class="sub"><input id="kill" type="checkbox"/> kill mid-run (crash demo)</label>
76
  <button id="btnRun">Run ReAct</button>
@@ -85,8 +85,9 @@
85
  <span id="chainState"></span>
86
  </div>
87
  <table id="traceTbl"><thead><tr>
88
- <th>seq</th><th>node</th><th>body</th><th>link</th><th>signature</th><th>hash</th>
89
  </tr></thead><tbody></tbody></table>
 
90
  </div>
91
  <div class="card" id="cpCard" style="display:none">
92
  <strong>Checkpoints (SqliteSaver-style)</strong>
@@ -166,6 +167,23 @@ async function jget(u){const r=await fetch(u);return {status:r.status,json:await
166
  function esc(s){return (s==null?"":String(s)).replace(/[&<>]/g,c=>({"&":"&amp;","<":"&lt;",">":"&gt;"}[c]));}
167
 
168
  // ---------- Agent Loop ----------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  async function renderTrace(runId){
170
  const {json:tr} = await jget(API+"/trace/"+encodeURIComponent(runId));
171
  if(tr.error){return;}
@@ -179,7 +197,7 @@ async function renderTrace(runId){
179
  :(r.signed?"<span class='bad'>FAIL ✗</span>":"<span class='mut'>unsigned</span>");
180
  const link = r.link_ok?"<span class='ok'>✓</span>":"<span class='bad'>✗</span>";
181
  tb.innerHTML += `<tr><td>${r.seq}</td><td><span class="node ${r.node}">${r.node}</span></td>
182
- <td><pre>${esc(JSON.stringify(r.body))}</pre></td><td>${link}</td><td>${sig}</td>
183
  <td class="hash">${esc((r.hash||"").slice(0,18))}…</td></tr>`;
184
  });
185
  if(tr.reflection){
 
70
  <section class="view active" id="v-loop">
71
  <div class="card">
72
  <div class="row">
73
+ <input id="goal" type="text" placeholder="goal, e.g. implement a function that validates an email address" value="implement a function that validates an email address"/>
74
  <label class="sub">max_steps <input id="maxsteps" type="number" value="4" style="width:64px"/></label>
75
  <label class="sub"><input id="kill" type="checkbox"/> kill mid-run (crash demo)</label>
76
  <button id="btnRun">Run ReAct</button>
 
85
  <span id="chainState"></span>
86
  </div>
87
  <table id="traceTbl"><thead><tr>
88
+ <th>seq</th><th>node</th><th>body</th><th>restraint</th><th>link</th><th>signature</th><th>hash</th>
89
  </tr></thead><tbody></tbody></table>
90
+ <div class="sub" style="margin-top:6px">Action nodes that <strong>write code</strong> are gated through <strong>a11oy Restraint</strong> (the Ponytail-derived 6-rung frugality ladder, <a href="https://github.com/DietrichGebert/ponytail" target="_blank" rel="noopener">Ponytail MIT</a> — adopted + governed). The chosen rung + signed restraint receipt are recorded in that node's receipt. <strong>R1 owns the ladder module</strong>; honest <strong>PENDING</strong> until it is live.</div>
91
  </div>
92
  <div class="card" id="cpCard" style="display:none">
93
  <strong>Checkpoints (SqliteSaver-style)</strong>
 
167
  function esc(s){return (s==null?"":String(s)).replace(/[&<>]/g,c=>({"&":"&amp;","<":"&lt;",">":"&gt;"}[c]));}
168
 
169
  // ---------- Agent Loop ----------
170
+ // Restraint verdict cell for a node body. Only code-writing ACTION nodes carry
171
+ // a `restraint` block; everything else shows a dim em-dash (honest).
172
+ function restraintCell(body){
173
+ const rs = body && body.restraint;
174
+ if(!rs) return "<span class='mut'>—</span>";
175
+ const live = rs.status==="LIVE";
176
+ const badge = live ? L("LIVE") : (L("ROADMAP")+" <span class='lbl' style='border-color:var(--warn);color:var(--warn)'>PENDING</span>");
177
+ if(rs.stopped_at_rung!=null){
178
+ const saved = (rs.lines_saved_estimate!=null)
179
+ ? (" · saved≈"+rs.lines_saved_estimate+" LOC ("+esc(rs.lines_saved_label||"MODELED")+")") : "";
180
+ const lam = (rs.lambda_advisory!=null) ? (" · Λ "+Number(rs.lambda_advisory).toFixed(3)) : "";
181
+ const ceil = rs.restraint_comment ? ("<div class='mut' style='font-size:11px'><code>"+esc(rs.restraint_comment)+"</code></div>") : "";
182
+ return "<div><span class='ok'>rung "+rs.stopped_at_rung+"</span> "+esc(rs.rung_key||"")+" "+badge+"</div>"+
183
+ "<div class='mut' style='font-size:11px'>"+esc(rs.rung_name||"")+saved+lam+"</div>"+ceil;
184
+ }
185
+ return "<div>"+badge+"</div><div class='mut' style='font-size:11px'>code gated; restraint not live yet (no rung fabricated)</div>";
186
+ }
187
  async function renderTrace(runId){
188
  const {json:tr} = await jget(API+"/trace/"+encodeURIComponent(runId));
189
  if(tr.error){return;}
 
197
  :(r.signed?"<span class='bad'>FAIL ✗</span>":"<span class='mut'>unsigned</span>");
198
  const link = r.link_ok?"<span class='ok'>✓</span>":"<span class='bad'>✗</span>";
199
  tb.innerHTML += `<tr><td>${r.seq}</td><td><span class="node ${r.node}">${r.node}</span></td>
200
+ <td><pre>${esc(JSON.stringify(r.body))}</pre></td><td>${restraintCell(r.body)}</td><td>${link}</td><td>${sig}</td>
201
  <td class="hash">${esc((r.hash||"").slice(0,18))}…</td></tr>`;
202
  });
203
  if(tr.reflection){
web/nemo.html CHANGED
@@ -165,6 +165,31 @@ table.tau th{color:var(--dim);text-transform:uppercase;font-size:9.5px;letter-sp
165
  </div>
166
  </div>
167
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  <!-- ============ 3D ROUTER DASHBOARD (F4 · additive · toggle enhancement; 2D pages above remain the fallback) ============ -->
169
  <div class="panel" id="router3d_panel">
170
  <h2>3D Router Dashboard <span class="meta">GPU blocks · particle token-flows · signed MoE routing pulses · live J/token</span>
@@ -447,6 +472,54 @@ async function doRoute(q){
447
  }
448
  }
449
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
450
  async function loadMTP(){
451
  const d=await getJSON(A+"/mtp"); if(!d){$('mtp_kv').textContent='unreachable';return;}
452
  $('mtp_kv').innerHTML=
@@ -542,11 +615,13 @@ async function doSelfImprove(){
542
 
543
  document.querySelectorAll('button.ghost[data-q]').forEach(b=>b.addEventListener('click',()=>{$('q').value=b.getAttribute('data-q');doRoute(b.getAttribute('data-q'));}));
544
  $('go').addEventListener('click',()=>doRoute($('q').value));
 
545
  $('si_go').addEventListener('click',doSelfImprove);
546
 
547
  (async function(){
548
  await Promise.all([loadDiag(),loadMTP(),loadTiers(),loadTau(),loadCard()]);
549
  await doRoute($('q').value);
 
550
  })();
551
  </script>
552
  </body>
 
165
  </div>
166
  </div>
167
 
168
+ <!-- a11oy RESTRAINT (gates the CODE path before any diff is emitted) -->
169
+ <div class="panel">
170
+ <h2>a11oy Restraint <span class="meta">code-frugality ladder · gates the code path before emit · signed</span></h2>
171
+ <div class="desc">
172
+ Before SZL-Nemo emits ANY code, the intended diff is routed through the governed, Ponytail-derived
173
+ <b>6-rung frugality ladder</b> (YAGNI → stdlib → native → installed-deps → one-liner → minimal). The chosen rung,
174
+ the <code>restraint:</code> ceiling, a lines-saved estimate and a <b>signed restraint receipt</b> are attached to the
175
+ Nemo response. Adopted from <a href="https://github.com/DietrichGebert/ponytail" target="_blank" rel="noopener">Ponytail (MIT)</a>,
176
+ governed + Λ-scored here. <b>R1 owns the ladder module</b>; if it isn't live yet this reads honest <b>PENDING</b>
177
+ (no rung or number fabricated).
178
+ </div>
179
+ <div class="row">
180
+ <input type="text" id="cq" value="write me a Python function that validates email addresses"/>
181
+ <button class="btn" id="cgo">Ask SZL-Nemo for code →</button>
182
+ <span id="c_rung" class="pill dim">rung —</span>
183
+ <span id="c_status" class="pill dim">—</span>
184
+ </div>
185
+ <div class="kv" id="c_restraint" style="margin-top:.5rem;">— (ask SZL-Nemo for code to see the restraint verdict)</div>
186
+ <div style="margin-top:.6rem;">
187
+ <div class="meta mono" style="color:var(--dim);font-size:10px;">SIGNED RESTRAINT RECEIPT (nested in the Nemo code receipt)</div>
188
+ <pre class="rcpt" id="c_receipt">—</pre>
189
+ <div class="kv"><span class="k">verify</span><span class="v" id="c_verify">—</span></div>
190
+ </div>
191
+ </div>
192
+
193
  <!-- ============ 3D ROUTER DASHBOARD (F4 · additive · toggle enhancement; 2D pages above remain the fallback) ============ -->
194
  <div class="panel" id="router3d_panel">
195
  <h2>3D Router Dashboard <span class="meta">GPU blocks · particle token-flows · signed MoE routing pulses · live J/token</span>
 
472
  }
473
  }
474
 
475
+ async function doCode(q){
476
+ $('c_restraint').innerHTML='<span class="muted mono">routing the intended diff through a11oy Restraint…</span>';
477
+ $('c_rung').textContent='rung …'; $('c_rung').className='pill dim';
478
+ $('c_status').textContent='…'; $('c_status').className='pill dim';
479
+ const d=await getJSON(A+"/code",{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({query:q})});
480
+ if(!d){$('c_restraint').innerHTML='<div class="muted mono">code endpoint unreachable</div>';return;}
481
+ const rs=d.restraint||{};
482
+ const status=String(rs.status||'PENDING');
483
+ const live=(status==='LIVE');
484
+ // "Restraint applied" indicator: rung + lines-saved estimate + restraint: ceiling
485
+ // PENDING is not in the shared canonical vocabulary (R1 owns labels); show the
486
+ // closest honest canonical badge (ROADMAP) + the literal PENDING word in text.
487
+ $('c_status').innerHTML = live ? labelPill('LIVE') : (labelPill('ROADMAP')+' <span class="pill yellow">PENDING</span>');
488
+ if(rs.stopped_at_rung!=null){
489
+ $('c_rung').textContent='rung '+rs.stopped_at_rung+' · '+(rs.rung_key||'');
490
+ $('c_rung').className='pill green';
491
+ }else{
492
+ $('c_rung').textContent='rung — (PENDING)'; $('c_rung').className='pill yellow';
493
+ }
494
+ const saved=(rs.lines_saved_estimate!=null)?(rs.lines_saved_estimate+' LOC ('+esc(rs.lines_saved_label||'MODELED')+')'):'— (not measured)';
495
+ const lam=(rs.lambda_advisory!=null)?fmt(rs.lambda_advisory,3):'—';
496
+ const applied = live
497
+ ? `<span class="pill green">Restraint applied</span>`
498
+ : `<span class="pill yellow">Restraint PENDING</span>`;
499
+ $('c_restraint').innerHTML=
500
+ `<div>${applied} <span class="k">rung</span> <span class="v">${rs.stopped_at_rung!=null?(rs.stopped_at_rung+' · '+esc(rs.rung_name||rs.rung_key||'')):'—'}</span></div>`+
501
+ `<div><span class="k">lines saved (est.)</span> <span class="v">${saved}</span></div>`+
502
+ `<div><span class="k">Λ advisory</span> <span class="v">${lam}</span></div>`+
503
+ (rs.restraint_comment?`<div><span class="k">restraint: ceiling</span> <code class="mono" style="font-size:10.5px;">${esc(rs.restraint_comment)}</code></div>`:
504
+ (rs.ceiling?`<div><span class="k">ceiling</span> <span class="v">${esc(rs.ceiling)}</span></div>`:''))+
505
+ `<div class="muted" style="font-size:10px;margin-top:.3rem;">integration: ${esc(rs.integration||'')}</div>`+
506
+ (rs.honesty?`<div class="muted" style="font-size:10px;">${esc(rs.honesty)}</div>`:'')+
507
+ `<div class="muted" style="font-size:10px;">Ponytail (MIT) — adopted + governed · R1 owns a11oy_restraint.py</div>`;
508
+ // signed restraint receipt (nested in the Nemo code receipt)
509
+ const r=d.restraint_receipt||rs.restraint_receipt||{};
510
+ $('c_receipt').textContent=JSON.stringify(r,null,1);
511
+ if(r&&r.signatures&&r.signatures.length&&window.SZLReceipts&&window.SZLReceipts.verifyEnvelope){
512
+ $('c_verify').textContent='verifying…';
513
+ try{
514
+ const v=await window.SZLReceipts.verifyEnvelope(r,{});
515
+ const ok=v&&(v.valid||v.signature_valid);
516
+ $('c_verify').innerHTML=ok?pill('SIGNATURE VALID','green'):pill('signed (server-verify)','blue');
517
+ }catch(e){$('c_verify').innerHTML=pill('signed','blue');}
518
+ }else{
519
+ $('c_verify').innerHTML=(r&&r.signed===false)?pill('UNSIGNED/PENDING','yellow')+' '+esc(r.honesty||''):pill('—','dim');
520
+ }
521
+ }
522
+
523
  async function loadMTP(){
524
  const d=await getJSON(A+"/mtp"); if(!d){$('mtp_kv').textContent='unreachable';return;}
525
  $('mtp_kv').innerHTML=
 
615
 
616
  document.querySelectorAll('button.ghost[data-q]').forEach(b=>b.addEventListener('click',()=>{$('q').value=b.getAttribute('data-q');doRoute(b.getAttribute('data-q'));}));
617
  $('go').addEventListener('click',()=>doRoute($('q').value));
618
+ $('cgo').addEventListener('click',()=>doCode($('cq').value));
619
  $('si_go').addEventListener('click',doSelfImprove);
620
 
621
  (async function(){
622
  await Promise.all([loadDiag(),loadMTP(),loadTiers(),loadTau(),loadCard()]);
623
  await doRoute($('q').value);
624
+ await doCode($('cq').value);
625
  })();
626
  </script>
627
  </body>