[object Object]

← back to Model Arena

add 'Re-run entire challenge' button (re-queues every model in a battle)

bde0e0c9faa90f122ca6bcc20fa7e68dad80e1af · 2026-07-23 07:11:46 -0700 · Steve Abrams

Files touched

Diff

commit bde0e0c9faa90f122ca6bcc20fa7e68dad80e1af
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Jul 23 07:11:46 2026 -0700

    add 'Re-run entire challenge' button (re-queues every model in a battle)
---
 public/index.html | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/public/index.html b/public/index.html
index a239ffc..9c37fee 100644
--- a/public/index.html
+++ b/public/index.html
@@ -186,6 +186,7 @@ tr.clk{cursor:pointer}tr.clk:hover td{background:rgba(0,229,255,.06)}
   <section id="detail" class="view">
     <span class="back" id="back">← back to challenges</span>
     <a class="back" id="export" style="margin-left:16px" download>⬇ export battle as standalone HTML</a>
+    <button class="btn pink" id="rerun-all" style="margin-left:16px" title="Re-run EVERY model in this battle from scratch (re-spends any metered models)">↻ Re-run entire challenge</button>
     <label class="blindtog"><input type="checkbox" id="blind"> 🕶 Blind judging — hide model names until a winner is crowned (kills brand bias)</label>
     <h2 id="d-title"></h2>
     <div class="meta" id="d-meta"></div>
@@ -371,6 +372,15 @@ async function renderDetail(id, statusOnly){
   const remixNote = c.remixOf ? '🧬 remixed from ' + mLabel(c.remixSource) + "'s artifact\n" : '';
   $('#d-meta').textContent = '🕓 ' + fmtWhen(c.created_at) + (c.category?'  ·  '+c.category:'') + '\n' + remixNote + c.prompt;
   $('#export').href = API+'/export/'+c.id;
+  // Re-run entire challenge — re-queue+run every model in this battle from scratch.
+  { const rb = $('#rerun-all'); if (rb) rb.onclick = async () => {
+      const metered = c.runs.filter(r => { const m = (models||[]).find(x=>x.id===r.model); return m && m.kind!=='local' && m.kind!=='cli'; }).length;
+      if (!confirm('Re-run all '+c.runs.length+' models in "'+c.title+'"?'+(metered?'\n\n'+metered+' metered model(s) will be re-billed.':''))) return;
+      rb.disabled = true; rb.textContent = '↻ re-running…';
+      for (const run of c.runs) { try { await fetch(API+'/api/challenges/'+c.id+'/retry/'+run.model, {method:'POST'}); } catch {} }
+      rb.disabled = false; rb.textContent = '↻ Re-run entire challenge';
+      openDetail(c.id);
+  }; }
   // AI referee status bar
   const anyArt = c.runs.some(r=>r.status==='done'&&r.thumb);
   const ai = $('#d-ai');

← 0dbc486 auto-resume runs interrupted by a server restart: on boot, r  ·  back to Model Arena  ·  watchdog: age queued runs from their own queued_at, not chal ca4eed6 →